From 4cc74e596a8da83a31ef1d99daf05e4c2affd607 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Sun, 3 Sep 2023 17:43:50 -0500 Subject: [PATCH] add conversation collection --- .../Conversations/Models/Conversation.cs | 1 + .../Conversations/Models/ConversationState.cs | 14 ++ .../Repositories/IBotSharpRepository.cs | 11 ++ .../Repositories/Models/KeyValueModel.cs | 19 ++ .../Records/ConversationRecord.cs | 12 ++ .../Agents/Services/AgentService.GetAgents.cs | 6 - .../Services/ConversationService.cs | 46 ++--- .../Services/ConversationStateService.cs | 64 ++---- .../Services/ConversationStorage.cs | 59 +----- .../Repository/BotSharpDbContext.cs | 36 ++++ .../Repository/FileRepository.cs | 184 ++++++++++++++++++ .../BotSharp.Core/Routing/Router.cs | 9 - .../Users/Services/UserService.cs | 4 +- .../Collections/ConversationCollection.cs | 4 + .../Repository/MongoRepository.cs | 119 +++++++++++ 15 files changed, 435 insertions(+), 153 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Repositories/Models/KeyValueModel.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs index c101dfa2..c9c30edc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs @@ -6,6 +6,7 @@ public class Conversation public string AgentId { get; set; } = string.Empty; public string UserId { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; + public string Dialog { get; set; } public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationState.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationState.cs index ad36c4d3..98fcbf0c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationState.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/ConversationState.cs @@ -1,5 +1,19 @@ +using BotSharp.Abstraction.Repositories.Models; + namespace BotSharp.Abstraction.Conversations.Models; public class ConversationState : Dictionary { + public ConversationState() + { + + } + + public ConversationState(List pairs) + { + foreach (var pair in pairs) + { + this[pair.Key] = pair.Value; + } + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 46a0023c..e0b0d4a1 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Repositories.Records; using BotSharp.Abstraction.Routing.Models; using System.Linq; @@ -27,4 +28,14 @@ public interface IBotSharpRepository AgentRecord GetAgent(string agentId); List GetAgentResponses(string agentId); + + void CreateNewConversation(ConversationRecord conversation); + string GetConversationDialog(string conversationId); + void UpdateConversationDialog(string conversationId, string dialogs); + + List GetConversationState(string conversationId); + void UpdateConversationState(string conversationId, List state); + + ConversationRecord GetConversation(string conversationId); + List GetConversations(string userId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/KeyValueModel.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/KeyValueModel.cs new file mode 100644 index 00000000..412e618b --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Models/KeyValueModel.cs @@ -0,0 +1,19 @@ + +namespace BotSharp.Abstraction.Repositories.Models; + +public class KeyValueModel +{ + public string Key { get; set; } + public string Value { get; set; } + + public KeyValueModel() + { + + } + + public KeyValueModel(string key, string value) + { + Key = key; + Value = value; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/ConversationRecord.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/ConversationRecord.cs index 6a4dc338..ecbcc9cc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/ConversationRecord.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/ConversationRecord.cs @@ -1,4 +1,6 @@ using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Repositories.Models; +using System.Text.Json.Serialization; namespace BotSharp.Abstraction.Repositories.Records; @@ -15,6 +17,12 @@ public class ConversationRecord : RecordBase [MaxLength(64)] public string Title { get; set; } = string.Empty; + [JsonIgnore] + public string Dialog { get; set; } + + [JsonIgnore] + public List State { get; set; } + [Required] public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; @@ -29,6 +37,8 @@ public class ConversationRecord : RecordBase UserId = conv.UserId, Id = conv.Id, Title = conv.Title, + Dialog = conv.Dialog, + State = conv.State?.Select(x => new KeyValueModel(x.Key, x.Value))?.ToList() ?? new List(), CreatedTime = conv.CreatedTime, UpdatedTime = conv.UpdatedTime }; @@ -42,6 +52,8 @@ public class ConversationRecord : RecordBase Title = Title, UserId = UserId, AgentId = AgentId, + Dialog = Dialog, + State = new ConversationState(State), CreatedTime = CreatedTime, UpdatedTime = UpdatedTime }; diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index 73145edc..7894eabf 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -20,13 +20,7 @@ public partial class AgentService public async Task GetAgent(string id) { var db = _services.GetRequiredService(); - //var query = from agent in db.Agent - // where agent.Id == id - // select agent.ToAgent(); - - //var profile = query.FirstOrDefault(); var profile = db.GetAgent(id)?.ToAgent(); - //var dir = GetAgentDataDir(id); var instructionFile = profile?.Instruction; if (instructionFile != null) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 0870cd84..12135219 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -36,21 +36,26 @@ public partial class ConversationService : IConversationService 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(); + //var query = from sess in db.Conversation + // where sess.Id == id + // orderby sess.CreatedTime descending + // select sess.ToConversation(); + + var conversation = db.GetConversation(id); + return conversation?.ToConversation(); } 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(); + //var query = from sess in db.Conversation + // where sess.UserId == _user.Id + // orderby sess.CreatedTime descending + // select sess.ToConversation(); + + var user = db.User.FirstOrDefault(x => x.ExternalId == _user.Id); + var conversations = db.GetConversations(user?.Id); + return conversations.Select(x => x.ToConversation()).OrderByDescending(x => x.CreatedTime).ToList(); } public async Task NewConversation(Conversation sess) @@ -66,26 +71,7 @@ public partial class ConversationService : IConversationService record.UserId = sess.UserId.IfNullOrEmptyAs(foundUserId); record.Title = "New Conversation"; - //db.Transaction(delegate - //{ - // db.Add(record); - //}); - - var dir = Path.Combine(dbSettings.FileRepository, conversationSettings.DataDir, record.Id); - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - var path = Path.Combine(dir, "conversation.json"); - File.WriteAllText(path, JsonSerializer.Serialize(record, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - WriteIndented = true - })); - - _storage.InitStorage(record.Id); - + db.CreateNewConversation(record); return record.ToConversation(); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs index 81d23528..2f87bca5 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStateService.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Repositories.Records; using MongoDB.Bson; using System.IO; @@ -20,6 +21,7 @@ public class ConversationStateService : IConversationStateService, IDisposable private BotSharpDatabaseSettings _dbSettings; private string _conversationId; private string _file; + private List _savedStates; public ConversationStateService(ILogger logger, IServiceProvider services, @@ -65,18 +67,13 @@ public class ConversationStateService : IConversationStateService, IDisposable } _state = new ConversationState(); + _savedStates = _db.GetConversationState(_conversationId); - _file = GetStorageFile(_conversationId); - //_file = GetConversationState(_conversationId); - - if (_file != null) + if (_savedStates != null) { - var dict = File.ReadAllLines(_file); - //var dict = _file.SplitByNewLine(); - - foreach (var line in dict) + foreach (var data in _savedStates) { - _state[line.Split('=')[0]] = line.Split('=')[1]; + _state[data.Key] = data.Value; } } @@ -92,32 +89,20 @@ public class ConversationStateService : IConversationStateService, IDisposable public void Save() { - //var states = new StringBuilder(); - //var conversation = _db.Conversation.FirstOrDefault(x => x.Id == _conversationId); - - var states = new List(); + var states = new List(); foreach (var dic in _state) { - states.Add($"{dic.Key}={dic.Value}"); - //states.AppendLine($"{dic.Key}={dic.Value}"); + states.Add(new KeyValueModel(dic.Key, dic.Value)); } - File.WriteAllLines(_file, states); - _logger.LogInformation($"Saved state {_conversationId}"); - //if (conversation != null) - //{ - // conversation.State = states.ToString(); - // _db.Transaction(delegate - // { - // _db.Add(conversation); - // }); - //} + _db.UpdateConversationState(_conversationId, states); + _logger.LogInformation($"Saved state {_conversationId}"); } public void CleanState() { - File.Delete(_file); + //File.Delete(_file); } private string GetStorageFile(string conversationId) @@ -136,33 +121,6 @@ public class ConversationStateService : IConversationStateService, IDisposable return stateFile; } - //private string GetConversationState(string conversationId) - //{ - // var conversation = _db.Conversation.FirstOrDefault(x => x.Id == conversationId); - // if (conversation == null) - // { - // var user = _db.User.FirstOrDefault(x => x.ExternalId == _user.Id); - // var record = new ConversationRecord() - // { - // Id = ObjectId.GenerateNewId().ToString(), - // //AgentId = _agentSettings.RouterId, - // UserId = user?.Id ?? ObjectId.GenerateNewId().ToString(), - // Title = "New Conversation", - // Dialog = string.Empty, - // State = string.Empty - // }; - - // _db.Transaction(delegate - // { - // _db.Add(record); - // }); - - // conversation = _db.Conversation.FirstOrDefault(x => x.Id == record.Id); - // } - - // return conversation.State ?? string.Empty; - //} - public string GetState(string name) { if (!_state.ContainsKey(name)) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 303e9c7b..4041fa83 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -1,11 +1,6 @@ using BotSharp.Abstraction.Agents.Enums; -using BotSharp.Abstraction.Agents.Settings; -using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Repositories; -using BotSharp.Abstraction.Repositories.Records; -using MongoDB.Bson; using System.IO; -using Tensorflow; namespace BotSharp.Core.Conversations.Services; @@ -29,12 +24,9 @@ public class ConversationStorage : IConversationStorage public void Append(string conversationId, string agentId, RoleDialogModel dialog) { - //var dialogs = GetConversationDialogs(conversationId); - //var sb = new StringBuilder(dialogs); var db = _services.GetRequiredService(); - - var conversationFile = GetStorageFile(conversationId); - var sb = new StringBuilder(); + var dialogText = db.GetConversationDialog(conversationId); + var sb = new StringBuilder(dialogText); if (dialog.Role == AgentRole.Function) { @@ -63,24 +55,15 @@ public class ConversationStorage : IConversationStorage } var updatedDialogs = sb.ToString(); - File.AppendAllText(conversationFile, updatedDialogs); - - //var conversation = db.Conversation.FirstOrDefault(x => x.Id == conversationId); - //conversation.AgentId = agentId; - //conversation.Dialog = updatedDialogs; - //db.Transaction(delegate - //{ - // db.Add(conversation); - //}); + //File.AppendAllText(conversationFile, updatedDialogs); + db.UpdateConversationDialog(conversationId, updatedDialogs); } public List GetDialogs(string conversationId) { - var conversationFile = GetStorageFile(conversationId); - var dialogs = File.ReadAllLines(conversationFile); - - //var conversationFile = GetConversationDialogs(conversationId); - //var dialogs = conversationFile.SplitByNewLine(); + var db = _services.GetRequiredService(); + var dialogText = db.GetConversationDialog(conversationId); + var dialogs = dialogText.SplitByNewLine(); var results = new List(); for (int i = 0; i < dialogs.Length; i += 2) @@ -113,8 +96,6 @@ public class ConversationStorage : IConversationStorage { File.WriteAllLines(file, new string[0]); } - - //GetConversationDialogs(conversationId); } private string GetStorageFile(string conversationId) @@ -126,30 +107,4 @@ public class ConversationStorage : IConversationStorage } return Path.Combine(dir, "dialogs.txt"); } - - //private string GetConversationDialogs(string conversationId) - //{ - // var db = _services.GetRequiredService(); - // var conversation = db.Conversation.FirstOrDefault(x => x.Id == conversationId); - // if (conversation == null) - // { - // var user = db.User.FirstOrDefault(x => x.ExternalId == _user.Id); - // var record = new ConversationRecord() - // { - // Id = ObjectId.GenerateNewId().ToString(), - // //AgentId = _agentSettings.RouterId, - // UserId = user?.Id ?? ObjectId.GenerateNewId().ToString(), - // Title = "New Conversation" - // }; - - // db.Transaction(delegate - // { - // db.Add(record); - // }); - - // conversation = db.Conversation.FirstOrDefault(x => x.Id == record.Id); - // } - - // return conversation.Dialog ?? string.Empty; - //} } diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 5ba6f80d..453f43a1 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Repositories.Records; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -106,4 +107,39 @@ public class BotSharpDbContext : Database, IBotSharpRepository { throw new NotImplementedException(); } + + public void CreateNewConversation(ConversationRecord conversation) + { + throw new NotImplementedException(); + } + + public string GetConversationDialog(string conversationId) + { + throw new NotImplementedException(); + } + + public void UpdateConversationDialog(string conversationId, string dialogs) + { + throw new NotImplementedException(); + } + + public List GetConversationState(string conversationId) + { + throw new NotImplementedException(); + } + + public void UpdateConversationState(string conversationId, List state) + { + throw new NotImplementedException(); + } + + public ConversationRecord GetConversation(string conversationId) + { + throw new NotImplementedException(); + } + + public List GetConversations(string userId) + { + throw new NotImplementedException(); + } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index be59916b..e85d932f 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -1,7 +1,14 @@ +using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Conversations.Settings; using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Repositories.Records; +using MongoDB.Driver.Core.Operations; using System.IO; +using static Tensorflow.TensorShapeProto.Types; +using Tensorflow; +using FunctionDef = BotSharp.Abstraction.Functions.Models.FunctionDef; namespace BotSharp.Core.Repository; @@ -401,4 +408,181 @@ public class FileRepository : IBotSharpRepository var functions = functionDefs.Select(x => JsonSerializer.Serialize(x, _options)).ToList(); return functions; } + + public void CreateNewConversation(ConversationRecord conversation) + { + var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir, conversation.Id); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + var convDir = Path.Combine(dir, "conversation.json"); + if (!File.Exists(convDir)) + { + File.WriteAllText(convDir, JsonSerializer.Serialize(conversation, _options)); + } + + var dialogDir = Path.Combine(dir, "dialogs.txt"); + if (!File.Exists(dialogDir)) + { + File.WriteAllText(dialogDir, string.Empty); + } + + var stateDir = Path.Combine(dir, "state.dict"); + if (!File.Exists(stateDir)) + { + File.WriteAllText(stateDir, string.Empty); + } + } + + public string GetConversationDialog(string conversationId) + { + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var dialogDir = Path.Combine(convDir, "dialogs.txt"); + if (File.Exists(dialogDir)) + { + return File.ReadAllText(dialogDir); + } + } + + return string.Empty; + } + + public void UpdateConversationDialog(string conversationId, string dialogs) + { + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var dialogDir = Path.Combine(convDir, "dialogs.txt"); + if (File.Exists(dialogDir)) + { + File.WriteAllText(dialogDir, dialogs); + } + } + + return; + } + + public List GetConversationState(string conversationId) + { + var curStates = new List(); + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var stateDir = Path.Combine(convDir, "state.dict"); + if (File.Exists(stateDir)) + { + var dict = File.ReadAllLines(stateDir); + foreach (var line in dict) + { + var data = line.Split('='); + curStates.Add(new KeyValueModel(data[0], data[1])); + } + } + } + + return curStates; + } + + private string? FindConversationDirectory(string conversationId) + { + var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir); + + foreach (var d in Directory.GetDirectories(dir)) + { + var path = Path.Combine(d, "conversation.json"); + if (!File.Exists(path)) continue; + + var json = File.ReadAllText(path); + var conv = JsonSerializer.Deserialize(json, _options); + if (conv != null && conv.Id == conversationId) + { + return d; + } + } + + return null; + } + + public void UpdateConversationState(string conversationId, List state) + { + var localStates = new List(); + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var stateDir = Path.Combine(convDir, "state.dict"); + if (File.Exists(stateDir)) + { + foreach (var data in state) + { + localStates.Add($"{data.Key}={data.Value}"); + } + File.WriteAllLines(stateDir, localStates); + } + } + } + + public ConversationRecord GetConversation(string conversationId) + { + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var convFile = Path.Combine(convDir, "conversation.json"); + var record = JsonSerializer.Deserialize(convFile); + + var dialogFile = Path.Combine(convDir, "dialogs.txt"); + if (record != null && File.Exists(dialogFile)) + { + record.Dialog = File.ReadAllText(dialogFile); + } + + var stateFile = Path.Combine(convDir, "state.dict"); + if (record != null && File.Exists(stateFile)) + { + var states = File.ReadLines(stateFile); + record.State = states.Select(x => new KeyValueModel(x.Split('=')[0], x.Split('=')[1])).ToList(); + } + + return record; + } + + return null; + } + + public List GetConversations(string userId) + { + var records = new List(); + var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir); + + foreach (var d in Directory.GetDirectories(dir)) + { + var path = Path.Combine(d, "conversation.json"); + if (!File.Exists(path)) continue; + + var json = File.ReadAllText(path); + var record = JsonSerializer.Deserialize(json, _options); + if (record != null && record.UserId == userId) + { + var dialogFile = Path.Combine(d, "dialogs.txt"); + if (File.Exists(dialogFile)) + { + record.Dialog = File.ReadAllText(dialogFile); + } + + var stateFile = Path.Combine(d, "state.dict"); + if (File.Exists(stateFile)) + { + var states = File.ReadLines(stateFile); + record.State = states.Select(x => new KeyValueModel(x.Split('=')[0], x.Split('=')[1])).ToList(); + } + + records.Add(record); + } + } + + return records; + } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Router.cs b/src/Infrastructure/BotSharp.Core/Routing/Router.cs index 181f0619..296a3b02 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Router.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Router.cs @@ -31,24 +31,15 @@ public class Router : IAgentRouting public RoutingItem[] GetRoutingRecords() { - var agentSettings = _services.GetRequiredService(); - var dbSettings = _services.GetRequiredService(); var db = _services.GetRequiredService(); - //var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, "route.json"); - //var records = JsonSerializer.Deserialize(File.ReadAllText(filePath)); var records = db.RoutingItem.Select(x => x.ToRoutingItem()).ToArray(); - - // check if routing profile is specified - //filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, "routing-profile.json"); - var profiles = db.RoutingProfile.ToList(); if (profiles != null && profiles.Any()) { var state = _services.GetRequiredService(); var name = state.GetState("channel"); - //var profiles = JsonSerializer.Deserialize(File.ReadAllText(filePath)); var specifiedProfile = profiles.FirstOrDefault(x => x.Name == name); if (specifiedProfile != null) { diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index dee8bf33..d81279ca 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -96,11 +96,9 @@ public class UserService : IUserService public async Task GetMyProfile() { - var userId = _user.Id; - var db = _services.GetRequiredService(); var user = (from u in db.User - where u.Id == userId + where u.ExternalId == _user.Id select new User { Id = u.Id, diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs index 283551ef..c7aaa58e 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Repositories.Models; + namespace BotSharp.Plugin.MongoStorage.Collections; public class ConversationCollection : MongoBase @@ -5,6 +7,8 @@ public class ConversationCollection : MongoBase public Guid AgentId { get; set; } public Guid UserId { get; set; } public string Title { get; set; } + public string Dialog { get; set; } + public List State { get; set; } public DateTime CreatedTime { get; set; } public DateTime UpdatedTime { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 9b78d71a..87d1611b 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -1,3 +1,6 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Repositories.Models; using BotSharp.Plugin.MongoStorage.Collections; namespace BotSharp.Plugin.MongoStorage.Repository; @@ -210,6 +213,8 @@ public class MongoRepository : IBotSharpRepository AgentId = Guid.Parse(x.AgentId), UserId = Guid.Parse(x.UserId), Title = x.Title, + Dialog = x.Dialog, + State = x.State, CreatedTime = x.CreatedTime, UpdatedTime = x.UpdatedTime }).ToList(); @@ -221,6 +226,8 @@ public class MongoRepository : IBotSharpRepository .Set(x => x.AgentId, conversation.AgentId) .Set(x => x.UserId, conversation.UserId) .Set(x => x.Title, conversation.Title) + .Set(x => x.Dialog, conversation.Dialog) + .Set(x => x.State, conversation.State) .Set(x => x.CreatedTime, conversation.CreatedTime) .Set(x => x.UpdatedTime, conversation.UpdatedTime); _dc.Conversations.UpdateOne(filter, update, _options); @@ -444,4 +451,116 @@ public class MongoRepository : IBotSharpRepository var foundAgent = Agent.FirstOrDefault(x => x.Id == agentId); return foundAgent; } + + public void CreateNewConversation(ConversationRecord conversation) + { + if (conversation == null) return; + + var collection = new ConversationCollection + { + Id = Guid.Parse(conversation.Id), + AgentId = Guid.Parse(conversation.AgentId), + UserId = Guid.Parse(conversation.UserId), + Title = conversation.Title, + Dialog = string.Empty, + State = new List(), + CreatedTime = DateTime.UtcNow, + UpdatedTime = DateTime.UtcNow, + }; + + _dc.Conversations.InsertOne(collection); + } + + public string GetConversationDialog(string conversationId) + { + if (string.IsNullOrEmpty(conversationId)) return string.Empty; + + var filterById = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault(); + if (foundConversation == null) return string.Empty; + + return foundConversation.Dialog; + } + + public void UpdateConversationDialog(string conversationId, string dialogs) + { + if (string.IsNullOrEmpty(conversationId)) return; + + var filterById = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault(); + if (foundConversation == null) return; + + var update = Builders.Update + .Set(x => x.Dialog, dialogs) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Conversations.UpdateOne(filterById, update); + } + + public List GetConversationState(string conversationId) + { + var states = new List(); + if (string.IsNullOrEmpty(conversationId)) return states; + + var filterById = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault(); + if (foundConversation == null) return states; + + var savedStates = foundConversation.State ?? new List(); + return savedStates; + } + + public void UpdateConversationState(string conversationId, List state) + { + if (string.IsNullOrEmpty(conversationId)) return; + + var filterById = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault(); + if (foundConversation == null) return; + + var update = Builders.Update + .Set(x => x.State, state) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Conversations.UpdateOne(filterById, update); + } + + public ConversationRecord GetConversation(string conversationId) + { + if (string.IsNullOrEmpty(conversationId)) return null; + + var filterById = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var found = _dc.Conversations.Find(filterById).FirstOrDefault(); + + return found != null ? new ConversationRecord + { + Id = found.Id.ToString(), + AgentId = found.AgentId.ToString(), + UserId = found.UserId.ToString(), + Title = found.Title, + Dialog = found.Dialog, + State = found.State, + CreatedTime = found.CreatedTime, + UpdatedTime = found.UpdatedTime + }: null; + } + + public List GetConversations(string userId) + { + if (string.IsNullOrEmpty(userId)) return new List(); + + var filterByUserId = Builders.Filter.Eq(x => x.UserId, Guid.Parse(userId)); + var conversations = _dc.Conversations.Find(filterByUserId).ToList(); + return conversations.Select(x => new ConversationRecord + { + Id = x.Id.ToString(), + AgentId = x.AgentId.ToString(), + UserId = x.UserId.ToString(), + Title = x.Title, + Dialog = x.Dialog, + State = x.State, + CreatedTime = x.CreatedTime, + UpdatedTime = x.UpdatedTime + }).ToList(); + } }