Files
BeWoPlaner/BeWo/ViewModel/ListViewModel/AiConversationListVM.cs
2025-06-27 13:19:36 +02:00

526 lines
13 KiB
C#

using BeWo.Core;
using BeWo.Core.Commands;
using BeWo.ServiceProxy;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Feature.AI;
using BS.Shared.Extensions;
using ChatController.Utilities.Extensions;
using DevExpress.Mvvm;
using DevExpress.Xpf.Editors;
using DevExpress.XtraPrinting.Native;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Threading;
namespace BeWo.ViewModel.ListViewModel
{
public class AiConversationListVM : AbstractDCListMapperVM<AiConversationDC, AiConversationVM>
{
private bool _IsSettingsOpen;
private bool _IsCloneOpen;
private bool _IsSending;
private string _MessageInput;
private string _ContextInput;
private AiModelDC _SelectedModel;
private AiConfigVM _Config;
public AiConversationListVM() : this(null)
{
if (BeWoApp.IsInDesignMode)
{
InitDesigner();
}
}
public AiConversationListVM(List<AiConversationDC> pDCs) : base(pDCs)
{
Models = new BS.Shared.Core.ObservableSortCollection<AiModelDC>();
bool sendCanExecute() => SelectedVM is object && !string.IsNullOrWhiteSpace(MessageInput) && !IsSending;
SendNewMessageCommand = new DelegateCommand(SendNewMessage, sendCanExecute);
OpenNewConversationCommand = new DelegateCommand(OpenNewConversation, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatAdd));
bool startconvCanExecute() => !string.IsNullOrWhiteSpace(MessageInput) && !IsSending;
StartConversationWithMessageCommand = new DelegateCommand(StartConversationWithMessage, startconvCanExecute);
ReloadConfigCommand = new DelegateCommand(ReloadConfig);
ReloadConversationsCommand = new DelegateCommand(ReloadConversations);
ReloadModelsCommand = new DelegateCommand(ReloadModels);
bool openCanExecute() => (BeWoApp.AppSettings?.ModuleAiSettingsEnabled ?? true) && BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleViewSetting);
OpenSettingCommand = new DelegateCommand(OpenSetting, openCanExecute, false);
OpenCloneCommand = new DelegateCommand(OpenClone, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatClone) && SelectedVM is object);
CloneCommand = new DelegateCommand(Clone);
AskDeleteCommand = new DelegateCommand(AskDelete, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatDelete) && SelectedVM is object);
SelectedVMChanged += (s, e) => FirePropertyChanged(nameof(IsNewConversationVisible));
}
public event EventHandler SendNewMessageSuccess;
public DelegateCommand SendNewMessageCommand { get; set; }
public DelegateCommand OpenNewConversationCommand { get; set; }
public DelegateCommand StartConversationWithMessageCommand { get; set; }
//public DelegateCommand RequestNewConversationCommand { get; set; }
//public DelegateCommand TestCommand { get; set; }
public DelegateCommand AskDeleteCommand { get; set; }
public DelegateCommand ReloadConfigCommand { get; set; }
public DelegateCommand ReloadConversationsCommand { get; set; }
public DelegateCommand ReloadModelsCommand { get; set; }
public DelegateCommand OpenSettingCommand { get; set; }
public DelegateCommand OpenCloneCommand { get; set; }
public DelegateCommand CloneCommand { get; set; }
public ObservableCollection<AiModelDC> Models { get; set; }
public AiModelDC SelectedModel
{
get { return _SelectedModel; }
set
{
if (_SelectedModel == value)
return;
_SelectedModel = value;
FirePropertyChanged(nameof(SelectedModel));
}
}
public AiConfigVM Config
{
get { return _Config; }
set
{
if (Config == value)
return;
_Config = value;
FirePropertyChanged(nameof(Config));
}
}
public string MessageInput
{
get { return _MessageInput; }
set
{
if (MessageInput == value)
return;
_MessageInput = value;
FirePropertyChanged(nameof(MessageInput));
}
}
public string ContextInput
{
get { return _ContextInput; }
set
{
if (ContextInput == value)
return;
_ContextInput = value;
FirePropertyChanged(nameof(ContextInput));
}
}
public bool IsSettingsOpen
{
get => _IsSettingsOpen;
set
{
_IsSettingsOpen = value;
FirePropertyChanged(nameof(IsSettingsOpen));
}
}
public bool IsCloneOpen
{
get => _IsCloneOpen;
set
{
_IsCloneOpen = value;
FirePropertyChanged(nameof(IsCloneOpen));
}
}
public bool IsSending
{
get => _IsSending;
set
{
_IsSending = value;
FirePropertyChanged(nameof(IsSending));
}
}
public bool IsNewConversationVisible => SelectedVM is null;
public int UIContext { get; set; }
public long? ReferenceObjectOid { get; set; }
public Dictionary<TableID, long[]> ContextBeWoObjects { get; set; }
private void StartConversationWithMessage()
{
StartSending();
try
{
var message = MessageInput;
var conv = new AiConversationDC();
conv.Created = DateTime.Now;
conv.Updated = DateTime.Now;
conv.UIContext = UIContext;
conv.ContextBeWoObjects = ContextBeWoObjects;
conv.Messages = new List<AiConversationMessageDC>()
{
new AiConversationMessageDC()
{
Message = message,
Role = AiConversationMessageRole.User
}
};
var vm = InsertConverstion(conv);
ServiceFacade.DoAiEnhancedServiceAsnyc(
x => x.CreateAiConversationWithMessage(conv, Config.SelectedModel.Oid.Value, message),
dc => UpdateConverstion(vm, dc),
e => EndSending());
}
catch(Exception ex)
{
EndSending();
}
}
private void OpenNewConversation()
{
SelectedVM = null;
}
private void SendNewMessage()
{
StartSending();
try
{
var conv = SelectedVM;
var msg_dc = new AiConversationMessageDC();
msg_dc.Message = MessageInput;
msg_dc.Role = AiConversationMessageRole.User;
msg_dc.Created = DateTime.Now;
var msg_vm = new AiConversationMessageVM(msg_dc);
conv.Messages.VMList.Add(msg_vm);
ServiceFacade.DoAiEnhancedServiceAsnyc(
x => x.SendNewMessage(conv.DataContract.Oid.Value, MessageInput),
(messages) =>
{
if (messages.Count != 2)
throw new InvalidOperationException("message count: " + messages.Count);
msg_vm.DataContract = messages[0];
conv.Messages.VMList.Add(new AiConversationMessageVM(messages[1]));
MessageInput = string.Empty;
EndSending();
SendNewMessageSuccess?.Invoke(this, EventArgs.Empty);
},
(exception) =>
{
conv.Messages.VMList.Remove(msg_vm);
EndSending();
}
);
}
catch (Exception ex) {
EndSending();
}
}
private void StartSending()
{
if (IsSending)
throw new InvalidOperationException("Sendet bereits");
IsSending = true;
}
private void EndSending()
{
if (!IsSending)
throw new InvalidOperationException("Sendet nicht");
IsSending = false;
}
private void Test()
{
throw new NotImplementedException();
//var limit = 5;
//var models = ServiceFacade.DoOperationsEnhancedServiceSnyc(x => x.GetAiModels());
//Models.MakeEqualTo(models);
//VMList.Clear();
//foreach (var vm in Models)
//{
// var dc = new AiConversationDC();
// dc.Created = DateTime.Now;
// dc.Displayname = "Example";
// dc.Modell = vm.ToString();
// var pvm = new AiConversationVM(dc);
// VMList.Add(pvm);
//}
//var msg = "Wie alt ist Frau Müller?";
//var context = "Frau Müller wurde am 1.1.1950 geboren. Aktuelle haben wir folgende Universalzeit: " + DateTime.Now.ToUniversalTime();
//for (var i = 0; i < limit; i++)
//{
// foreach (var vm in VMList)
// {
// ServiceFacade.DoOperationsEnhancedServiceAsnyc(x => x.SendNewMessage(vm.CommitToDataContract(), context, msg), (message) =>
// {
// vm.Messages.VMList.Add(new AiConversationMessageVM(message));
// });
// }
//}
}
private AiConversationVM InsertConverstion(AiConversationDC dc)
{
var vm = new AiConversationVM(dc);
VMList.Insert(0, vm);
SelectedVM = vm;
return vm;
}
private void UpdateConverstion(AiConversationVM vm, AiConversationDC dc)
{
vm.UpdateByDataContract(dc);
MessageInput = string.Empty;
EndSending();
SendNewMessageSuccess?.Invoke(this, EventArgs.Empty);
}
private void ReloadConfig()
{
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiConfig(), (x) =>
{
if (Config is null)
Config = new AiConfigVM(x);
else
Config.Update(x);
});
}
public void UpdateConfig()
{
if (!Config.IsDirty)
return;
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.UpdateAiConfig(Config.CommitToDataContract()), (x) =>
{
Config.Update(x);
});
}
private void ReloadModels()
{
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiModels(), (x) =>
{
Models.MakeEqualTo(x);
if (Config.SelectedModel is null && Models.Any())
Config.SelectedModel = Models.First();
});
}
private void ReloadConversations()
{
var ui_context = UIContext;
var reference = ReferenceObjectOid;
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiConversations(ui_context, reference), (x) =>
{
x.Reverse();
var vms = new AiConversationListVM(x);
VMList.MakeEqualTo(vms.VMList);
});
}
private void OpenSetting()
{
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiModels(), (x) =>
{
Models.MakeEqualTo(x);
IsSettingsOpen = true;
});
}
private void OpenClone()
{
foreach (var message in SelectedVM.Messages.VMList)
{
message.IsChecked = true;
}
IsCloneOpen = true;
}
private void Clone()
{
var conv = SelectedVM;
AiConversationMessageVM last = null;
foreach (var msg in conv.Messages.VMList)
{
if (!msg.IsChecked)
break;
last = msg;
}
var conv_oid = conv.DataContract.Oid.Value;
var msg_oid = last?.DataContract.Oid;
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.CloneAiConversation(conv_oid, msg_oid), dc =>
{
InsertConverstion(dc);
CloseClone();
});
}
private void CloseClone()
{
IsCloneOpen = false;
}
public void AskDelete()
{
var selected = SelectedVM;
var oid = selected.DataContract.Oid.Value;
var msg = $"Wollen Sie die ausgewählte Konversation ({oid}) löschen?";
if (MessageBox.Show(msg, "Konversation löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning) ==
MessageBoxResult.Yes)
{
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.DeleteAiConversation(oid), () => {
VMList.Remove(selected);
CommandManager.InvalidateRequerySuggested();
//SelectedVM = VMList.FirstOrDefault();
});
}
}
#region Designer
private void InitDesigner()
{
var model = new AiModelDC()
{
ModelName = "N llama3.2"
};
var message_dc = new AiConversationMessageDC()
{
Created = DateTime.Now,
Message = "Nu bist eine intelligente Einheit mit ganz ganz vielen Eingaben: value1, value2, value3, value4\r\nTest",
Role = BS.Shared.AiConversationMessageRole.System
};
var message_dc2 = new AiConversationMessageDC()
{
Created = DateTime.Now,
Message = "N. Dies ist eine Design Frage: Du sollst ganz viele Sachen machen. Dabei sollst du auf ganz viele Sachen achten: Zum Beispiel:\r\nSache 1\r\nSchritt 2",
Role = BS.Shared.AiConversationMessageRole.User
};
var message_dc3 = new AiConversationMessageDC()
{
Created = DateTime.Now,
Message = "N. Deine Antwort. Dies ist eine Design Antwort. Du hast ganz viele Sachen angefragt. Dabei soll ich auf ganz viele Sachen achten. Wie Test, test, tEst und tesT.\r\nTest\r\nTest\r\nTest",
Role = BS.Shared.AiConversationMessageRole.Assistent,
ModelName = model.ModelName,
Duration = 10,
};
var messages_dc = new List<AiConversationMessageDC>()
{
message_dc,
message_dc2,
message_dc3,
message_dc2,
message_dc3,
message_dc2,
message_dc3,
message_dc2,
message_dc3,
};
var conversation_dc = new AiConversationDC()
{
Created = DateTime.Now,
Displayname = "Displayname Megamegalange Deluxe Op 3000",
Messages = messages_dc,
Modell = model,
UIContext = 19,
Updated = DateTime.Now,
};
var conversation_vm = new AiConversationVM(conversation_dc);
VMList.Add(conversation_vm);
InitDummyConversations(10);
//SelectedVM = conversation_vm;
}
private void InitDummyConversations(int count)
{
var model = new AiModelDC()
{
ModelName = "llama3.2"
};
for (int i = 0; i < count; i++)
{
var conversation_dc2 = new AiConversationDC()
{
Created = DateTime.Now,
Displayname = "Dummy Num " + i.ToString(),
Modell = model,
UIContext = 19,
Updated = DateTime.Now,
};
var conversation_vm2 = new AiConversationVM(conversation_dc2);
VMList.Add(conversation_vm2);
}
}
#endregion
}
}