using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Conversations.Settings; using BotSharp.Abstraction.Knowledges.Models; using BotSharp.Abstraction.MLTasks; using System.Text.Json; namespace BotSharp.Core.Conversations.Services; public class ConversationService : IConversationService { private readonly IServiceProvider _services; private readonly IUserIdentity _user; private readonly ConversationSetting _settings; private readonly IConversationStorage _storage; public ConversationService(IServiceProvider services, IUserIdentity user, ConversationSetting settings, IConversationStorage storage) { _services = services; _user = user; _settings = settings; _storage = storage; } public Task DeleteConversation(string id) { throw new NotImplementedException(); } public async Task GetConversation(string id) { var db = _services.GetRequiredService(); var query = from sess in db.Conversation where sess.Id == id orderby sess.CreatedTime descending select sess.ToConversation(); return query.FirstOrDefault(); } public async Task> GetConversations() { var db = _services.GetRequiredService(); var query = from sess in db.Conversation where sess.UserId == _user.Id orderby sess.CreatedTime descending select sess.ToConversation(); return query.ToList(); } public async Task NewConversation(Conversation sess) { var db = _services.GetRequiredService(); var record = ConversationRecord.FromConversation(sess); record.Id = sess.Id.IfNullOrEmptyAs(Guid.NewGuid().ToString()); record.UserId = sess.UserId.IfNullOrEmptyAs(_user.Id); record.Title = "New Conversation"; db.Transaction(delegate { db.Add(record); }); _storage.InitStorage(sess.AgentId, record.Id); return record.ToConversation(); } public async Task SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func onMessageReceived) { _storage.Append(agentId, conversationId, lastDalog); var wholeDialogs = GetDialogHistory(agentId, conversationId); var response = await SendMessage(agentId, conversationId, wholeDialogs, async msg => { var content = msg.Content.Replace("\r", " ").Replace("\n", " "); if (msg.Role == "function") { content += $"[{msg.Function}] {content}"; _storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content)); } else { await onMessageReceived(msg); _storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content)); } }); return response; } public async Task SendMessage(string agentId, string conversationId, List wholeDialogs, Func onMessageReceived) { var agent = await _services.GetRequiredService().GetAgent(agentId); var converation = await GetConversation(conversationId); // Get relevant domain knowledge if (_settings.EnableKnowledgeBase) { var knowledge = _services.GetRequiredService(); agent.Knowledges = await knowledge.GetKnowledges(new KnowledgeRetrievalModel { AgentId = agentId, Question = string.Join("\n", wholeDialogs.Select(x => x.Content)) }); } var chatCompletion = GetChatCompletion(); var hooks = _services.GetServices().ToList(); // Before chat completion hook foreach (var hook in hooks) { await hook.SetAgent(agent) .SetConversation(converation) .SetDialogs(wholeDialogs) .SetChatCompletion(chatCompletion) .BeforeCompletion(); } var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg => { if (msg.Role == "function") { // Execute functions foreach (var hook in hooks) { var executionResult = await hook.OnFunctionExecution(msg.Function, msg.Content); msg.ExecutionResult = JsonSerializer.Serialize(executionResult); } } else { // After chat completion hook foreach (var hook in hooks) { await hook.AfterCompletion(msg); } await onMessageReceived(msg); } }); return result; } public IChatCompletion GetChatCompletion() { var completions = _services.GetServices(); return completions.FirstOrDefault(x => x.GetType().FullName.EndsWith(_settings.ChatCompletion)); } public Task CleanHistory(string agentId) { throw new NotImplementedException(); } public List GetDialogHistory(string agentId, string conversationId) { return _storage.GetDialogs(agentId, conversationId); } }