Files
BeWoPlaner/BeWo/ViewModel/View/AI/AiConversationChatViewModel.cs

405 lines
9.7 KiB
C#
Raw Normal View History

2025-11-24 12:20:26 +01:00
using BS.Shared;
2025-05-14 10:05:15 +02:00
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;
2025-11-24 12:20:26 +01:00
using BeWo.ViewModel.View.Dialogs;
2025-05-14 10:05:15 +02:00
using System.Windows.Input;
using BS.Shared.Core;
using DevExpress.Mvvm;
using BeWo.ServiceProxy;
using BS.Shared.Extensions;
2025-11-05 11:49:53 +01:00
namespace BeWo.ViewModel.View.AI
2025-05-14 10:05:15 +02:00
{
Merge branch 'master' into feature_rene_18_ai - kein kommentar... # Conflicts: # BeWo/BeWo.csproj # BeWo/BeWoApp.xaml.cs # BeWo/ServiceProxy/GeneratedAiEnhancedService.cs # BeWo/Services/BeWoControlFactory.cs # BeWo/Services/BeWoWindowFactory.cs # BeWo/Services/BeWoWindowService.cs # BeWo/Services/IControlFactory.cs # BeWo/Services/IWindowFactory.cs # BeWo/Services/IWindowService.cs # BeWo/View/BeWoFileView.xaml # BeWo/View/Detail/Report/AbwesenheitsView.xaml # BeWo/View/Windows/AnimatedBeWoWindow.xaml.cs # BeWo/app.config # BeWoAllReports.sln # BeWoPlanerMobil.sln # BeWoPlanerMobil/.vs/BeWoPlanerMobil.csproj.dtbcache.json # BeWoTests.sln # Dakota/DakotaUtils.cs # Dakota/Logic/DakotaInfoCreator.cs # Dakota/Models/DakotaFile.cs # Data/Access/GenericDAO.cs # Data/Access/SearchDAO.cs # Data/Data.csproj # Host/Web.config # Server/Components/ServerUtils/ApiFacade/WebClientFacade.cs # Service/BeWoServiceEnums.cs # Service/Core/ServiceHelper.cs # Service/Core/ServiceValidator.cs # Service/Extensions/ServiceEnumExtension.cs # Service/Service.csproj # Service/ServiceContracts/Enhanced/IAiEnhancedService.cs # Service/ServiceContracts/Enhanced/IOperationsEnhancedService.cs # Service/ServiceImplementations/EmployeeServiceImp.cs # Service/ServiceImplementations/Enhanced/AiEnhancedServiceImp.cs # Service/ServiceImplementations/Enhanced/OperationsEnhancedServiceImp.cs # Service/ServiceProxy/OpenWebUIFacade.cs # Service/ServiceProxy/ServiceFacade.cs # Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs # Shared/BeWoEntityEnums.cs # Shared/Core/AppError.cs # Shared/Core/Facade/WebClientFacade.cs # Shared/Core/WebClientFacade.cs # Shared/Shared.csproj
2025-11-28 12:07:35 +01:00
public class AiConversationChatViewModel : BaseDialogViewModel
2025-05-14 10:05:15 +02:00
{
private bool _IsSettingsOpen;
private bool _IsCloneOpen;
private bool _IsSending;
private string _MessageInput;
private string _ContextInput;
private AiModelDC _SelectedModel;
private AiConfigVM _Config;
public AiConversationChatViewModel()
{
Models = new ObservableSortCollection<AiModelDC>();
SendNewMessageCommand = new DelegateCommand(SendNewMessage, () => ListVM.SelectedVM is object && !string.IsNullOrWhiteSpace(MessageInput) && !IsSending);
OpenNewConversationCommand = new DelegateCommand(OpenNewConversation, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatAdd));
StartConversationWithMessageCommand = new DelegateCommand(StartConversationWithMessage, () => !string.IsNullOrWhiteSpace(MessageInput) && !IsSending);
ReloadConfigCommand = new DelegateCommand(ReloadConfig);
ReloadConversationsCommand = new DelegateCommand(ReloadConversations);
ReloadModelsCommand = new DelegateCommand(ReloadModels);
OpenSettingCommand = new DelegateCommand(OpenSetting, () => (BeWoApp.AppSettings?.ModuleAiSettingsEnabled ?? true) && BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleViewSetting));
2025-07-08 16:30:58 +02:00
RenameCommand = new DelegateCommand(Rename, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatEdit) && ListVM.SelectedVM is object);
2025-08-20 12:10:53 +02:00
OpenCloneCommand = new DelegateCommand(OpenClone, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatClone) && ListVM.SelectedVM is object && BeWoAppInfo.IsInAiDeveloperMode);
2025-05-14 10:05:15 +02:00
CloneCommand = new DelegateCommand(Clone);
2025-08-20 12:10:53 +02:00
2025-05-14 10:05:15 +02:00
AskDeleteCommand = new DelegateCommand(AskDelete, () => BeWoApp.HasLoggedOnUserRight(UserRightType.AiModuleChatDelete) && ListVM.SelectedVM is object);
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; }
2025-07-08 16:30:58 +02:00
public ICommand RenameCommand { get; set; }
2025-05-14 10:05:15 +02:00
public ICommand OpenCloneCommand { get; set; }
public ICommand CloneCommand { 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;
2025-07-25 14:27:57 +02:00
public AiContextType UIContext { get; set; }
2025-05-14 10:05:15 +02:00
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;
2025-07-25 14:27:57 +02:00
conv.UIContext = UIContext;
2025-05-14 10:05:15 +02:00
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),
2025-07-04 14:27:08 +02:00
e => {
EndSending();
ListVM.VMList.Remove(vm);
}
);
2025-05-14 10:05:15 +02:00
}
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()
{
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;
VMFactory.CreateAiConversationListVM(ui_context, reference, (listvm) =>
{
ListVM.VMList.MakeEqualTo(listvm.VMList);
});
}
private void OpenSetting()
{
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.GetAiModels(), (x) =>
{
Models.MakeEqualTo(x);
IsSettingsOpen = true;
});
}
2025-07-08 16:30:58 +02:00
private void Rename()
{
if(ListVM.SelectedVM is AiConversationVM vm)
{
vm.IsEditing = !vm.IsEditing;
}
}
2025-05-14 10:05:15 +02:00
private void OpenClone()
{
foreach (var message in ListVM.SelectedVM.Messages.VMList)
{
2025-07-09 15:30:54 +02:00
message.SetIsChecked(true);
2025-05-14 10:05:15 +02:00
}
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;
2025-07-03 14:39:22 +02:00
var info = selected.Displayname;
2025-05-14 10:05:15 +02:00
2025-07-03 14:39:22 +02:00
var oid = selected.DataContract.Oid;
2025-08-20 12:10:53 +02:00
if (BeWoAppInfo.IsInAiDeveloperMode)
2025-07-03 14:39:22 +02:00
{
info += $":{oid}";
}
var msg = $"Wollen Sie die ausgewählte Konversation ({info}) löschen?";
2025-05-14 10:05:15 +02:00
if (MessageBox.Show(msg, "Konversation löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning) ==
MessageBoxResult.Yes)
{
2025-07-03 14:39:22 +02:00
ServiceFacade.DoAiEnhancedServiceAsnyc(x => x.DeleteAiConversation(oid.Value), () => {
2025-05-14 10:05:15 +02:00
ListVM.VMList.Remove(selected);
CommandManager.InvalidateRequerySuggested();
//SelectedVM = VMList.FirstOrDefault();
});
}
}
}
}