Files
BeWoPlaner/BeWo/ViewModel/View/AI/AiConversationChatViewModel.cs
2026-03-16 14:08:48 +01:00

463 lines
11 KiB
C#

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;
namespace BeWo.ViewModel.View.AI
{
public class AiConversationChatViewModel : DialogViewModel
{
private bool _IsSettingsOpen;
private bool _IsCloneOpen;
private bool _IsSending;
private string _MessageInput;
private string _ContextInput;
private AiModelDC _SelectedModel;
private AiConfigVM _Config;
private AiPromptbausteinPromptVM _SavePromptVM;
public AiConversationChatViewModel()
{
Models = new ObservableSortCollection<AiModelDC>();
SendNewMessageCommand = new DelegateCommand(SendNewMessage, () => ListVM.SelectedVM is object && !string.IsNullOrWhiteSpace(MessageInput) && !IsSending);
OpenNewConversationCommand = new DelegateCommand(OpenNewConversation, () => CanSendNewMessage && BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleServiceRecordChat));
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, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleServiceRecordChat) && ListVM.SelectedVM is object);
OpenCloneCommand = new DelegateCommand(OpenClone, () => ListVM.SelectedVM is object && BeWoAppInfo.IsInAiDeveloperMode);
CloneCommand = new DelegateCommand(Clone);
AskDeleteCommand = new DelegateCommand(AskDelete, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleServiceRecordChat) && ListVM.SelectedVM is object);
SavePromptCommand = new DelegateCommand<AiConversationMessageVM>(SavePrompt, vm => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModulePromptbausteineEdit));
AcceptSavePromptCommand = new DelegateCommand(AcceptSavePrompt);
CancelSavePromptCommand = new DelegateCommand(CancelSavePrompt);
ListVM = new AiConversationListVM();
ListVM.SelectedVMChanged += (s, e) => FirePropertyChanged(nameof(IsNewConversationVisible));
}
public event EventHandler SendNewMessageSuccess;
public ICommand SendNewMessageCommand { get; set; }
public ICommand OpenNewConversationCommand { get; set; }
public ICommand StartConversationWithMessageCommand { get; set; }
public ICommand RequestNewConversationCommand { get; set; }
public ICommand TestCommand { 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 bool CanSendNewMessage { get; set; }
public bool SendAfterLoaded { get; set; }
public AiConversationListVM ListVM { 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 => ListVM.SelectedVM is null;
public AiContextType AiContext { get; set; }
public long? ReferenceObjectOid { get; set; }
public Dictionary<TableID, long[]> ContextBeWoObjects { get; set; }
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 StartConversationWithMessage()
{
StartSending();
try
{
var message = MessageInput;
var conv = new AiConversationDC();
conv.Created = DateTime.Now;
conv.Updated = DateTime.Now;
conv.UIContext = AiContext;
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();
ListVM.VMList.Remove(vm);
}
);
}
catch (Exception ex)
{
EndSending();
}
}
private void OpenNewConversation()
{
ListVM.SelectedVM = null;
}
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]));
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 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);
MessageInput = string.Empty;
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 = AiContext;
var reference = ReferenceObjectOid;
var list = VMFactory.CreateAiConversationListVM(ui_context, reference);
ListVM.VMList.MakeEqualTo(list.VMList);
}
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(new List<AiPromptbausteinPromptDC>() { SavePromptVM.CommitToDataContract() }), cb => SavePromptVM = null, exc => SavePromptVM = null);
}
public void CancelSavePrompt()
{
SavePromptVM = null;
}
}
}