using BS.Shared; using BS.Shared.DataContracts.Feature.AI; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using BeWo.ViewModel.ListViewModel; using System.Windows.Input; using BS.Shared.Core; using DevExpress.Mvvm; using BeWo.ServiceProxy; using BS.Shared.Extensions; using System.Diagnostics; using DevExpress.XtraCharts.Native; using static DevExpress.Utils.Drawing.Helpers.NativeMethods; using System.Security.Cryptography; using BeWo.ViewModel.Controls.AI; using DevExpress.Charts.Native; namespace BeWo.ViewModel.View.AI { public class AiConversationChatViewModel : DialogViewModel { private bool _IsSettingsOpen; private bool _IsCloneOpen; private bool _IsSending; private string _MessageInput; private AiModelDC _SelectedModel; private AiConfigVM _Config; private AiPromptbausteinPromptVM _SavePromptVM; public AiConversationChatViewModel() { Models = new ObservableSortCollection(); SendNewMessageCommand = new DelegateCommand(SendNewMessage, () => ListVM.SelectedVM is object && !string.IsNullOrWhiteSpace(MessageInput) && !IsSending); OpenNewConversationCommand = new DelegateCommand(OpenNewConversation, () => CanSendNewMessage && ListVM.SelectedVM is object); StartConversationWithMessageCommand = new DelegateCommand(StartConversationWithMessage, () => CanSendNewMessage && !string.IsNullOrWhiteSpace(MessageInput) && !IsSending); ReloadConfigCommand = new DelegateCommand(ReloadConfig); ReloadConversationsCommand = new DelegateCommand(ReloadConversations); ReloadModelsCommand = new DelegateCommand(ReloadModels); OpenSettingCommand = new DelegateCommand(OpenSetting, () => BeWoApp.AppSettings?.ModuleAiSettingsEnabled ?? false); RenameCommand = new DelegateCommand(Rename, () => ListVM.SelectedVM is object); OpenCloneCommand = new DelegateCommand(OpenClone, () => ListVM.SelectedVM is object && BeWoAppInfo.IsInAiDeveloperMode); CloneCommand = new DelegateCommand(Clone); AskDeleteCommand = new DelegateCommand(AskDelete, () => ListVM.SelectedVM is object); SavePromptCommand = new DelegateCommand(SavePrompt, vm => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModulePromptbausteineEdit)); AcceptSavePromptCommand = new DelegateCommand(AcceptSavePrompt, () => !string.IsNullOrWhiteSpace(SavePromptVM?.Title)); CancelSavePromptCommand = new DelegateCommand(CancelSavePrompt); ListVM = new AiConversationListVM(); ListVM.SelectedVMChanged += (s, e) => FirePropertyChanged(nameof(IsNewConversationVisible)); AssistentCommands = new List(); } public event EventHandler SendNewMessageSuccess; public ICommand SendNewMessageCommand { get; set; } public ICommand OpenNewConversationCommand { get; set; } public ICommand StartConversationWithMessageCommand { get; set; } public ICommand AskDeleteCommand { get; set; } public ICommand ReloadConfigCommand { get; set; } public ICommand ReloadConversationsCommand { get; set; } public ICommand ReloadModelsCommand { get; set; } public ICommand OpenSettingCommand { get; set; } public ICommand RenameCommand { get; set; } public ICommand OpenCloneCommand { get; set; } public ICommand CloneCommand { get; set; } public ICommand SavePromptCommand { get; set; } public ICommand AcceptSavePromptCommand { get; set; } public ICommand CancelSavePromptCommand { get; set; } public AiActionType ActionType { get; set; } public AiViewContextDC ViewContext { get; set; } public bool CanSendNewMessage { get; set; } public AiConversationListVM ListVM { get; set; } public ObservableCollection 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 AbstractBaseVM InputItem { get; set; } public List AssistentCommands { get; protected set; } 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 => ListVM.SelectedVM is null; public AiPromptbausteinPromptVM SavePromptVM { get => _SavePromptVM; set { if (SetProperty(ref _SavePromptVM, value, nameof(SavePromptVM))) { FirePropertyChanged(nameof(IsSavePromptOpen)); } } } public bool IsSavePromptOpen { get => SavePromptVM is object; set { if (!value) SavePromptVM = null; } } private void OpenNewConversation() { ListVM.SelectedVM = null; } private void StartConversationWithMessage() { StartSending(); try { var message = MessageInput; var conv = new AiConversationDC(); conv.Created = DateTime.Now; conv.Updated = DateTime.Now; conv.ActionType = ActionType; conv.Messages = new List() { new AiConversationMessageDC() { Message = message, Role = AiConversationMessageRole.User } }; var vm = InsertConverstion(conv); ServiceFacade.DoAiEnhancedServiceAsnyc( x => x.CreateAiConversationWithMessage(conv, ViewContext, message), dc => UpdateConverstion(vm, dc), e => { EndSending(); ListVM.VMList.Remove(vm); } ); } catch (Exception ex) { EndSending(); } } private void SendNewMessage() { StartSending(); try { var conv = ListVM.SelectedVM; var msg_dc = new AiConversationMessageDC(); msg_dc.Message = MessageInput; msg_dc.Role = BS.Shared.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])); conv.Updated = DateTime.Now; FinishSending(); }, (exception) => { conv.Messages.VMList.Remove(msg_vm); EndSending(); } ); } catch (Exception ex) { EndSending(); } } private void StartSending() { if (IsSending) throw new InvalidOperationException("Sendet bereits"); IsSending = true; IsWaiting = true; } private void EndSending() { if (!IsSending) throw new InvalidOperationException("Sendet nicht"); IsSending = false; IsWaiting = false; } private AiConversationVM InsertConverstion(AiConversationDC dc) { var vm = new AiConversationVM(dc); ListVM.VMList.Insert(0, vm); ListVM.SelectedVM = vm; return vm; } private void UpdateConverstion(AiConversationVM vm, AiConversationDC dc) { vm.UpdateByDataContract(dc); FinishSending(); } private void FinishSending() { MessageInput = string.Empty; ReloadConversations(ListVM.VMList); EndSending(); SendNewMessageSuccess?.Invoke(this, EventArgs.Empty); } private void ReloadConfig() { var config = ServiceFacade.DoAiEnhancedServiceSnyc(x => x.GetAiConfig()); if (Config is null) Config = new AiConfigVM(config); else Config.Update(config); //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 = ActionType; var reference = ViewContext.Primary; var list = VMFactory.CreateAiConversationListVM(ui_context, reference); ReloadConversations(list.VMList); } private void ReloadConversations(IEnumerable aiConversations) { if(aiConversations is null) { throw new ArgumentOutOfRangeException(nameof(aiConversations)); } var sorted = aiConversations.OrderByDescending(vm => vm.Updated).ToList(); var t0 = ListVM.SelectedVM; ListVM.VMList.UpdateBy(sorted); if(ListVM.VMList.Contains(t0)) ListVM.SelectedVM = t0; ListVM.VMList.ResetBindings(); } private void OpenSetting() { ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiModels(), (x) => { Models.MakeEqualTo(x); IsSettingsOpen = true; }); } private void Rename() { if (ListVM.SelectedVM is AiConversationVM vm) { vm.IsEditing = !vm.IsEditing; } } private void OpenClone() { foreach (var message in ListVM.SelectedVM.Messages.VMList) { message.SetIsChecked(true); } IsCloneOpen = true; } private void Clone() { var conv = ListVM.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 = ListVM.SelectedVM; var info = selected.Displayname; var oid = selected.DataContract.Oid; if (BeWoAppInfo.IsInAiDeveloperMode) { info += $":{oid}"; } var msg = $"Wollen Sie die ausgewählte Konversation ({info}) löschen?"; if (MessageBox.Show(msg, "Konversation löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes) { ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.DeleteAiConversation(oid.Value), () => { ListVM.VMList.Remove(selected); CommandManager.InvalidateRequerySuggested(); //SelectedVM = VMList.FirstOrDefault(); }); } } public void SavePrompt(AiConversationMessageVM message) { var dc = new AiPromptbausteinPromptDC(); dc.Creator = BeWoApp.CompactLoggedOnEmployee; dc.Prompt = message.Message; dc.CanEdit = true; dc.ActionType = AiActionType.ServiceRecordConversation; SavePromptVM = new AiPromptbausteinPromptVM(dc); } public void AcceptSavePrompt() { ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.InsertAiPromptbausteinPrompt(SavePromptVM.CommitToDataContract()), cb => SavePromptVM = null, exc => SavePromptVM = null); } public void CancelSavePrompt() { SavePromptVM = null; } public void ImportAssistentCommand(AiMenuItemTemplate origin) { var origin_command = origin.Command; var new_command = new DelegateCommand(x => { origin_command.Execute(x); Close(); }); var imported_menu_item = new AiMenuItemTemplate() { Command = new_command, Icon = origin.Icon, Name = origin.Name }; AssistentCommands.Add(imported_menu_item); } internal void Start() { if (InputItem is null) return; if (InputItem is AiPromptbausteinPromptVM prompt) { StartPrompt(prompt); } else if (InputItem is AiPromptbausteinRoutineVM routine) { StartRoutine(routine); } else { throw new ArgumentOutOfRangeException(nameof(InputItem)); } InputItem = null; } private void StartPrompt(AiPromptbausteinPromptVM prompt) { StartSending(); try { var conv = new AiConversationDC(); conv.Created = DateTime.Now; conv.Updated = DateTime.Now; conv.ActionType = ActionType; var vm = InsertConverstion(conv); Action error = (e) => { EndSending(); ListVM.VMList.Remove(vm); ServiceFacade.EndManuelWaiting(); }; ServiceFacade.StartManuelWaiting(); ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.CreateAiConversation(conv, ViewContext), cb => { vm.UpdateByDataContract(cb); var msg = prompt.Prompt; var msg_dc = new AiConversationMessageDC(); msg_dc.Message = msg; msg_dc.Role = BS.Shared.AiConversationMessageRole.User; msg_dc.Created = DateTime.Now; var msg_vm = new AiConversationMessageVM(msg_dc); vm.Messages.VMList.Add(msg_vm); ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.ExecuteAiConversationWithPrompt(cb.Oid.Value, ViewContext, prompt.DataContract.Oid.Value), cb2 => { vm.Updated = DateTime.Now; FinishSending(); ServiceFacade.EndManuelWaiting(); vm.Messages.VMList.Remove(msg_vm); vm.AddMessages(cb2); }, error); }, error); } catch (Exception ex) { EndSending(); } } private void StartRoutine(AiPromptbausteinRoutineVM routine) { StartSending(); try { var conv = new AiConversationDC(); conv.Created = DateTime.Now; conv.Updated = DateTime.Now; conv.ActionType = ActionType; var vm = InsertConverstion(conv); Action error = (e) => { EndSending(); ListVM.VMList.Remove(vm); ServiceFacade.EndManuelWaiting(); }; ServiceFacade.StartManuelWaiting(); ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.CreateAiConversation(conv, ViewContext), cb => { vm.UpdateByDataContract(cb); ExecuteChain(routine, 0, error); }, error); } catch (Exception ex) { EndSending(); } } private void ExecuteChain(AiPromptbausteinRoutineVM routine, int step, Action error) { var conv = ListVM.SelectedVM; if (step >= routine.Steps.Count) { conv.Updated = DateTime.Now; FinishSending(); ServiceFacade.EndManuelWaiting(); return; } var custom_viewContext = new AiViewContextDC { References = ViewContext.References, Primary = ViewContext.Primary }; if (step > 0 && routine.RoutineType == AiRoutineType.Chain) { custom_viewContext.Secondary = conv.Messages.VMList.Last().Message; } else { custom_viewContext.Secondary = ViewContext.Secondary; } var msg = routine.Steps.VMList[step].PromptReference.Prompt; var msg_dc = new AiConversationMessageDC { Message = msg, Role = AiConversationMessageRole.User, Created = DateTime.Now }; var msg_vm = new AiConversationMessageVM(msg_dc); conv.Messages.VMList.Add(msg_vm); ServiceFacade.DoAiEnhancedServiceAsnyc( x => x.ExecuteAiConversationWithRoutine(conv.Oid, custom_viewContext, routine.DataContract.Oid.Value, step), cb => { conv.Messages.VMList.Remove(msg_vm); conv.AddMessages(cb); ExecuteChain(routine, step + 1, error); }, error); } } }