Last Request
This commit is contained in:
@@ -310,6 +310,8 @@
|
||||
<add key="OpenWebUIUrl" value="https://owui1.ownsoft.de/"/>
|
||||
<add key="AiSystemPromptPath" value="C:\BeWoPlaner\AI\systemPrompts\customSystemPrompt.txt"/>
|
||||
<add key="AiServiceLogFilePath" value="C:\BeWoPlaner\logs2\server\aiservice.log.txt"/>
|
||||
<add key="AiServiceLastRequestEnabled" value="true"/>
|
||||
<add key="AiServiceLastRequestFilePath" value="C:\BeWoPlaner\logs2\server\lastairequest.json"/>
|
||||
</appSettings>
|
||||
<!-- <> <> <> Appsettings <> <> <> -->
|
||||
<devExpress>
|
||||
|
||||
387
Service/Plugins/AiService2.cs
Normal file
387
Service/Plugins/AiService2.cs
Normal file
@@ -0,0 +1,387 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.ServiceModel;
|
||||
using System.Text;
|
||||
using BeWo.Data.Access;
|
||||
using BeWo.Data.Entities;
|
||||
using BeWo.Data.Security;
|
||||
using BeWo.Service.AI;
|
||||
using BeWo.Service.Core;
|
||||
using BeWo.Service.DCEntityMapper;
|
||||
using BeWo.Service.Invoicing;
|
||||
using BeWo.Service.ServiceContracts;
|
||||
using BeWo.Service.ServiceProxy;
|
||||
using BS.Shared;
|
||||
using BS.Shared.Core;
|
||||
using BS.Shared.DataContracts;
|
||||
using BS.Shared.DataContracts.Compact;
|
||||
using BS.Shared.DataContracts.Feature.AI;
|
||||
using BS.Shared.Extensions;
|
||||
using Microsoft.ML.Tokenizers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BeWo.Service.Plugins
|
||||
{
|
||||
public class AiService2
|
||||
{
|
||||
// Was wird alles benötigt:
|
||||
// - WebConfig
|
||||
// - DBs
|
||||
|
||||
// ======================[ Config ]======================
|
||||
public AiConfigDC GetAiConfig()
|
||||
{
|
||||
var configs = DAOFactory.GenericDAO.GetAllActive<AiConfig>();
|
||||
|
||||
var config = configs.FirstOrDefault();
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
config = getDefaultAiConfig();
|
||||
|
||||
DAOFactory.GenericDAO.Insert(config);
|
||||
}
|
||||
|
||||
var config_dc = MapperFactory.AiConfig.MapToNewDC(config);
|
||||
|
||||
return config_dc;
|
||||
}
|
||||
public AiConfigDC UpdateAiConfig(AiConfigDC toUpdate)
|
||||
{
|
||||
if (toUpdate?.Oid is null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
var oid = toUpdate.Oid.Value;
|
||||
var entity = DAOFactory.GenericDAO.LoadByID<AiConfig>(oid);
|
||||
var update = MapperFactory.AiConfig.MergeWithEntity(toUpdate, entity);
|
||||
|
||||
DAOFactory.GenericDAO.Update(update);
|
||||
|
||||
var dc = MapperFactory.AiConfig.MapToNewDC(update);
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
// ======================[ Models ]======================
|
||||
public IEnumerable<AiModelDC> GetAiModels()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
return MapperFactory.AiModel.MapToNewDCs(models);
|
||||
}
|
||||
|
||||
|
||||
// ======================[ Conversations ]======================
|
||||
public IEnumerable<AiConversationDC> GetAiConversations(int uicontext, long? oid)
|
||||
{
|
||||
// SearchDAO
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
var convs = DAOFactory.GenericDAO.GetAllActive<AiConversation>();
|
||||
|
||||
var filter = new List<AiConversation>();
|
||||
foreach (var conv in convs)
|
||||
{
|
||||
if (conv.UIContext != uicontext)
|
||||
continue;
|
||||
|
||||
if (conv.ApplicationUserOid != current_user.Oid)
|
||||
continue;
|
||||
|
||||
if (oid is long ref_oid)
|
||||
{
|
||||
var main_ref_obj = conv.ContextBeWoObjects?.FirstOrDefault();
|
||||
|
||||
// ServiceRecord
|
||||
if (uicontext == 19)
|
||||
main_ref_obj = conv.ContextBeWoObjects.FirstOrDefault(x => x.Tid == TableID.SupportConcept);
|
||||
|
||||
if (main_ref_obj?.Oid != ref_oid)
|
||||
continue;
|
||||
}
|
||||
|
||||
filter.Add(conv);
|
||||
}
|
||||
|
||||
var dcs = MapperFactory.AiConversation.MapToNewDCs(filter);
|
||||
|
||||
return dcs;
|
||||
}
|
||||
|
||||
public AiConversationDC CreateAiConversation(AiConversationDC conversation, long modell_oid)
|
||||
{
|
||||
var conv = createAiConversation(conversation.UIContext, conversation.ContextBeWoObjects, modell_oid);
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
return conv_dc;
|
||||
}
|
||||
public AiConversationDC CreateAiConversationWithMessage(AiConversationDC conversation, long modell_oid, string message)
|
||||
{
|
||||
var conv = createAiConversation(conversation.UIContext, conversation.ContextBeWoObjects, modell_oid);
|
||||
|
||||
var new_messages = sendNewMessage(conv, message);
|
||||
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
|
||||
return conv_dc;
|
||||
}
|
||||
public AiConversationDC CloneAiConversation(long conversation_oid, long? last_message_oid)
|
||||
{
|
||||
var parent_conv = DAOFactory.GenericDAO.GetByID<AiConversation>(conversation_oid);
|
||||
|
||||
if (parent_conv is null)
|
||||
throw new InvalidOperationException("conv_oid unknown");
|
||||
|
||||
var clone_conv = new AiConversation();
|
||||
|
||||
clone_conv.Created = DateTime.Now;
|
||||
clone_conv.ContextBeWoObjects = parent_conv.ContextBeWoObjects.ToList();
|
||||
clone_conv.Displayname = "Klon von " + parent_conv.Displayname;
|
||||
clone_conv.Messages = new List<AiConversationMessage>();
|
||||
clone_conv.Modell = parent_conv.Modell;
|
||||
clone_conv.UIContext = parent_conv.UIContext;
|
||||
clone_conv.Updated = DateTime.Now;
|
||||
clone_conv.ApplicationUserOid = parent_conv.ApplicationUserOid;
|
||||
|
||||
if (last_message_oid is null)
|
||||
last_message_oid = parent_conv.Messages[0].Oid;
|
||||
|
||||
foreach (var msg in parent_conv.Messages)
|
||||
{
|
||||
var clone_msg = new AiConversationMessage();
|
||||
|
||||
clone_msg.Created = msg.Created;
|
||||
clone_msg.Message = msg.Message;
|
||||
clone_msg.Role = msg.Role;
|
||||
clone_msg.Duration = msg.Duration;
|
||||
clone_msg.ModelName = msg.ModelName;
|
||||
|
||||
clone_conv.Messages.Add(clone_msg);
|
||||
clone_msg.AiConversation = clone_conv;
|
||||
|
||||
if (msg.Oid == last_message_oid)
|
||||
break;
|
||||
}
|
||||
|
||||
DAOFactory.GenericDAO.Insert(clone_conv);
|
||||
|
||||
var dc = MapperFactory.AiConversation.MapToNewDC(clone_conv);
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
public long UpdateAiConversationDisplayname(long oid, long version, string displayname)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.GetByID<AiConversation>(oid);
|
||||
|
||||
ServiceLogic.ConcurrencyCheck(version, conv);
|
||||
|
||||
conv.Displayname = displayname;
|
||||
|
||||
DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
return conv.Version.Value;
|
||||
}
|
||||
|
||||
public void DeleteAiConversation(long conversation_oid)
|
||||
{
|
||||
var conversation = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation_oid);
|
||||
|
||||
DAOFactory.GenericDAO.SetActivationType(conversation, ActivationTypeId.Deleted);
|
||||
}
|
||||
|
||||
// ======================[ Conversationmessages ]======================
|
||||
public AiConversationMessageDC[] SendNewMessage(long conversation, string message)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation);
|
||||
|
||||
return sendNewMessage(conv, message);
|
||||
}
|
||||
|
||||
|
||||
// ======================[ private ]======================
|
||||
private AiConfig getDefaultAiConfig()
|
||||
{
|
||||
var config = new AiConfig();
|
||||
|
||||
config.Temperature = 1;
|
||||
config.Top_P = 1;
|
||||
config.Max_Gen_Len = 1000;
|
||||
config.SelectedModel = getDefaultAiModel();
|
||||
|
||||
return config;
|
||||
}
|
||||
private AiModel getDefaultAiModel()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
if (models == null || !models.Any())
|
||||
return null;
|
||||
|
||||
var llama = models.Where(x => x.ModelName.Contains("llama3.2"));
|
||||
|
||||
if (llama.Any())
|
||||
return llama.First();
|
||||
|
||||
return models.First();
|
||||
}
|
||||
private IEnumerable<AiModel> getAiModels()
|
||||
{
|
||||
var old_models = DAOFactory.GenericDAO.GetAll<AiModel>();
|
||||
var new_models = ServiceFacade.OpenWebApiClient.GetAiModelle().GetResponseData();
|
||||
var unknown_models = new_models.ToList();
|
||||
|
||||
foreach (var old_model in old_models)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (var new_model in new_models)
|
||||
{
|
||||
if (old_model.ModelName == new_model.ModelName)
|
||||
{
|
||||
if (old_model.IsActive != BS.Shared.ActivationTypeId.Active)
|
||||
DAOFactory.GenericDAO.SetActivationType(old_model, BS.Shared.ActivationTypeId.Active);
|
||||
|
||||
found = true;
|
||||
unknown_models.Remove(new_model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
DAOFactory.GenericDAO.Deactivate(old_model);
|
||||
}
|
||||
|
||||
if (unknown_models.Count != 0)
|
||||
{
|
||||
foreach (var unknown_model in unknown_models)
|
||||
{
|
||||
DAOFactory.GenericDAO.Insert(unknown_model);
|
||||
}
|
||||
}
|
||||
|
||||
var models = DAOFactory.GenericDAO.GetAllActive<AiModel>();
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
private AiConversation createAiConversation(int uicontext, Dictionary<TableID, long[]> context, long modell_oid)
|
||||
{
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
|
||||
var system_prompt = AiPromptFactory.CreateSystemInstructions(uicontext, context);
|
||||
|
||||
var conv = new AiConversation();
|
||||
conv.Created = DateTime.Now;
|
||||
conv.ContextBeWoObjects = MapperFactory.AiConversation.Parse(context);
|
||||
conv.Displayname = "Neue Unterhaltung";
|
||||
conv.Messages = new List<AiConversationMessage>();
|
||||
conv.Modell = DAOFactory.GenericDAO.LoadByID<AiModel>(modell_oid);
|
||||
conv.UIContext = uicontext;
|
||||
conv.Updated = DateTime.Now;
|
||||
conv.ApplicationUserOid = current_user.Oid;
|
||||
|
||||
var msg = new AiConversationMessage();
|
||||
msg.Message = system_prompt;
|
||||
msg.AiConversation = conv;
|
||||
msg.Role = AiConversationMessageRole.System;
|
||||
msg.Created = DateTime.Now;
|
||||
|
||||
conv.Messages.Add(msg);
|
||||
|
||||
DAOFactory.GenericDAO.Insert(conv);
|
||||
|
||||
return conv;
|
||||
}
|
||||
|
||||
private AiConversationMessageDC[] sendNewMessage(AiConversation conv, string message)
|
||||
{
|
||||
// Hole Config
|
||||
var config = GetAiConfig();
|
||||
var configModelName = config.SelectedModel.ModelName;
|
||||
|
||||
// Build Payload
|
||||
var payload = new
|
||||
{
|
||||
model = configModelName,
|
||||
messages = conv.Messages.Select(m => new { role = m.Role.ToString().ToLower(), content = m.Message })
|
||||
};
|
||||
|
||||
// Check Token Size
|
||||
checkTokenSize(conv.Messages, configModelName);
|
||||
|
||||
// Updated
|
||||
conv.Updated = DateTime.Now;
|
||||
|
||||
// Füge Message hinzu
|
||||
var user_msg = new AiConversationMessage();
|
||||
user_msg.Message = message;
|
||||
user_msg.AiConversation = conv;
|
||||
user_msg.Role = BS.Shared.AiConversationMessageRole.User;
|
||||
user_msg.Created = DateTime.Now;
|
||||
|
||||
conv.Messages.Add(user_msg);
|
||||
|
||||
// Update DB Entity
|
||||
// DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
var user_msg_dc = MapperFactory.AiConversationMessage.MapToNewDC(user_msg);
|
||||
|
||||
// Send Request, wait for Response
|
||||
var dt_before_request = DateTime.Now;
|
||||
var response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(payload, out var message2, out var model, out var duration);
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(response.Copy<string>());
|
||||
File.WriteAllText(MergedConfig.GetSetting("AiServiceLogFilePath"), json);
|
||||
}
|
||||
|
||||
var result = response.GetResponseData();
|
||||
|
||||
// Antwort
|
||||
var assi_msg = new AiConversationMessage();
|
||||
assi_msg.Message = message2;
|
||||
assi_msg.AiConversation = conv;
|
||||
assi_msg.Role = BS.Shared.AiConversationMessageRole.Assistent;
|
||||
assi_msg.Created = dt_before_request;
|
||||
assi_msg.Duration = duration ?? 0;
|
||||
assi_msg.ModelName = model;
|
||||
|
||||
conv.Messages.Add(assi_msg);
|
||||
|
||||
// Update conv.
|
||||
DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
var assi_msg_dc = MapperFactory.AiConversationMessage.MapToNewDC(assi_msg);
|
||||
|
||||
return new AiConversationMessageDC[] { user_msg_dc, assi_msg_dc };
|
||||
}
|
||||
|
||||
private void checkTokenSize(IList<AiConversationMessage> messages, string configModelName)
|
||||
{
|
||||
Tokenizer tokenizer = TiktokenTokenizer.CreateForModel(configModelName);
|
||||
|
||||
int tokens = countChatTokens(messages, tokenizer);
|
||||
}
|
||||
|
||||
private int countChatTokens(IList<AiConversationMessage> messages, Tokenizer tokenizer)
|
||||
{
|
||||
int tokensPerMessage = 4; // OpenAI Overhead
|
||||
int tokensPerReply = 2;
|
||||
|
||||
int total = 0;
|
||||
|
||||
foreach (var msg in messages)
|
||||
{
|
||||
total += tokensPerMessage;
|
||||
total += tokenizer.CountTokens(msg.Role.ToString());
|
||||
total += tokenizer.CountTokens(msg.Message);
|
||||
}
|
||||
|
||||
return total + tokensPerReply;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,6 +457,7 @@
|
||||
<Compile Include="Multitenancy\MultitenancyEndpointBehavior.cs" />
|
||||
<Compile Include="OwnChat\OwnChatHelper.cs" />
|
||||
<Compile Include="PivotTabelle\FlexibleReportManager.cs" />
|
||||
<Compile Include="Plugins\AiService2.cs" />
|
||||
<Compile Include="Plugins\AiService.cs" />
|
||||
<Compile Include="Plugins\AccountingService.cs" />
|
||||
<Compile Include="Plugins\CustomerService.cs" />
|
||||
|
||||
@@ -5,6 +5,7 @@ using BeWo.Data.Security;
|
||||
using BeWo.Service.AI;
|
||||
using BeWo.Service.Core;
|
||||
using BeWo.Service.DCEntityMapper;
|
||||
using BeWo.Service.Plugins;
|
||||
using BeWo.Service.ServiceContracts;
|
||||
using BeWo.Service.ServiceProxy;
|
||||
using BS.Shared;
|
||||
@@ -22,6 +23,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.Remoting.Metadata.W3cXsd2001;
|
||||
using System.Security.Cryptography;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
@@ -35,325 +37,58 @@ namespace BeWo.Service.ServiceImplementations
|
||||
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
|
||||
public class AiEnhancedServiceImp : IAiEnhancedService
|
||||
{
|
||||
// Was wird alles benötigt:
|
||||
// - WebConfig
|
||||
// - DBs
|
||||
|
||||
// ======================[ Config ]======================
|
||||
public AiConfigDC GetAiConfig()
|
||||
{
|
||||
var configs = DAOFactory.GenericDAO.GetAllActive<AiConfig>();
|
||||
|
||||
var config = configs.FirstOrDefault();
|
||||
|
||||
if(config == null)
|
||||
{
|
||||
config = getDefaultAiConfig();
|
||||
|
||||
DAOFactory.GenericDAO.Insert(config);
|
||||
}
|
||||
|
||||
var config_dc = MapperFactory.AiConfig.MapToNewDC(config);
|
||||
|
||||
return config_dc;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.GetAiConfig();
|
||||
}
|
||||
public AiConfigDC UpdateAiConfig(AiConfigDC toUpdate)
|
||||
{
|
||||
if (toUpdate?.Oid is null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
var oid = toUpdate.Oid.Value;
|
||||
var entity = DAOFactory.GenericDAO.LoadByID<AiConfig>(oid);
|
||||
var update = MapperFactory.AiConfig.MergeWithEntity(toUpdate, entity);
|
||||
|
||||
DAOFactory.GenericDAO.Update(update);
|
||||
|
||||
var dc = MapperFactory.AiConfig.MapToNewDC(update);
|
||||
|
||||
return dc;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.UpdateAiConfig(toUpdate);
|
||||
}
|
||||
|
||||
// ======================[ Models ]======================
|
||||
public IEnumerable<AiModelDC> GetAiModels()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
return MapperFactory.AiModel.MapToNewDCs(models);
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.GetAiModels();
|
||||
}
|
||||
|
||||
|
||||
// ======================[ Conversations ]======================
|
||||
public IEnumerable<AiConversationDC> GetAiConversations(int uicontext, long? oid)
|
||||
{
|
||||
// SearchDAO
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
var convs = DAOFactory.GenericDAO.GetAllActive<AiConversation>();
|
||||
|
||||
var filter = new List<AiConversation>();
|
||||
foreach (var conv in convs)
|
||||
{
|
||||
if (conv.UIContext != uicontext)
|
||||
continue;
|
||||
|
||||
if (conv.ApplicationUserOid != current_user.Oid)
|
||||
continue;
|
||||
|
||||
if (oid is long ref_oid)
|
||||
{
|
||||
var main_ref_obj = conv.ContextBeWoObjects?.FirstOrDefault();
|
||||
|
||||
// ServiceRecord
|
||||
if (uicontext == 19)
|
||||
main_ref_obj = conv.ContextBeWoObjects.FirstOrDefault(x => x.Tid == TableID.SupportConcept);
|
||||
|
||||
if (main_ref_obj?.Oid != ref_oid)
|
||||
continue;
|
||||
}
|
||||
|
||||
filter.Add(conv);
|
||||
}
|
||||
|
||||
var dcs = MapperFactory.AiConversation.MapToNewDCs(filter);
|
||||
|
||||
return dcs;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.GetAiConversations(uicontext, oid);
|
||||
}
|
||||
|
||||
public AiConversationDC CreateAiConversation(AiConversationDC conversation, long modell_oid)
|
||||
{
|
||||
var conv = CreateAiConversation(conversation.UIContext, conversation.ContextBeWoObjects, modell_oid);
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
return conv_dc;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.CreateAiConversation(conversation, modell_oid);
|
||||
}
|
||||
public AiConversationDC CreateAiConversationWithMessage(AiConversationDC conversation, long modell_oid, string message)
|
||||
{
|
||||
var conv = CreateAiConversation(conversation.UIContext, conversation.ContextBeWoObjects, modell_oid);
|
||||
|
||||
var new_messages = SendNewMessage(conv, message);
|
||||
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
|
||||
return conv_dc;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.CreateAiConversationWithMessage(conversation, modell_oid, message);
|
||||
}
|
||||
public AiConversationDC CloneAiConversation(long conversation_oid, long? last_message_oid)
|
||||
{
|
||||
var parent_conv = DAOFactory.GenericDAO.GetByID<AiConversation>(conversation_oid);
|
||||
|
||||
if (parent_conv is null)
|
||||
throw new InvalidOperationException("conv_oid unknown");
|
||||
|
||||
var clone_conv = new AiConversation();
|
||||
|
||||
clone_conv.Created = DateTime.Now;
|
||||
clone_conv.ContextBeWoObjects = parent_conv.ContextBeWoObjects.ToList();
|
||||
clone_conv.Displayname = "Klon von " + parent_conv.Displayname;
|
||||
clone_conv.Messages = new List<AiConversationMessage>();
|
||||
clone_conv.Modell = parent_conv.Modell;
|
||||
clone_conv.UIContext = parent_conv.UIContext;
|
||||
clone_conv.Updated = DateTime.Now;
|
||||
clone_conv.ApplicationUserOid = parent_conv.ApplicationUserOid;
|
||||
|
||||
if (last_message_oid is null)
|
||||
last_message_oid = parent_conv.Messages[0].Oid;
|
||||
|
||||
foreach (var msg in parent_conv.Messages)
|
||||
{
|
||||
var clone_msg = new AiConversationMessage();
|
||||
|
||||
clone_msg.Created = msg.Created;
|
||||
clone_msg.Message = msg.Message;
|
||||
clone_msg.Role = msg.Role;
|
||||
clone_msg.Duration = msg.Duration;
|
||||
clone_msg.ModelName = msg.ModelName;
|
||||
|
||||
clone_conv.Messages.Add(clone_msg);
|
||||
clone_msg.AiConversation = clone_conv;
|
||||
|
||||
if (msg.Oid == last_message_oid)
|
||||
break;
|
||||
}
|
||||
|
||||
DAOFactory.GenericDAO.Insert(clone_conv);
|
||||
|
||||
var dc = MapperFactory.AiConversation.MapToNewDC(clone_conv);
|
||||
|
||||
return dc;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.CloneAiConversation(conversation_oid, last_message_oid);
|
||||
}
|
||||
|
||||
public long UpdateAiConversationDisplayname(long oid, long version, string displayname)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.GetByID<AiConversation>(oid);
|
||||
|
||||
ServiceLogic.ConcurrencyCheck(version, conv);
|
||||
|
||||
conv.Displayname = displayname;
|
||||
|
||||
DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
return conv.Version.Value;
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.UpdateAiConversationDisplayname(oid, version, displayname);
|
||||
}
|
||||
|
||||
public void DeleteAiConversation(long conversation_oid)
|
||||
{
|
||||
var conversation = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation_oid);
|
||||
|
||||
DAOFactory.GenericDAO.SetActivationType(conversation, ActivationTypeId.Deleted);
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
p.DeleteAiConversation(conversation_oid);
|
||||
}
|
||||
|
||||
// ======================[ Conversationmessages ]======================
|
||||
public AiConversationMessageDC[] SendNewMessage(long conversation, string message)
|
||||
{
|
||||
var conv = DAOFactory.GenericDAO.LoadByID<AiConversation>(conversation);
|
||||
|
||||
return SendNewMessage(conv, message);
|
||||
}
|
||||
|
||||
|
||||
// ======================[ private ]======================
|
||||
private AiConfig getDefaultAiConfig()
|
||||
{
|
||||
var config = new AiConfig();
|
||||
|
||||
config.Temperature = 1;
|
||||
config.Top_P = 1;
|
||||
config.Max_Gen_Len = 1000;
|
||||
config.SelectedModel = getDefaultAiModel();
|
||||
|
||||
return config;
|
||||
}
|
||||
private AiModel getDefaultAiModel()
|
||||
{
|
||||
var models = getAiModels();
|
||||
|
||||
if (models == null || !models.Any())
|
||||
return null;
|
||||
|
||||
var llama = models.Where(x => x.ModelName.Contains("llama3.2"));
|
||||
|
||||
if(llama.Any())
|
||||
return llama.First();
|
||||
|
||||
return models.First();
|
||||
}
|
||||
private IEnumerable<AiModel> getAiModels()
|
||||
{
|
||||
var old_models = DAOFactory.GenericDAO.GetAll<AiModel>();
|
||||
var new_models = ServiceFacade.OpenWebApiClient.GetAiModelle().GetResponseData();
|
||||
var unknown_models = new_models.ToList();
|
||||
|
||||
foreach (var old_model in old_models)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (var new_model in new_models)
|
||||
{
|
||||
if (old_model.ModelName == new_model.ModelName)
|
||||
{
|
||||
if (old_model.IsActive != BS.Shared.ActivationTypeId.Active)
|
||||
DAOFactory.GenericDAO.SetActivationType(old_model, BS.Shared.ActivationTypeId.Active);
|
||||
|
||||
found = true;
|
||||
unknown_models.Remove(new_model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
DAOFactory.GenericDAO.Deactivate(old_model);
|
||||
}
|
||||
|
||||
if (unknown_models.Count != 0)
|
||||
{
|
||||
foreach (var unknown_model in unknown_models)
|
||||
{
|
||||
DAOFactory.GenericDAO.Insert(unknown_model);
|
||||
}
|
||||
}
|
||||
|
||||
var models = DAOFactory.GenericDAO.GetAllActive<AiModel>();
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
private AiConversation CreateAiConversation(int uicontext, Dictionary<TableID, long[]> context, long modell_oid)
|
||||
{
|
||||
var current_user = UserRightHelper.GetLoggedInUserWithOid();
|
||||
|
||||
var system_prompt = AiPromptFactory.CreateSystemInstructions(uicontext, context);
|
||||
|
||||
var conv = new AiConversation();
|
||||
conv.Created = DateTime.Now;
|
||||
conv.ContextBeWoObjects = MapperFactory.AiConversation.Parse(context);
|
||||
conv.Displayname = "Neue Unterhaltung";
|
||||
conv.Messages = new List<AiConversationMessage>();
|
||||
conv.Modell = DAOFactory.GenericDAO.LoadByID<AiModel>(modell_oid);
|
||||
conv.UIContext = uicontext;
|
||||
conv.Updated = DateTime.Now;
|
||||
conv.ApplicationUserOid = current_user.Oid;
|
||||
|
||||
var msg = new AiConversationMessage();
|
||||
msg.Message = system_prompt;
|
||||
msg.AiConversation = conv;
|
||||
msg.Role = AiConversationMessageRole.System;
|
||||
msg.Created = DateTime.Now;
|
||||
|
||||
conv.Messages.Add(msg);
|
||||
|
||||
DAOFactory.GenericDAO.Insert(conv);
|
||||
|
||||
return conv;
|
||||
}
|
||||
|
||||
private AiConversationMessageDC[] SendNewMessage(AiConversation conv, string message)
|
||||
{
|
||||
// Updated
|
||||
conv.Updated = DateTime.Now;
|
||||
|
||||
// Füge Message hinzu
|
||||
var user_msg = new AiConversationMessage();
|
||||
user_msg.Message = message;
|
||||
user_msg.AiConversation = conv;
|
||||
user_msg.Role = BS.Shared.AiConversationMessageRole.User;
|
||||
user_msg.Created = DateTime.Now;
|
||||
|
||||
conv.Messages.Add(user_msg);
|
||||
|
||||
// Update DB Entity
|
||||
// DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
var conv_dc = MapperFactory.AiConversation.MapToNewDC(conv);
|
||||
var user_msg_dc = MapperFactory.AiConversationMessage.MapToNewDC(user_msg);
|
||||
|
||||
// Hole Config
|
||||
var config = GetAiConfig();
|
||||
|
||||
// Send Request, wait for Response
|
||||
var dt_before_request = DateTime.Now;
|
||||
var response = ServiceFacade.OpenWebApiClient.SendAiMessageRequest(conv_dc, config, out var message2, out var model, out var duration);
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(response.Copy<string>());
|
||||
File.WriteAllText(MergedConfig.GetSetting("AiServiceLogFilePath"), json);
|
||||
}
|
||||
|
||||
var result = response.GetResponseData();
|
||||
|
||||
// Antwort
|
||||
var assi_msg = new AiConversationMessage();
|
||||
assi_msg.Message = message2;
|
||||
assi_msg.AiConversation = conv;
|
||||
assi_msg.Role = BS.Shared.AiConversationMessageRole.Assistent;
|
||||
assi_msg.Created = dt_before_request;
|
||||
assi_msg.Duration = duration ?? 0;
|
||||
assi_msg.ModelName = model;
|
||||
|
||||
conv.Messages.Add(assi_msg);
|
||||
|
||||
// Update conv.
|
||||
DAOFactory.GenericDAO.Update(conv);
|
||||
|
||||
var assi_msg_dc = MapperFactory.AiConversationMessage.MapToNewDC(assi_msg);
|
||||
|
||||
return new AiConversationMessageDC[] { user_msg_dc, assi_msg_dc };
|
||||
var p = PluginLoader.FindClass<AiService2>();
|
||||
return p.SendNewMessage(conversation, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using static DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper;
|
||||
|
||||
@@ -62,7 +63,7 @@ namespace BeWo.Service.ServiceProxy
|
||||
return ApiResponse<IEnumerable<AiModel>>.SuccessResponse(data);
|
||||
}
|
||||
|
||||
public ApiResponse<string> SendAiMessageRequest(AiConversationDC conversation, AiConfigDC config, out string message, out string model, out int? duration)
|
||||
public ApiResponse<string> SendAiMessageRequest(dynamic payload, out string message, out string model, out int? duration)
|
||||
{
|
||||
message = null;
|
||||
duration = null;
|
||||
@@ -70,12 +71,6 @@ namespace BeWo.Service.ServiceProxy
|
||||
|
||||
var sub_url = "api/chat/completions";
|
||||
|
||||
var payload = new
|
||||
{
|
||||
model = config.SelectedModel.ModelName,
|
||||
messages = conversation.Messages.Select(m => new { role = m.Role.ToString().ToLower(), content = m.Message })
|
||||
};
|
||||
|
||||
var response_format = new
|
||||
{
|
||||
id = string.Empty,
|
||||
@@ -101,6 +96,17 @@ namespace BeWo.Service.ServiceProxy
|
||||
|
||||
_PostClientFacade.JsonObject = payload;
|
||||
|
||||
if (MergedConfig.GetSetting("AiServiceLastRequestEnabled") is string str && bool.TryParse(str, out bool b) && b)
|
||||
{
|
||||
var path = MergedConfig.GetSetting("AiServiceLastRequestFilePath");
|
||||
if (Directory.GetParent(path) == null)
|
||||
throw new ArgumentException("AiServiceLastRequestFilePath ungültig");
|
||||
|
||||
var payload_ser = JsonConvert.SerializeObject(_PostClientFacade.JsonObject, Formatting.Indented);
|
||||
|
||||
File.WriteAllText(path, payload_ser);
|
||||
}
|
||||
|
||||
var response = _PostClientFacade.GetAnonymousTypeAsync(sub_url, response_format, _ErrorExtractor).GetAwaiter().GetResult();
|
||||
|
||||
if (!response.Success)
|
||||
|
||||
Reference in New Issue
Block a user