From e18845e4aeebcc803803212327df81b5bb72c8bd Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Thu, 25 Apr 2024 15:43:40 +0800 Subject: [PATCH 01/46] hdong:hard code page size to 10 for Qtoss project currently. --- .../BotSharp.Abstraction/Utilities/Pagination.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs index d11752f6..df0c247b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs @@ -3,7 +3,7 @@ namespace BotSharp.Abstraction.Utilities; public class Pagination { private int _page; - private int _size; + private int _size => 10; public int Page { @@ -20,10 +20,10 @@ public class Pagination return _size; } - set - { - _size = value; - } + //set + //{ + // _size = value; + //} } public int Offset From 8e2a97e39ffdc981475b02b1bc98a3c2eb2ab69a Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 11 May 2024 22:22:14 -0500 Subject: [PATCH 02/46] Add UserLanguage to IUserIdentity --- .../BotSharp.Abstraction/Users/IUserIdentity.cs | 1 + .../BotSharp.Core/Users/Services/UserIdentity.cs | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserIdentity.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserIdentity.cs index a0998117..4fecb48c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserIdentity.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserIdentity.cs @@ -8,4 +8,5 @@ public interface IUserIdentity string FirstName { get; } string LastName { get; } string FullName { get; } + string? UserLanguage { get; } } diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs index b8acdeea..a8eaac5e 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs @@ -56,4 +56,14 @@ public class UserIdentity : IUserIdentity return $"{FirstName} {LastName}".Trim(); } } + + [JsonPropertyName("user_language")] + public string? UserLanguage + { + get + { + _contextAccessor.HttpContext.Request.Headers.TryGetValue("User-Language", out var languages); + return languages.FirstOrDefault(); + } + } } From 66e233a11c85b6544d63216d03d4351ff150c9e2 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 15 May 2024 15:54:08 -0500 Subject: [PATCH 03/46] add user role filter --- .../FileRepository/FileRepository.User.cs | 2 + .../Controllers/AgentController.cs | 18 +++++++- .../Controllers/ConversationController.cs | 43 +++++++++++++------ .../ViewModels/Agents/AgentViewModel.cs | 2 + 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs index bc992a08..2d299f6d 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Users.Enums; using BotSharp.Abstraction.Users.Models; using System.IO; @@ -24,6 +25,7 @@ public partial class FileRepository { var userId = Guid.NewGuid().ToString(); user.Id = userId; + user.Role = UserRole.Admin; var dir = Path.Combine(_dbSettings.FileRepository, "users", userId); if (!Directory.Exists(dir)) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index bb67de2c..b10b60e8 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -1,4 +1,6 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Users.Enums; namespace BotSharp.OpenAPI.Controllers; @@ -7,11 +9,13 @@ namespace BotSharp.OpenAPI.Controllers; public class AgentController : ControllerBase { private readonly IAgentService _agentService; + private readonly IUserIdentity _user; private readonly IServiceProvider _services; - public AgentController(IAgentService agentService, IServiceProvider services) + public AgentController(IAgentService agentService, IUserIdentity user, IServiceProvider services) { _agentService = agentService; + _user = user; _services = services; } @@ -45,6 +49,18 @@ public class AgentController : ControllerBase rule.RedirectToAgentName = found.Name; } + + var editable = false; + var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + if (user != null && user.Role != UserRole.Admin) + { + var db = _services.GetRequiredService(); + var userAgents = db.GetAgentsByUser(user.Id); + editable = userAgents?.Select(x => x.Id)?.Contains(targetAgent.Id) ?? false; + } + + targetAgent.Editable = editable || user?.Role == UserRole.Admin; return targetAgent; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 34095acf..cbcc9028 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.Routing; using Newtonsoft.Json.Serialization; using Newtonsoft.Json; +using BotSharp.Abstraction.Users.Enums; namespace BotSharp.OpenAPI.Controllers; @@ -38,10 +39,16 @@ public class ConversationController : ControllerBase [HttpPost("/conversations")] public async Task> GetConversations([FromBody] ConversationFilter filter) { - var service = _services.GetRequiredService(); - var conversations = await service.GetConversations(filter); - + var convService = _services.GetRequiredService(); var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + if (user == null) + { + return new PagedItems(); + } + + filter.UserId = user.Role != UserRole.Admin ? user.Id : null; + var conversations = await convService.GetConversations(filter); var agentService = _services.GetRequiredService(); var list = conversations.Items .Select(x => ConversationViewModel.FromSession(x)) @@ -49,9 +56,8 @@ public class ConversationController : ControllerBase foreach (var item in list) { - var user = await userService.GetUser(item.User.Id); + user = await userService.GetUser(item.User.Id); item.User = UserViewModel.FromUser(user); - var agent = await agentService.GetAgent(item.AgentId); item.AgentName = agent?.Name; } @@ -116,21 +122,30 @@ public class ConversationController : ControllerBase } [HttpGet("/conversation/{conversationId}")] - public async Task GetConversation([FromRoute] string conversationId) + public async Task GetConversation([FromRoute] string conversationId) { var service = _services.GetRequiredService(); - var conversations = await service.GetConversations(new ConversationFilter - { - Id = conversationId - }); - var userService = _services.GetRequiredService(); - var result = ConversationViewModel.FromSession(conversations.Items.First()); + var user = await userService.GetUser(_user.Id); + if (user == null) + { + return null; + } + var filter = new ConversationFilter + { + Id = conversationId, + UserId = user.Role != UserRole.Admin ? user.Id : null + }; + var conversations = await service.GetConversations(filter); + if (conversations.Items.IsNullOrEmpty()) + { + return null; + } + + var result = ConversationViewModel.FromSession(conversations.Items.First()); var state = _services.GetRequiredService(); result.States = state.Load(conversationId, isReadOnly: true); - - var user = await userService.GetUser(result.User.Id); result.User = UserViewModel.FromUser(user); return result; diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs index 536f5b5d..9d87a3e2 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs @@ -42,6 +42,8 @@ public class AgentViewModel public PluginDef Plugin { get; set; } + public bool Editable { get; set; } + [JsonPropertyName("created_datetime")] public DateTime CreatedDateTime { get; set; } From 394d6071638fa1311711d0b35b97efeb455305a5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 15 May 2024 17:30:45 -0500 Subject: [PATCH 04/46] add user role limit --- .../Agents/IAgentService.cs | 2 ++ .../Services/AgentService.UpdateAgent.cs | 5 +++ .../Agents/Services/AgentService.cs | 6 ++++ .../FileRepository/FileRepository.User.cs | 1 - .../Users/Services/UserService.cs | 1 - .../Controllers/AgentController.cs | 9 +++-- .../Controllers/ConversationController.cs | 4 +-- .../Controllers/PluginController.cs | 33 +++++++++++++------ 8 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs index db4db62a..b435a4d1 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentService.cs @@ -48,5 +48,7 @@ public interface IAgentService string GetDataDir(); string GetAgentDataDir(string agentId); + List GetAgentsByUser(string userId); + PluginDef GetPlugin(string agentId); } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs index 154d7398..af6cb65e 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Repositories.Enums; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Users.Enums; using System.IO; namespace BotSharp.Core.Agents.Services; @@ -8,6 +9,10 @@ public partial class AgentService { public async Task UpdateAgent(Agent agent, AgentField updateField) { + var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + if (user?.Role != UserRole.Admin) return; + if (agent == null || string.IsNullOrEmpty(agent.Id)) return; var record = _db.GetAgent(agent.Id); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs index bd009db0..da1b8cf1 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs @@ -47,4 +47,10 @@ public partial class AgentService : IAgentService } return dir; } + + public List GetAgentsByUser(string userId) + { + var agents = _db.GetAgentsByUser(userId); + return agents; + } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs index 2d299f6d..8f1103e6 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs @@ -25,7 +25,6 @@ public partial class FileRepository { var userId = Guid.NewGuid().ToString(); user.Id = userId; - user.Role = UserRole.Admin; var dir = Path.Combine(_dbSettings.FileRepository, "users", userId); if (!Directory.Exists(dir)) { diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 6e856b9f..322b300d 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -1,4 +1,3 @@ -using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Users.Models; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index b10b60e8..d867e782 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -50,17 +50,16 @@ public class AgentController : ControllerBase rule.RedirectToAgentName = found.Name; } - var editable = false; + var editable = true; var userService = _services.GetRequiredService(); var user = await userService.GetUser(_user.Id); - if (user != null && user.Role != UserRole.Admin) + if (user?.Role != UserRole.Admin) { - var db = _services.GetRequiredService(); - var userAgents = db.GetAgentsByUser(user.Id); + var userAgents = _agentService.GetAgentsByUser(user?.Id); editable = userAgents?.Select(x => x.Id)?.Contains(targetAgent.Id) ?? false; } - targetAgent.Editable = editable || user?.Role == UserRole.Admin; + targetAgent.Editable = editable; return targetAgent; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index cbcc9028..f62680d2 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -50,9 +50,7 @@ public class ConversationController : ControllerBase filter.UserId = user.Role != UserRole.Admin ? user.Id : null; var conversations = await convService.GetConversations(filter); var agentService = _services.GetRequiredService(); - var list = conversations.Items - .Select(x => ConversationViewModel.FromSession(x)) - .ToList(); + var list = conversations.Items.Select(x => ConversationViewModel.FromSession(x)).ToList(); foreach (var item in list) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs index 2c231e16..dc2c2740 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Plugins.Models; +using BotSharp.Abstraction.Users.Enums; using BotSharp.Core.Plugins; namespace BotSharp.OpenAPI.Controllers; @@ -8,38 +9,50 @@ namespace BotSharp.OpenAPI.Controllers; public class PluginController : ControllerBase { private readonly IServiceProvider _services; + private readonly IUserIdentity _user; private readonly PluginSettings _settings; - public PluginController(IServiceProvider services, PluginSettings settings) + public PluginController(IServiceProvider services, IUserIdentity user, PluginSettings settings) { _services = services; + _user = user; _settings = settings; } [HttpGet("/plugins")] - public PagedItems GetPlugins([FromQuery] PluginFilter filter) + public async Task> GetPlugins([FromQuery] PluginFilter filter) { + var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + if (user?.Role != UserRole.Admin) + { + return new PagedItems(); + } + var loader = _services.GetRequiredService(); return loader.GetPagedPlugins(_services, filter); } [HttpGet("/plugin/menu")] - public List GetPluginMenu() + public async Task> GetPluginMenu() { var menu = new List { new PluginMenuDef("Apps", weight: 5) { IsHeader = true, - }, - new PluginMenuDef("System", weight: 30) - { - IsHeader = true - }, - new PluginMenuDef("Plugins", link: "page/plugin", icon: "bx bx-plug", weight: 31), - new PluginMenuDef("Settings", link: "page/setting", icon: "bx bx-cog", weight: 32), + } }; + var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + if (user?.Role == UserRole.Admin) + { + menu.Add(new PluginMenuDef("System", weight: 30) { IsHeader = true }); + menu.Add(new PluginMenuDef("Plugins", link: "page/plugin", icon: "bx bx-plug", weight: 31)); + menu.Add(new PluginMenuDef("Settings", link: "page/setting", icon: "bx bx-cog", weight: 32)); + } + var loader = _services.GetRequiredService(); foreach (var plugin in loader.GetPlugins(_services)) { From ca5407f97c777947dd2f27332934ec4a78f9c644 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 15 May 2024 17:53:39 -0500 Subject: [PATCH 05/46] add user role in menu --- .../Plugins/Models/PluginMenuDef.cs | 3 +++ .../BotSharp.Core/Agents/AgentPlugin.cs | 2 +- .../BotSharp.Core/Plugins/PluginLoader.cs | 16 ++++++++++++ .../BotSharp.Core/Tasks/TaskPlugin.cs | 6 ++++- .../Controllers/PluginController.cs | 26 ++++++++++++------- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Plugins/Models/PluginMenuDef.cs b/src/Infrastructure/BotSharp.Abstraction/Plugins/Models/PluginMenuDef.cs index bd5a1d88..5f8a59b9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Plugins/Models/PluginMenuDef.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Plugins/Models/PluginMenuDef.cs @@ -19,6 +19,9 @@ public class PluginMenuDef [JsonIgnore] public int Weight { get; set; } + [JsonIgnore] + public List? Roles { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public List? SubMenu { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs index eb21fb31..4aef8ca4 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs @@ -43,7 +43,7 @@ public class AgentPlugin : IBotSharpPlugin { SubMenu = new List { - new PluginMenuDef("Routing", link: "page/agent/router"), // icon: "bx bx-map-pin" + new PluginMenuDef("Routing", link: "page/agent/router") { Roles = new List { "admin" } }, // icon: "bx bx-map-pin" new PluginMenuDef("Evaluating", link: "page/agent/evaluator"), // icon: "bx bx-task" new PluginMenuDef("Agents", link: "page/agent"), // icon: "bx bx-bot" } diff --git a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs index f6de19ac..05867cb0 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs @@ -269,4 +269,20 @@ public class PluginLoader } }); } + + public List FilterPluginsByRoles(List plugins, string userRole) + { + if (plugins.IsNullOrEmpty()) return plugins; + + var filtered = new List(); + foreach (var plugin in plugins) + { + if (plugin.Roles.IsNullOrEmpty() || plugin.Roles.Contains(userRole)) + { + plugin.SubMenu = FilterPluginsByRoles(plugin.SubMenu, userRole); + filtered.Add(plugin); + } + } + return filtered; + } } diff --git a/src/Infrastructure/BotSharp.Core/Tasks/TaskPlugin.cs b/src/Infrastructure/BotSharp.Core/Tasks/TaskPlugin.cs index ddf709ec..27c55ab5 100644 --- a/src/Infrastructure/BotSharp.Core/Tasks/TaskPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Tasks/TaskPlugin.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Tasks; +using BotSharp.Abstraction.Users.Enums; using BotSharp.Core.Tasks.Services; using Microsoft.Extensions.Configuration; @@ -19,7 +20,10 @@ public class TaskPlugin : IBotSharpPlugin public bool AttachMenu(List menu) { var section = menu.First(x => x.Label == "Apps"); - menu.Add(new PluginMenuDef("Task", link: "page/task", icon: "bx bx-task", weight: section.Weight + 8)); + menu.Add(new PluginMenuDef("Task", link: "page/task", icon: "bx bx-task", weight: section.Weight + 8) + { + Roles = new List { UserRole.Admin } + }); return true; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs index dc2c2740..da3de2c8 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs @@ -41,18 +41,22 @@ public class PluginController : ControllerBase new PluginMenuDef("Apps", weight: 5) { IsHeader = true, + }, + new PluginMenuDef("System", weight: 30) + { + IsHeader = true, + Roles = new List { UserRole.Admin } + }, + new PluginMenuDef("Plugins", link: "page/plugin", icon: "bx bx-plug", weight: 31) + { + Roles = new List { UserRole.Admin } + }, + new PluginMenuDef("Settings", link: "page/setting", icon: "bx bx-cog", weight: 32) + { + Roles = new List { UserRole.Admin } } }; - var userService = _services.GetRequiredService(); - var user = await userService.GetUser(_user.Id); - if (user?.Role == UserRole.Admin) - { - menu.Add(new PluginMenuDef("System", weight: 30) { IsHeader = true }); - menu.Add(new PluginMenuDef("Plugins", link: "page/plugin", icon: "bx bx-plug", weight: 31)); - menu.Add(new PluginMenuDef("Settings", link: "page/setting", icon: "bx bx-cog", weight: 32)); - } - var loader = _services.GetRequiredService(); foreach (var plugin in loader.GetPlugins(_services)) { @@ -62,6 +66,10 @@ public class PluginController : ControllerBase } plugin.Module.AttachMenu(menu); } + + var userService = _services.GetRequiredService(); + var user = await userService.GetUser(_user.Id); + menu = loader.FilterPluginsByRoles(menu, user?.Role); menu = menu.OrderBy(x => x.Weight).ToList(); return menu; } From 89c33bafc0e8628e4c02ba652dc6b393bda8af58 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 15 May 2024 18:07:11 -0500 Subject: [PATCH 06/46] check convsation user when delete --- .../Controllers/ConversationController.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index f62680d2..0946084c 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Routing; using Newtonsoft.Json.Serialization; using Newtonsoft.Json; using BotSharp.Abstraction.Users.Enums; +using BotSharp.Abstraction.Users.Models; namespace BotSharp.OpenAPI.Controllers; @@ -181,7 +182,22 @@ public class ConversationController : ControllerBase [HttpDelete("/conversation/{conversationId}")] public async Task DeleteConversation([FromRoute] string conversationId) { + var userService = _services.GetRequiredService(); var conversationService = _services.GetRequiredService(); + + var user = await userService.GetUser(_user.Id); + var filter = new ConversationFilter + { + Id = conversationId, + UserId = user.Role != UserRole.Admin ? user.Id : null + }; + var conversations = await conversationService.GetConversations(filter); + + if (conversations.Items.IsNullOrEmpty()) + { + return false; + } + var response = await conversationService.DeleteConversations(new List { conversationId }); return response; } From 04e90a3664d8064b339fac254373c47fa156c0b3 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 16 May 2024 10:41:59 -0500 Subject: [PATCH 07/46] rename function --- .../BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs | 4 ---- src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs | 4 ++-- .../BotSharp.OpenAPI/Controllers/PluginController.cs | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index ce6512af..d3754a94 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -1,8 +1,4 @@ -using BotSharp.Abstraction.Agents.Models; -using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Tasks.Models; -using BotSharp.Abstraction.Users.Models; using System.IO; using System.Text.RegularExpressions; diff --git a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs index 05867cb0..1b883657 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs @@ -270,7 +270,7 @@ public class PluginLoader }); } - public List FilterPluginsByRoles(List plugins, string userRole) + public List GetPluginMenuByRoles(List plugins, string userRole) { if (plugins.IsNullOrEmpty()) return plugins; @@ -279,7 +279,7 @@ public class PluginLoader { if (plugin.Roles.IsNullOrEmpty() || plugin.Roles.Contains(userRole)) { - plugin.SubMenu = FilterPluginsByRoles(plugin.SubMenu, userRole); + plugin.SubMenu = GetPluginMenuByRoles(plugin.SubMenu, userRole); filtered.Add(plugin); } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs index da3de2c8..342f39fb 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/PluginController.cs @@ -69,7 +69,7 @@ public class PluginController : ControllerBase var userService = _services.GetRequiredService(); var user = await userService.GetUser(_user.Id); - menu = loader.FilterPluginsByRoles(menu, user?.Role); + menu = loader.GetPluginMenuByRoles(menu, user?.Role); menu = menu.OrderBy(x => x.Weight).ToList(); return menu; } From 6625b3ec088fa204bf8b414206feea59422954b8 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 16 May 2024 12:58:37 -0500 Subject: [PATCH 08/46] minor change --- src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs index 4aef8ca4..83ce823c 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.MLTasks; using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Settings; +using BotSharp.Abstraction.Users.Enums; using Microsoft.Extensions.Configuration; namespace BotSharp.Core.Agents; @@ -43,8 +44,8 @@ public class AgentPlugin : IBotSharpPlugin { SubMenu = new List { - new PluginMenuDef("Routing", link: "page/agent/router") { Roles = new List { "admin" } }, // icon: "bx bx-map-pin" - new PluginMenuDef("Evaluating", link: "page/agent/evaluator"), // icon: "bx bx-task" + new PluginMenuDef("Routing", link: "page/agent/router") { Roles = new List { UserRole.Admin } }, // icon: "bx bx-map-pin" + new PluginMenuDef("Evaluating", link: "page/agent/evaluator") { Roles = new List { UserRole.Admin } }, // icon: "bx bx-task" new PluginMenuDef("Agents", link: "page/agent"), // icon: "bx bx-bot" } }); From 8eee1fd1643273e2c4c673367e55e4efc066e705 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Fri, 17 May 2024 18:45:18 -0500 Subject: [PATCH 09/46] Change SendHttpRequest args --- .../Browsing/IWebBrowser.cs | 2 +- .../Browsing/Models/ElementActionArgs.cs | 2 ++ .../Browsing/Models/HttpRequestParams.cs | 2 +- .../PlaywrightDriver/PlaywrightInstance.cs | 5 ++-- .../PlaywrightWebDriver.DoAction.cs | 5 ++++ .../PlaywrightWebDriver.HttpRequest.cs | 4 ++-- .../PlaywrightWebDriver.LocateElement.cs | 23 +++++++++++++++++-- .../SeleniumWebDriver.HttpRequest.cs | 4 ++-- .../Functions/HttpRequestFn.cs | 7 +++++- 9 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs index 80dd6925..fc907351 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs @@ -24,6 +24,6 @@ public interface IWebBrowser Task EvaluateScript(string contextId, string script); Task CloseBrowser(string contextId); Task CloseCurrentPage(string contextId); - Task SendHttpRequest(string contextId, HttpRequestParams actionParams); + Task SendHttpRequest(MessageInfo message, HttpRequestParams actionParams); Task GetAttributeValue(MessageInfo message, ElementLocatingArgs location); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementActionArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementActionArgs.cs index 8b644b31..0d44066a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementActionArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementActionArgs.cs @@ -10,6 +10,8 @@ public class ElementActionArgs public ElementPosition? Position { get; set; } + public string? PressKey { get; set; } + /// /// Required for deserialization /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/HttpRequestParams.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/HttpRequestParams.cs index 2b8cc052..e6d24a8e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/HttpRequestParams.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/HttpRequestParams.cs @@ -18,7 +18,7 @@ public class HttpRequestParams public HttpRequestParams(string url, HttpMethod method, string? payload = null) { - Method = HttpMethod.Get; + Method = method; Url = url; Payload = payload; } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs index a801400b..e7fd5908 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs @@ -40,11 +40,12 @@ public class PlaywrightInstance : IDisposable Channel = "chrome", IgnoreDefaultArgs = new[] { - "--disable-infobars" + "--enable-automation", }, Args = new[] { "--disable-infobars", + "--no-sandbox", // "--start-maximized" } }); @@ -104,6 +105,6 @@ public class PlaywrightInstance : IDisposable public void Dispose() { _contexts.Clear(); - _playwright.Dispose(); + _playwright?.Dispose(); } } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs index dd4600c9..91a99aa8 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs @@ -28,6 +28,11 @@ public partial class PlaywrightWebDriver else if (action.Action == BroswerActionEnum.InputText) { await locator.FillAsync(action.Content); + + if (action.PressKey != null) + { + await locator.PressAsync(action.PressKey); + } } } } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs index a5a59334..4a0177a0 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs @@ -4,7 +4,7 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; public partial class PlaywrightWebDriver { - public async Task SendHttpRequest(string contextId, HttpRequestParams args) + public async Task SendHttpRequest(MessageInfo message, HttpRequestParams args) { var result = new BrowserActionResult(); @@ -27,7 +27,7 @@ public partial class PlaywrightWebDriver try { - var response = await EvaluateScript(contextId, script); + var response = await EvaluateScript(message.ContextId, script); result.IsSuccess = true; result.Body = JsonSerializer.Serialize(response); } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs index 78fa00a3..13b0464c 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs @@ -1,3 +1,5 @@ +using System.Xml.Linq; + namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; public partial class PlaywrightWebDriver @@ -18,12 +20,12 @@ public partial class PlaywrightWebDriver // check if selector is specified if (location.Selector != null) { - locator = page.Locator(location.Selector); + locator = locator.Locator(location.Selector); count = await locator.CountAsync(); } // try attribute - if (count == 0 && !string.IsNullOrEmpty(location.AttributeName)) + if (!string.IsNullOrEmpty(location.AttributeName)) { locator = locator.Locator($"[{location.AttributeName}='{location.AttributeValue}']"); count = await locator.CountAsync(); @@ -65,12 +67,29 @@ public partial class PlaywrightWebDriver else if (count == 1) { result.Selector = locator.ToString().Split('@').Last(); + + // Make sure the element is visible + await locator.EvaluateAsync("element => element.style.height = ''"); + await locator.EvaluateAsync("element => element.style.width = ''"); + await locator.EvaluateAsync("element => element.style.opacity = ''"); + var text = await locator.InnerTextAsync(); result.Body = text; result.IsSuccess = true; } else if (count > 1) { + // Make sure the element is visible + foreach (var element in await locator.AllAsync()) + { + if (!await element.IsVisibleAsync()) + { + await element.EvaluateAsync("element => element.style.height = '10px'"); + await element.EvaluateAsync("element => element.style.width = '10px'"); + await element.EvaluateAsync("element => element.style.opacity = '1.0'"); + } + } + if (location.FailIfMultiple) { result.Message = $"Multiple elements are found by {locator}"; diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs index b88a5d96..c9940318 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.HttpRequest.cs @@ -4,7 +4,7 @@ namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver; public partial class SeleniumWebDriver { - public async Task SendHttpRequest(string contextId, HttpRequestParams args) + public async Task SendHttpRequest(MessageInfo message, HttpRequestParams args) { var result = new BrowserActionResult(); @@ -27,7 +27,7 @@ public partial class SeleniumWebDriver try { - var response = await EvaluateScript(contextId, script); + var response = await EvaluateScript(message.ContextId, script); result.IsSuccess = true; result.Body = JsonSerializer.Serialize(response); } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/HttpRequestFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/HttpRequestFn.cs index c16da29c..fff2c240 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/HttpRequestFn.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/HttpRequestFn.cs @@ -21,7 +21,12 @@ public class HttpRequestFn : IFunctionCallback var agentService = _services.GetRequiredService(); var agent = await agentService.LoadAgent(message.CurrentAgentId); - var result = await _browser.SendHttpRequest(convService.ConversationId, args); + var result = await _browser.SendHttpRequest(new MessageInfo + { + AgentId = agent.Id, + MessageId = message.MessageId, + ContextId = convService.ConversationId + }, args); message.Content = result.IsSuccess ? result.Body : From 018d889ad33429fb756a8b6b4bce3776eff46c36 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Tue, 21 May 2024 05:51:38 -0500 Subject: [PATCH 10/46] Add UserCreated hook. --- .../BotSharp.Abstraction/Users/IAuthenticationHook.cs | 1 + .../BotSharp.Core/Users/Services/UserService.cs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs index 33b8086f..0de10328 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IAuthenticationHook.cs @@ -8,4 +8,5 @@ public interface IAuthenticationHook Task Authenticate(string id, string password); void AddClaims(List claims); void BeforeSending(Token token); + Task UserCreated(User user); } diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 6e856b9f..d51b6f4a 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -1,4 +1,3 @@ -using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Users.Models; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; @@ -57,6 +56,12 @@ public class UserService : IUserService _logger.LogWarning($"Created new user account: {record.Id} {record.UserName}"); Utilities.ClearCache(); + var hooks = _services.GetServices(); + foreach (var hook in hooks) + { + await hook.UserCreated(record); + } + return record; } From 003de30538ea864e3738b89ee6a7c23441d95dd1 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 21 May 2024 11:20:03 -0500 Subject: [PATCH 11/46] resolve conflict --- .../BotSharp.OpenAPI/Controllers/ConversationController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 08e4c0a0..6831e74c 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Users.Enums; namespace BotSharp.OpenAPI.Controllers; From 6a0a400500951cfef9cae03bf88533ede37ba008 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Tue, 21 May 2024 12:02:06 -0500 Subject: [PATCH 12/46] Fix SSE response format. --- .../Translation/Models/TranslationOutput.cs | 2 +- .../Translation/TranslationService.cs | 2 +- .../Controllers/ConversationController.cs | 24 ++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationOutput.cs b/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationOutput.cs index 52ad54ec..b15bfef4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationOutput.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationOutput.cs @@ -9,5 +9,5 @@ public class TranslationOutput public string OutputLanguage { get; set; } = LanguageType.ENGLISH; [JsonPropertyName("texts")] - public string[] Texts { get; set; } = Array.Empty(); + public TranslationInput[] Texts { get; set; } = Array.Empty(); } diff --git a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs index 5c60e108..e5149751 100644 --- a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs +++ b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs @@ -79,7 +79,7 @@ public class TranslationService : ITranslationService for (var i = 0; i < texts.Count; i++) { - map[keys[i]] = translatedTexts[i]; + map[keys[i]] = translatedTexts[i].Text; } clonedData = Assign(clonedData, map); diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index a1d2ca3e..80374a6d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -257,7 +257,11 @@ public class ConversationController : ControllerBase conv.SetConversationId(conversationId, input.States); SetStates(conv, input); - var response = new ChatResponseModel(); + var response = new ChatResponseModel + { + ConversationId = conversationId, + MessageId = inputMsg.MessageId, + }; Response.StatusCode = 200; Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "text/event-stream"); @@ -266,6 +270,7 @@ public class ConversationController : ControllerBase await conv.SendMessage(agentId, inputMsg, replyMessage: input.Postback, + // responsed generated async msg => { response.Text = !string.IsNullOrEmpty(msg.SecondaryContent) ? msg.SecondaryContent : msg.Content; @@ -274,18 +279,21 @@ public class ConversationController : ControllerBase response.Instruction = msg.Instruction; response.Data = msg.Data; - await OnChunkReceived(Response, msg); + await OnChunkReceived(Response, response); }, + // executing async msg => { - var message = new RoleDialogModel(AgentRole.Function, msg.Content) + var indicator = new ChatResponseModel { - FunctionArgs = msg.FunctionArgs, - FunctionName = msg.FunctionName, - Indication = msg.Indication + ConversationId = conversationId, + MessageId = msg.MessageId, + Text = msg.Indication, + Function = "indicating", }; - await OnChunkReceived(Response, message); + await OnChunkReceived(Response, indicator); }, + // executed async msg => { @@ -299,7 +307,7 @@ public class ConversationController : ControllerBase // await OnEventCompleted(Response); } - private async Task OnChunkReceived(HttpResponse response, RoleDialogModel message) + private async Task OnChunkReceived(HttpResponse response, ChatResponseModel message) { var json = JsonSerializer.Serialize(message); From effd44eb7c7f6a620f7a50be71fbbd142223cfb8 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 21 May 2024 15:55:12 -0500 Subject: [PATCH 13/46] add agent delete --- .../Services/AgentService.CreateAgent.cs | 23 ++---------- .../Services/AgentService.DeleteAgent.cs | 13 ++++++- .../FileRepository/FileRepository.Agent.cs | 35 ++++++++++++++++++- .../Controllers/AgentController.cs | 11 ++++-- 4 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index d3754a94..ae429484 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -22,32 +22,13 @@ public partial class AgentService var dbSettings = _services.GetRequiredService(); var agentSettings = _services.GetRequiredService(); - var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir); - var foundAgent = FetchAgentFileByName(agent.Name, filePath); - - if (foundAgent != null) - { - agentRecord.SetId(foundAgent.Id) - .SetName(foundAgent.Name) - .SetDescription(foundAgent.Description) - .SetIsPublic(foundAgent.IsPublic) - .SetDisabled(foundAgent.Disabled) - .SetAgentType(foundAgent.Type) - .SetProfiles(foundAgent.Profiles) - .SetRoutingRules(foundAgent.RoutingRules) - .SetInstruction(foundAgent.Instruction) - .SetTemplates(foundAgent.Templates) - .SetFunctions(foundAgent.Functions) - .SetResponses(foundAgent.Responses) - .SetLlmConfig(foundAgent.LlmConfig); - } var user = _db.GetUserById(_user.Id); var userAgentRecord = new UserAgent { Id = Guid.NewGuid().ToString(), UserId = user.Id, - AgentId = foundAgent?.Id ?? agentRecord.Id, + AgentId = agentRecord.Id, Editable = false, CreatedTime = DateTime.UtcNow, UpdatedTime = DateTime.UtcNow @@ -61,7 +42,7 @@ public partial class AgentService Utilities.ClearCache(); - return agentRecord; + return await Task.FromResult(agentRecord); } private Agent FetchAgentFileByName(string agentName, string filePath) diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs index 23111fd2..1fe5c6e1 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.DeleteAgent.cs @@ -1,9 +1,20 @@ +using BotSharp.Abstraction.Users.Enums; + namespace BotSharp.Core.Agents.Services; public partial class AgentService { public async Task DeleteAgent(string id) { - throw new NotImplementedException(); + var user = _db.GetUserById(_user.Id); + var agent = _db.GetAgentsByUser(_user.Id).FirstOrDefault(x => x.Id.IsEqualTo(id)); + + if (user?.Role != UserRole.Admin && agent == null) + { + return false; + } + + var deleted = _db.DeleteAgent(id); + return await Task.FromResult(deleted); } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs index a46669a5..b7141a5b 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs @@ -436,7 +436,40 @@ namespace BotSharp.Core.Repository public bool DeleteAgent(string agentId) { - return false; + if (string.IsNullOrEmpty(agentId)) return false; + + try + { + var agentDir = GetAgentDataDir(agentId); + if (string.IsNullOrEmpty(agentDir)) return false; + + // Delete agent user relationships + var usersDir = Path.Combine(_dbSettings.FileRepository, "users"); + if (Directory.Exists(usersDir)) + { + foreach (var userDir in Directory.GetDirectories(usersDir)) + { + var userAgentFile = Directory.GetFiles(userDir).FirstOrDefault(x => Path.GetFileName(x) == USER_AGENT_FILE); + if (string.IsNullOrEmpty(userAgentFile)) continue; + + var text = File.ReadAllText(userAgentFile); + var userAgents = JsonSerializer.Deserialize>(text, _options); + if (userAgents.IsNullOrEmpty()) continue; + + userAgents = userAgents.Where(x => x.AgentId != agentId).ToList(); + File.WriteAllText(userAgentFile, JsonSerializer.Serialize(userAgents, _options)); + } + } + + // Delete agent folder + Directory.Delete(agentDir, true); + + return true; + } + catch + { + return false; + } } } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index d867e782..a7b5652d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -1,5 +1,4 @@ using BotSharp.Abstraction.Agents.Models; -using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Users.Enums; namespace BotSharp.OpenAPI.Controllers; @@ -27,7 +26,7 @@ public class AgentController : ControllerBase } [HttpGet("/agent/{id}")] - public async Task GetAgent([FromRoute] string id) + public async Task GetAgent([FromRoute] string id) { var agents = await GetAgents(new AgentFilter { @@ -35,6 +34,8 @@ public class AgentController : ControllerBase }); var targetAgent = agents.Items.FirstOrDefault(); + if (targetAgent == null) return null; + var redirectAgentIds = targetAgent.RoutingRules .Where(x => !string.IsNullOrEmpty(x.RedirectTo)) .Select(x => x.RedirectTo).ToList(); @@ -133,4 +134,10 @@ public class AgentController : ControllerBase model.Id = agentId; return await _agentService.PatchAgentTemplate(model); } + + [HttpDelete("/agent/{agentId}")] + public async Task DeleteAgent([FromRoute] string agentId) + { + return await _agentService.DeleteAgent(agentId); + } } \ No newline at end of file From 343f3b91abcea27648b6dc62b424733aa36e5d78 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Tue, 21 May 2024 22:07:26 -0500 Subject: [PATCH 14/46] Retry language translation. --- .../BotSharp.Core/Translation/TranslationService.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs index e5149751..44bb22a8 100644 --- a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs +++ b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs @@ -62,10 +62,18 @@ public class TranslationService : ITranslationService Id = i + 1, Text = text }).ToList(); - var translatedStringList = await InnerTranslate(texts, language, template); try { + var translatedStringList = await InnerTranslate(texts, language, template); + + int retry = 0; + while (translatedStringList.Texts.Length != texts.Count && retry < 3) + { + translatedStringList = await InnerTranslate(texts, language, template); + retry++; + } + // Override language if it's Unknown, it's used to output the corresponding language. var states = _services.GetRequiredService(); if (!states.ContainsState(StateConst.LANGUAGE)) From c93511065a7b50218b02b326dbb39633c9100b94 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Tue, 21 May 2024 23:33:31 -0500 Subject: [PATCH 15/46] refine file storage --- .../Files/IBotSharpFileService.cs | 7 +- .../Files/BotSharpFileService.cs | 105 ++++++++++++++---- .../Controllers/FileController.cs | 25 ++++- .../ViewModels/Users/UserViewModel.cs | 4 +- .../WebSocketsMiddleware.cs | 22 +++- 5 files changed, 133 insertions(+), 30 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs b/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs index 272abf0d..16197b9c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs @@ -5,8 +5,11 @@ public interface IBotSharpFileService string GetDirectory(string conversationId); IEnumerable GetChatImages(string conversationId, List conversations, int offset = 2); IEnumerable GetMessageFiles(string conversationId, IEnumerable messageIds, bool imageOnly = false); - string? GetMessageFile(string conversationId, string messageId, string fileName); - void SaveMessageFiles(string conversationId, string messageId, List files); + string GetMessageFile(string conversationId, string messageId, string fileName); + bool SaveMessageFiles(string conversationId, string messageId, List files); + + string GetUserAvatar(); + bool SaveUserAvatar(BotSharpFile file); /// /// Delete files under messages diff --git a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs index d7e961be..178790bc 100644 --- a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs +++ b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.StaticFiles; +using System; using System.IO; using System.Threading; @@ -8,21 +9,27 @@ public class BotSharpFileService : IBotSharpFileService { private readonly BotSharpDatabaseSettings _dbSettings; private readonly IServiceProvider _services; + private readonly IUserIdentity _user; private readonly ILogger _logger; private readonly string _baseDir; private readonly IEnumerable _allowedTypes = new List { "image/png", "image/jpeg" }; private const string CONVERSATION_FOLDER = "conversations"; private const string FILE_FOLDER = "files"; + private const string USERS_FOLDER = "users"; + private const string USER_AVATAR_FOLDER = "avatar"; + private const int MIN_OFFSET = 1; private const int MAX_OFFSET = 5; public BotSharpFileService( BotSharpDatabaseSettings dbSettings, + IUserIdentity user, ILogger logger, IServiceProvider services) { _dbSettings = dbSettings; + _user = user; _logger = logger; _services = services; _baseDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dbSettings.FileRepository); @@ -38,7 +45,7 @@ public class BotSharpFileService : IBotSharpFileService return dir; } - public IEnumerable GetChatImages(string conversationId, List conversations, int offset = 2) + public IEnumerable GetChatImages(string conversationId, List conversations, int offset = 1) { var files = new List(); if (string.IsNullOrEmpty(conversationId) || conversations.IsNullOrEmpty()) @@ -68,7 +75,7 @@ public class BotSharpFileService : IBotSharpFileService foreach (var messageId in messageIds) { var dir = GetConversationFileDirectory(conversationId, messageId); - if (string.IsNullOrEmpty(dir)) + if (!ExistDirectory(dir)) { continue; } @@ -101,24 +108,24 @@ public class BotSharpFileService : IBotSharpFileService return files; } - public string? GetMessageFile(string conversationId, string messageId, string fileName) + public string GetMessageFile(string conversationId, string messageId, string fileName) { var dir = GetConversationFileDirectory(conversationId, messageId); - if (string.IsNullOrEmpty(dir)) + if (!ExistDirectory(dir)) { - return null; + return string.Empty; } var found = Directory.GetFiles(dir).FirstOrDefault(f => Path.GetFileNameWithoutExtension(f).IsEqualTo(fileName)); return found; } - public void SaveMessageFiles(string conversationId, string messageId, List files) + public bool SaveMessageFiles(string conversationId, string messageId, List files) { - if (files.IsNullOrEmpty()) return; + if (files.IsNullOrEmpty()) return false; var dir = GetConversationFileDirectory(conversationId, messageId, createNewDir: true); - if (string.IsNullOrEmpty(dir)) return; + if (!ExistDirectory(dir)) return false; try { @@ -136,10 +143,53 @@ public class BotSharpFileService : IBotSharpFileService Thread.Sleep(100); File.WriteAllBytes(Path.Combine(dir, fileName), bytes); } + return true; } catch (Exception ex) { - _logger.LogError($"Error when saving conversation files: {ex.Message}"); + _logger.LogWarning($"Error when saving conversation files: {ex.Message}"); + return false; + } + } + + public string GetUserAvatar() + { + var db = _services.GetRequiredService(); + var user = db.GetUserById(_user.Id); + var dir = GetUserAvatarDir(user?.Id); + + if (!ExistDirectory(dir)) return string.Empty; + + var found = Directory.GetFiles(dir).FirstOrDefault() ?? string.Empty; + return found; + } + + public bool SaveUserAvatar(BotSharpFile file) + { + if (file == null || string.IsNullOrEmpty(file.FileData)) return false; + + try + { + var db = _services.GetRequiredService(); + var user = db.GetUserById(_user.Id); + var dir = GetUserAvatarDir(user?.Id); + + if (string.IsNullOrEmpty(dir)) return false; + + if (Directory.Exists(dir)) + { + Directory.Delete(dir, true); + } + + dir = GetUserAvatarDir(user?.Id, createNewDir: true); + var (_, bytes) = GetFileInfoFromData(file.FileData); + File.WriteAllBytes(Path.Combine(dir, file.FileName), bytes); + return true; + } + catch (Exception ex) + { + _logger.LogWarning($"Error when saving user avatar: {ex.Message}"); + return false; } } @@ -152,9 +202,9 @@ public class BotSharpFileService : IBotSharpFileService var prevDir = GetConversationFileDirectory(conversationId, targetMessageId); var newDir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, newMessageId); - if (Directory.Exists(prevDir)) + if (ExistDirectory(prevDir)) { - if (Directory.Exists(newDir)) + if (ExistDirectory(newDir)) { Directory.Delete(newDir, true); } @@ -182,7 +232,7 @@ public class BotSharpFileService : IBotSharpFileService foreach (var conversationId in conversationIds) { var convDir = FindConversationDirectory(conversationId); - if (string.IsNullOrEmpty(convDir)) continue; + if (!ExistDirectory(convDir)) continue; Directory.Delete(convDir, true); } @@ -215,16 +265,9 @@ public class BotSharpFileService : IBotSharpFileService } var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, messageId); - if (!Directory.Exists(dir)) + if (!Directory.Exists(dir) && createNewDir) { - if (createNewDir) - { - Directory.CreateDirectory(dir); - } - else - { - return string.Empty; - } + Directory.CreateDirectory(dir); } return dir; } @@ -234,8 +277,21 @@ public class BotSharpFileService : IBotSharpFileService if (string.IsNullOrEmpty(conversationId)) return null; var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId); - if (!Directory.Exists(dir)) return null; + return dir; + } + private string GetUserAvatarDir(string? userId, bool createNewDir = false) + { + if (string.IsNullOrEmpty(userId)) + { + return string.Empty; + } + + var dir = Path.Combine(_baseDir, USERS_FOLDER, userId, USER_AVATAR_FOLDER); + if (!Directory.Exists(dir) && createNewDir) + { + Directory.CreateDirectory(dir); + } return dir; } @@ -250,5 +306,10 @@ public class BotSharpFileService : IBotSharpFileService return contentType; } + + private bool ExistDirectory(string? dir) + { + return !string.IsNullOrEmpty(dir) && Directory.Exists(dir); + } #endregion } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs index cfae602c..0c7fa255 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs @@ -46,7 +46,7 @@ public class FileController : ControllerBase } [HttpGet("/conversation/{conversationId}/message/{messageId}/file/{fileName}")] - public async Task GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string fileName) + public IActionResult GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string fileName) { var fileService = _services.GetRequiredService(); var file = fileService.GetMessageFile(conversationId, messageId, fileName); @@ -54,7 +54,30 @@ public class FileController : ControllerBase { return NotFound(); } + return BuildFileResult(file); + } + [HttpPost("/user/avatar")] + public bool UploadUserAvatar([FromBody] BotSharpFile file) + { + var fileService = _services.GetRequiredService(); + return fileService.SaveUserAvatar(file); + } + + [HttpGet("/user/avatar")] + public IActionResult GetUserAvatar() + { + var fileService = _services.GetRequiredService(); + var file = fileService.GetUserAvatar(); + if (string.IsNullOrEmpty(file)) + { + return NotFound(); + } + return BuildFileResult(file); + } + + private FileContentResult BuildFileResult(string file) + { using Stream stream = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); var bytes = new byte[stream.Length]; stream.Read(bytes, 0, (int)stream.Length); diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs index eeb1a8a2..8d28cf03 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs @@ -19,6 +19,7 @@ public class UserViewModel public string Source { get; set; } [JsonPropertyName("external_id")] public string? ExternalId { get; set; } + public string Avatar { get; set; } = "/user/avatar"; [JsonPropertyName("create_date")] public DateTime CreateDate { get; set; } [JsonPropertyName("update_date")] @@ -47,7 +48,8 @@ public class UserViewModel Source = user.Source, ExternalId = user.ExternalId, CreateDate = user.CreatedTime, - UpdateDate = user.UpdatedTime + UpdateDate = user.UpdatedTime, + Avatar = "/user/avatar" }; } } diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/WebSocketsMiddleware.cs b/src/Plugins/BotSharp.Plugin.ChatHub/WebSocketsMiddleware.cs index e20f8602..79cb803a 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/WebSocketsMiddleware.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/WebSocketsMiddleware.cs @@ -14,13 +14,11 @@ public class WebSocketsMiddleware public async Task Invoke(HttpContext httpContext) { - var request = httpContext.Request;; - var messageFileRegex = new Regex(@"/conversation/[a-z0-9-]+/message/[a-z0-9-]+/file/[a-z0-9-]+", RegexOptions.IgnoreCase); + var request = httpContext.Request; // web sockets cannot pass headers so we must take the access token from query param and // add it to the header before authentication middleware runs - if ((request.Path.StartsWithSegments("/chatHub", StringComparison.OrdinalIgnoreCase) - || messageFileRegex.IsMatch(request.Path.Value ?? string.Empty)) && + if ((VerifyChatHubRequest(request) || VerifyGetRequest(request)) && request.Query.TryGetValue("access_token", out var accessToken)) { request.Headers["Authorization"] = $"Bearer {accessToken}"; @@ -28,4 +26,20 @@ public class WebSocketsMiddleware await _next(httpContext); } + + private bool VerifyChatHubRequest(HttpRequest request) + { + return request.Path.StartsWithSegments("/chatHub", StringComparison.OrdinalIgnoreCase); + } + + private bool VerifyGetRequest(HttpRequest request) + { + var regexes = new List + { + new Regex(@"/conversation/[a-z0-9-]+/message/[a-z0-9-]+/file/[a-z0-9-]+", RegexOptions.IgnoreCase), + new Regex(@"/user/avatar", RegexOptions.IgnoreCase) + }; + + return request.Method.IsEqualTo("GET") && regexes.Any(x => x.IsMatch(request.Path.Value ?? string.Empty)); + } } From adc6486345fe53bd20d8d40b565fe32d9140f1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E7=A3=8A?= Date: Wed, 22 May 2024 14:53:36 +0800 Subject: [PATCH 16/46] Update TranslationService.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hotfix json escaped question error: [ERR] [] '<' is not a hex digit following '\u' within a JSON string. The string should be correctly escaped. Path: $.texts[0].text | LineNumber: 0 | BytePositionInLine: 411. json: {"input_lang":"English", "output_count":3, "output_lang":"Spanish", "texts":[{"id":1,"text":"Aquí hay un resumen de los horarios que ha indicado que está disponible. Las fechas no están confirmadas. El técnico revisará y se pondrá en contacto para programar.\u003Cp\u003E\u003Cb\u003EJueves, 23 de mayo de 2024\u003C/b\u003E\u003C/br\u003ETodo el día (08:00 AM - 08:00 PM)\u003C/p\u003E\u003Cp\u003E\u003Viernes, 24 de mayo de 2024\u003C/b\u003E\u003C/br\u003EMañana (08:00 AM - 01:00 PM)\u003C/p\u003E\u003Cp\u003E\u003Lunes, 27 de mayo de 2024\u003C/b\u003E\u003C/br\u003ETarde (01:00 PM - 08:00 PM)\u003C/p\u003E"},{"id":2,"text":"Se ve bien"},{"id":3,"text":"Empezar de nuevo"}]} --- .../BotSharp.Core/Translation/TranslationService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs index 44bb22a8..7067eb7e 100644 --- a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs +++ b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs @@ -310,7 +310,8 @@ public class TranslationService : ITranslationService /// private async Task InnerTranslate(List texts, string language, string template) { - var jsonString = JsonSerializer.Serialize(texts); + var options = new JsonSerializerOptions() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + var jsonString = JsonSerializer.Serialize(texts, options); var translator = new Agent { Id = Guid.Empty.ToString(), From 6f8c840dcd273ded0c03d237efef2c0a4369602d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E7=A3=8A?= Date: Wed, 22 May 2024 15:08:13 +0800 Subject: [PATCH 17/46] Update translation_prompt.liquid optimize translation prompt 1.Enrich the translation examples. 2.Add necessary validation conditions for "output_count". --- .../templates/translation_prompt.liquid | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/translation_prompt.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/translation_prompt.liquid index 3d33375b..6b3a8677 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/translation_prompt.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/translation_prompt.liquid @@ -2,4 +2,5 @@ ===== Translate all the above sentences into {{ language }}. -Output the translated text in JSON {"input_lang":"original text language", "output_count": {{ text_list_size }}, "output_lang":"{{ language }}", "texts":[{"id": 1, "text":""}]}. +Output the translated text in JSON {"input_lang":"original text language", "output_count": {{ text_list_size }}, "output_lang":"{{ language }}", "texts":[{"id": 1, "text":""},{"id": 2, "text":""}]}. +The "output_count" must equal the length of the "texts" array in the output. From 80a60b23eb98a570e73d3296f95b1f8fa2477840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E7=A3=8A?= Date: Wed, 22 May 2024 20:12:15 +0800 Subject: [PATCH 18/46] Update TranslationService.cs add using --- .../BotSharp.Core/Translation/TranslationService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs index 7067eb7e..97e997c7 100644 --- a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs +++ b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs @@ -6,6 +6,7 @@ using BotSharp.Abstraction.Templating; using BotSharp.Abstraction.Translation.Models; using System.Collections; using System.Reflection; +using System.Text.Encodings.Web; namespace BotSharp.Core.Translation; From 9dad9ae80be85d3615995173d561470dee1e2c61 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 22 May 2024 10:39:04 -0500 Subject: [PATCH 19/46] split file service --- .../Files/BotSharpFileService.Conversation.cs | 188 ++++++++++++++ .../Files/BotSharpFileService.User.cs | 65 +++++ .../Files/BotSharpFileService.cs | 234 +----------------- 3 files changed, 254 insertions(+), 233 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs create mode 100644 src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.User.cs diff --git a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs new file mode 100644 index 00000000..f12ecb60 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs @@ -0,0 +1,188 @@ +using Microsoft.AspNetCore.StaticFiles; +using System.IO; +using System.Threading; + +namespace BotSharp.Core.Files; + +public partial class BotSharpFileService +{ + public IEnumerable GetChatImages(string conversationId, List conversations, int offset = 1) + { + var files = new List(); + if (string.IsNullOrEmpty(conversationId) || conversations.IsNullOrEmpty()) + { + return files; + } + + if (offset <= 0) + { + offset = MIN_OFFSET; + } + else if (offset > MAX_OFFSET) + { + offset = MAX_OFFSET; + } + + var messageIds = conversations.Select(x => x.MessageId).Distinct().TakeLast(offset).ToList(); + files = GetMessageFiles(conversationId, messageIds, imageOnly: true).ToList(); + return files; + } + + public IEnumerable GetMessageFiles(string conversationId, IEnumerable messageIds, bool imageOnly = false) + { + var files = new List(); + if (messageIds.IsNullOrEmpty()) return files; + + foreach (var messageId in messageIds) + { + var dir = GetConversationFileDirectory(conversationId, messageId); + if (!ExistDirectory(dir)) + { + continue; + } + + foreach (var file in Directory.GetFiles(dir)) + { + var contentType = GetFileContentType(file); + if (imageOnly && !_allowedTypes.Contains(contentType)) + { + continue; + } + + var fileName = Path.GetFileNameWithoutExtension(file); + var extension = Path.GetExtension(file); + var fileType = extension.Substring(1); + + var model = new MessageFileModel() + { + MessageId = messageId, + FileUrl = $"/conversation/{conversationId}/message/{messageId}/file/{fileName}", + FileStorageUrl = file, + FileName = fileName, + FileType = fileType, + ContentType = contentType + }; + files.Add(model); + } + } + + return files; + } + + public string GetMessageFile(string conversationId, string messageId, string fileName) + { + var dir = GetConversationFileDirectory(conversationId, messageId); + if (!ExistDirectory(dir)) + { + return string.Empty; + } + + var found = Directory.GetFiles(dir).FirstOrDefault(f => Path.GetFileNameWithoutExtension(f).IsEqualTo(fileName)); + return found; + } + + public bool SaveMessageFiles(string conversationId, string messageId, List files) + { + if (files.IsNullOrEmpty()) return false; + + var dir = GetConversationFileDirectory(conversationId, messageId, createNewDir: true); + if (!ExistDirectory(dir)) return false; + + try + { + for (int i = 0; i < files.Count; i++) + { + var file = files[i]; + if (string.IsNullOrEmpty(file.FileData)) + { + continue; + } + + var (_, bytes) = GetFileInfoFromData(file.FileData); + var fileType = Path.GetExtension(file.FileName); + var fileName = $"{i + 1}{fileType}"; + Thread.Sleep(100); + File.WriteAllBytes(Path.Combine(dir, fileName), bytes); + } + return true; + } + catch (Exception ex) + { + _logger.LogWarning($"Error when saving conversation files: {ex.Message}"); + return false; + } + } + + + + public bool DeleteMessageFiles(string conversationId, IEnumerable messageIds, string targetMessageId, string? newMessageId = null) + { + if (string.IsNullOrEmpty(conversationId) || messageIds == null) return false; + + if (!string.IsNullOrEmpty(targetMessageId) && !string.IsNullOrEmpty(newMessageId)) + { + var prevDir = GetConversationFileDirectory(conversationId, targetMessageId); + var newDir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, newMessageId); + + if (ExistDirectory(prevDir)) + { + if (ExistDirectory(newDir)) + { + Directory.Delete(newDir, true); + } + + Directory.Move(prevDir, newDir); + } + } + + foreach (var messageId in messageIds) + { + var dir = GetConversationFileDirectory(conversationId, messageId); + if (string.IsNullOrEmpty(dir)) continue; + + Thread.Sleep(100); + Directory.Delete(dir, true); + } + + return true; + } + + public bool DeleteConversationFiles(IEnumerable conversationIds) + { + if (conversationIds.IsNullOrEmpty()) return false; + + foreach (var conversationId in conversationIds) + { + var convDir = FindConversationDirectory(conversationId); + if (!ExistDirectory(convDir)) continue; + + Directory.Delete(convDir, true); + } + return true; + } + + #region Private methods + private string GetConversationFileDirectory(string? conversationId, string? messageId, bool createNewDir = false) + { + if (string.IsNullOrEmpty(conversationId) || string.IsNullOrEmpty(messageId)) + { + return string.Empty; + } + + var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, messageId); + if (!Directory.Exists(dir) && createNewDir) + { + Directory.CreateDirectory(dir); + } + return dir; + } + + private string? FindConversationDirectory(string conversationId) + { + if (string.IsNullOrEmpty(conversationId)) return null; + + var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId); + return dir; + } + #endregion +} diff --git a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.User.cs b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.User.cs new file mode 100644 index 00000000..b6a87993 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.User.cs @@ -0,0 +1,65 @@ +using System.IO; + +namespace BotSharp.Core.Files; + +public partial class BotSharpFileService +{ + public string GetUserAvatar() + { + var db = _services.GetRequiredService(); + var user = db.GetUserById(_user.Id); + var dir = GetUserAvatarDir(user?.Id); + + if (!ExistDirectory(dir)) return string.Empty; + + var found = Directory.GetFiles(dir).FirstOrDefault() ?? string.Empty; + return found; + } + + public bool SaveUserAvatar(BotSharpFile file) + { + if (file == null || string.IsNullOrEmpty(file.FileData)) return false; + + try + { + var db = _services.GetRequiredService(); + var user = db.GetUserById(_user.Id); + var dir = GetUserAvatarDir(user?.Id); + + if (string.IsNullOrEmpty(dir)) return false; + + if (Directory.Exists(dir)) + { + Directory.Delete(dir, true); + } + + dir = GetUserAvatarDir(user?.Id, createNewDir: true); + var (_, bytes) = GetFileInfoFromData(file.FileData); + File.WriteAllBytes(Path.Combine(dir, file.FileName), bytes); + return true; + } + catch (Exception ex) + { + _logger.LogWarning($"Error when saving user avatar: {ex.Message}"); + return false; + } + } + + + #region Private methods + private string GetUserAvatarDir(string? userId, bool createNewDir = false) + { + if (string.IsNullOrEmpty(userId)) + { + return string.Empty; + } + + var dir = Path.Combine(_baseDir, USERS_FOLDER, userId, USER_AVATAR_FOLDER); + if (!Directory.Exists(dir) && createNewDir) + { + Directory.CreateDirectory(dir); + } + return dir; + } + #endregion +} diff --git a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs index 178790bc..76d26dbc 100644 --- a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs +++ b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.cs @@ -5,7 +5,7 @@ using System.Threading; namespace BotSharp.Core.Files; -public class BotSharpFileService : IBotSharpFileService +public partial class BotSharpFileService : IBotSharpFileService { private readonly BotSharpDatabaseSettings _dbSettings; private readonly IServiceProvider _services; @@ -45,200 +45,6 @@ public class BotSharpFileService : IBotSharpFileService return dir; } - public IEnumerable GetChatImages(string conversationId, List conversations, int offset = 1) - { - var files = new List(); - if (string.IsNullOrEmpty(conversationId) || conversations.IsNullOrEmpty()) - { - return files; - } - - if (offset <= 0) - { - offset = MIN_OFFSET; - } - else if (offset > MAX_OFFSET) - { - offset = MAX_OFFSET; - } - - var messageIds = conversations.Select(x => x.MessageId).Distinct().TakeLast(offset).ToList(); - files = GetMessageFiles(conversationId, messageIds, imageOnly: true).ToList(); - return files; - } - - public IEnumerable GetMessageFiles(string conversationId, IEnumerable messageIds, bool imageOnly = false) - { - var files = new List(); - if (messageIds.IsNullOrEmpty()) return files; - - foreach (var messageId in messageIds) - { - var dir = GetConversationFileDirectory(conversationId, messageId); - if (!ExistDirectory(dir)) - { - continue; - } - - foreach (var file in Directory.GetFiles(dir)) - { - var contentType = GetFileContentType(file); - if (imageOnly && !_allowedTypes.Contains(contentType)) - { - continue; - } - - var fileName = Path.GetFileNameWithoutExtension(file); - var extension = Path.GetExtension(file); - var fileType = extension.Substring(1); - - var model = new MessageFileModel() - { - MessageId = messageId, - FileUrl = $"/conversation/{conversationId}/message/{messageId}/file/{fileName}", - FileStorageUrl = file, - FileName = fileName, - FileType = fileType, - ContentType = contentType - }; - files.Add(model); - } - } - - return files; - } - - public string GetMessageFile(string conversationId, string messageId, string fileName) - { - var dir = GetConversationFileDirectory(conversationId, messageId); - if (!ExistDirectory(dir)) - { - return string.Empty; - } - - var found = Directory.GetFiles(dir).FirstOrDefault(f => Path.GetFileNameWithoutExtension(f).IsEqualTo(fileName)); - return found; - } - - public bool SaveMessageFiles(string conversationId, string messageId, List files) - { - if (files.IsNullOrEmpty()) return false; - - var dir = GetConversationFileDirectory(conversationId, messageId, createNewDir: true); - if (!ExistDirectory(dir)) return false; - - try - { - for (int i = 0; i < files.Count; i++) - { - var file = files[i]; - if (string.IsNullOrEmpty(file.FileData)) - { - continue; - } - - var (_, bytes) = GetFileInfoFromData(file.FileData); - var fileType = Path.GetExtension(file.FileName); - var fileName = $"{i + 1}{fileType}"; - Thread.Sleep(100); - File.WriteAllBytes(Path.Combine(dir, fileName), bytes); - } - return true; - } - catch (Exception ex) - { - _logger.LogWarning($"Error when saving conversation files: {ex.Message}"); - return false; - } - } - - public string GetUserAvatar() - { - var db = _services.GetRequiredService(); - var user = db.GetUserById(_user.Id); - var dir = GetUserAvatarDir(user?.Id); - - if (!ExistDirectory(dir)) return string.Empty; - - var found = Directory.GetFiles(dir).FirstOrDefault() ?? string.Empty; - return found; - } - - public bool SaveUserAvatar(BotSharpFile file) - { - if (file == null || string.IsNullOrEmpty(file.FileData)) return false; - - try - { - var db = _services.GetRequiredService(); - var user = db.GetUserById(_user.Id); - var dir = GetUserAvatarDir(user?.Id); - - if (string.IsNullOrEmpty(dir)) return false; - - if (Directory.Exists(dir)) - { - Directory.Delete(dir, true); - } - - dir = GetUserAvatarDir(user?.Id, createNewDir: true); - var (_, bytes) = GetFileInfoFromData(file.FileData); - File.WriteAllBytes(Path.Combine(dir, file.FileName), bytes); - return true; - } - catch (Exception ex) - { - _logger.LogWarning($"Error when saving user avatar: {ex.Message}"); - return false; - } - } - - public bool DeleteMessageFiles(string conversationId, IEnumerable messageIds, string targetMessageId, string? newMessageId = null) - { - if (string.IsNullOrEmpty(conversationId) || messageIds == null) return false; - - if (!string.IsNullOrEmpty(targetMessageId) && !string.IsNullOrEmpty(newMessageId)) - { - var prevDir = GetConversationFileDirectory(conversationId, targetMessageId); - var newDir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, newMessageId); - - if (ExistDirectory(prevDir)) - { - if (ExistDirectory(newDir)) - { - Directory.Delete(newDir, true); - } - - Directory.Move(prevDir, newDir); - } - } - - foreach ( var messageId in messageIds) - { - var dir = GetConversationFileDirectory(conversationId, messageId); - if (string.IsNullOrEmpty(dir)) continue; - - Thread.Sleep(100); - Directory.Delete(dir, true); - } - - return true; - } - - public bool DeleteConversationFiles(IEnumerable conversationIds) - { - if (conversationIds.IsNullOrEmpty()) return false; - - foreach (var conversationId in conversationIds) - { - var convDir = FindConversationDirectory(conversationId); - if (!ExistDirectory(convDir)) continue; - - Directory.Delete(convDir, true); - } - return true; - } - public (string, byte[]) GetFileInfoFromData(string data) { if (string.IsNullOrEmpty(data)) @@ -257,44 +63,6 @@ public class BotSharpFileService : IBotSharpFileService } #region Private methods - private string GetConversationFileDirectory(string? conversationId, string? messageId, bool createNewDir = false) - { - if (string.IsNullOrEmpty(conversationId) || string.IsNullOrEmpty(messageId)) - { - return string.Empty; - } - - var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, FILE_FOLDER, messageId); - if (!Directory.Exists(dir) && createNewDir) - { - Directory.CreateDirectory(dir); - } - return dir; - } - - private string? FindConversationDirectory(string conversationId) - { - if (string.IsNullOrEmpty(conversationId)) return null; - - var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId); - return dir; - } - - private string GetUserAvatarDir(string? userId, bool createNewDir = false) - { - if (string.IsNullOrEmpty(userId)) - { - return string.Empty; - } - - var dir = Path.Combine(_baseDir, USERS_FOLDER, userId, USER_AVATAR_FOLDER); - if (!Directory.Exists(dir) && createNewDir) - { - Directory.CreateDirectory(dir); - } - return dir; - } - private string GetFileContentType(string filePath) { string contentType; From d9fd6525dc0eb61185615911a46dc0d62e5f97ff Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Wed, 22 May 2024 11:02:14 -0500 Subject: [PATCH 20/46] Fix SSE response format. --- .../Controllers/ConversationController.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 80374a6d..fd66b225 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -251,6 +251,8 @@ public class ConversationController : ControllerBase await conv.TruncateConversation(conversationId, input.TruncateMessageId, inputMsg.MessageId); } + var state = _services.GetRequiredService(); + var routing = _services.GetRequiredService(); routing.Context.SetMessageId(conversationId, inputMsg.MessageId); @@ -278,6 +280,7 @@ public class ConversationController : ControllerBase response.RichContent = msg.SecondaryRichContent ?? msg.RichContent; response.Instruction = msg.Instruction; response.Data = msg.Data; + response.States = state.GetStates(); await OnChunkReceived(Response, response); }, @@ -290,6 +293,7 @@ public class ConversationController : ControllerBase MessageId = msg.MessageId, Text = msg.Indication, Function = "indicating", + States = new Dictionary() }; await OnChunkReceived(Response, indicator); }, @@ -299,7 +303,6 @@ public class ConversationController : ControllerBase }); - var state = _services.GetRequiredService(); response.States = state.GetStates(); response.MessageId = inputMsg.MessageId; response.ConversationId = conversationId; @@ -309,7 +312,10 @@ public class ConversationController : ControllerBase private async Task OnChunkReceived(HttpResponse response, ChatResponseModel message) { - var json = JsonSerializer.Serialize(message); + var json = JsonSerializer.Serialize(message, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }); var buffer = Encoding.UTF8.GetBytes($"data:{json}\n"); await response.Body.WriteAsync(buffer, 0, buffer.Length); From f584c3190fc723c4c4d0e95b19d71b72b04e09a5 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Thu, 23 May 2024 07:05:36 -0500 Subject: [PATCH 21/46] Fix UserService. --- .../Browsing/Models/BrowserActionResult.cs | 5 +++++ .../Browsing/Models/ElementLocatingArgs.cs | 5 +++++ .../Users/Services/UserService.cs | 2 +- .../PlaywrightWebDriver.LocateElement.cs | 20 ++++++++++++++++--- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs index a634cccd..b3576b90 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs @@ -8,4 +8,9 @@ public class BrowserActionResult public string Selector { get; set; } public string Body { get; set; } public bool IsHighlighted { get; set; } + + public override string ToString() + { + return $"{IsSuccess} - {Selector}"; + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs index 6d6411d8..3b96c760 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs @@ -5,6 +5,9 @@ public class ElementLocatingArgs [JsonPropertyName("match_rule")] public string MatchRule { get; set; } = string.Empty; + [JsonPropertyName("tag")] + public string? Tag { get; set; } = null!; + [JsonPropertyName("text")] public string? Text { get; set; } @@ -20,6 +23,8 @@ public class ElementLocatingArgs [JsonPropertyName("selector")] public string? Selector { get; set; } + public bool Parent { get; set; } + public bool FailIfMultiple { get; set; } /// diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index de4c12c8..4324b6f7 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -77,7 +77,7 @@ public class UserService : IUserService record = db.GetUserByUserName(id); } - User? user = null; + User? user = record; var hooks = _services.GetServices(); if (record == null || record.Source != "internal") { diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs index 13b0464c..df6e0a7d 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs @@ -24,6 +24,12 @@ public partial class PlaywrightWebDriver count = await locator.CountAsync(); } + if (location.Tag != null) + { + locator = page.Locator(location.Tag); + count = await locator.CountAsync(); + } + // try attribute if (!string.IsNullOrEmpty(location.AttributeName)) { @@ -66,12 +72,20 @@ public partial class PlaywrightWebDriver } else if (count == 1) { + if (location.Parent) + { + locator = locator.Locator(".."); + } + result.Selector = locator.ToString().Split('@').Last(); // Make sure the element is visible - await locator.EvaluateAsync("element => element.style.height = ''"); - await locator.EvaluateAsync("element => element.style.width = ''"); - await locator.EvaluateAsync("element => element.style.opacity = ''"); + /*if (!await locator.IsVisibleAsync()) + { + await locator.EvaluateAsync("element => element.style.height = '15px'"); + await locator.EvaluateAsync("element => element.style.width = '15px'"); + await locator.EvaluateAsync("element => element.style.opacity = '1.0'"); + }*/ var text = await locator.InnerTextAsync(); result.Body = text; From e8656a99c01d88fc4a76456cabc189d5986c7483 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sat, 25 May 2024 20:34:29 -0500 Subject: [PATCH 22/46] Add new user verification code. --- .../Repositories/IBotSharpRepository.cs | 9 +-- .../Users/IUserService.cs | 2 + .../BotSharp.Abstraction/Users/Models/User.cs | 2 + .../Users/Models/UserActivationModel.cs | 7 +++ .../Users/Settings/AccountSetting.cs | 9 +++ .../BotSharp.Core/BotSharpCoreExtensions.cs | 5 ++ .../Repository/BotSharpDbContext.cs | 15 ----- .../FileRepository/FileRepository.User.cs | 9 +++ .../Users/Services/UserService.cs | 59 ++++++++++++++++++- .../Controllers/UserController.cs | 12 ++++ .../Collections/UserDocument.cs | 7 ++- .../Repository/MongoRepository.User.cs | 10 ++++ .../PlaywrightWebDriver.HttpRequest.cs | 1 + 13 files changed, 125 insertions(+), 22 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Users/Settings/AccountSetting.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index a451071e..6adcc8ad 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -17,10 +17,11 @@ public interface IBotSharpRepository #endregion #region User - User? GetUserByEmail(string email); - User? GetUserById(string id); - User? GetUserByUserName(string userName); - void CreateUser(User user); + User? GetUserByEmail(string email) => throw new NotImplementedException(); + User? GetUserById(string id) => throw new NotImplementedException(); + User? GetUserByUserName(string userName) => throw new NotImplementedException(); + void CreateUser(User user) => throw new NotImplementedException(); + void UpdateUserVerified(string userId) => throw new NotImplementedException(); #endregion #region Agent diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs index debf68f4..8f314ffa 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Users.Models; +using BotSharp.OpenAPI.ViewModels.Users; namespace BotSharp.Abstraction.Users; @@ -6,6 +7,7 @@ public interface IUserService { Task GetUser(string id); Task CreateUser(User user); + Task ActiveUser(UserActivationModel model); Task GetToken(string authorization); Task GetMyProfile(); } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs index 7ca441fe..4e6ca265 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs @@ -14,6 +14,8 @@ public class User public string Source { get; set; } = "internal"; public string? ExternalId { get; set; } public string Role { get; set; } = UserRole.Client; + public string? VerificationCode { get; set; } + public bool Verified { get; set; } public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs new file mode 100644 index 00000000..904bd936 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/UserActivationModel.cs @@ -0,0 +1,7 @@ +namespace BotSharp.OpenAPI.ViewModels.Users; + +public class UserActivationModel +{ + public string UserName { get; set; } + public string VerificationCode { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Settings/AccountSetting.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Settings/AccountSetting.cs new file mode 100644 index 00000000..06176ce6 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Settings/AccountSetting.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Abstraction.Users.Settings; + +public class AccountSetting +{ + /// + /// Whether to enable verification code to verify the authenticity of new users + /// + public bool NewUserVerification { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs index 51f3eb1d..2dd2dc7f 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs @@ -5,6 +5,7 @@ using BotSharp.Core.Plugins; using BotSharp.Abstraction.Settings; using BotSharp.Abstraction.Options; using BotSharp.Abstraction.Messaging.JsonConverters; +using BotSharp.Abstraction.Users.Settings; namespace BotSharp.Core; @@ -84,6 +85,10 @@ public static class BotSharpCoreExtensions return settingService.Bind("PluginLoader"); }); + var accountSettings = new AccountSetting(); + config.Bind("Account", accountSettings); + services.AddScoped(x => accountSettings); + var loader = new PluginLoader(services, config, pluginSettings); loader.Load(assembly => { diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 28aac06b..6bba6c2a 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -1,6 +1,5 @@ using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Plugins.Models; -using BotSharp.Abstraction.Repositories.Models; using BotSharp.Abstraction.Tasks.Models; using BotSharp.Abstraction.Users.Models; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -176,20 +175,6 @@ public class BotSharpDbContext : Database, IBotSharpRepository => throw new NotImplementedException(); #endregion - #region User - public User? GetUserByEmail(string email) - => throw new NotImplementedException(); - - public User? GetUserById(string id) - => throw new NotImplementedException(); - - public User? GetUserByUserName(string userName) - => throw new NotImplementedException(); - - public void CreateUser(User user) - => throw new NotImplementedException(); - #endregion - #region Execution Log public void AddExecutionLogs(string conversationId, List logs) { diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs index bc992a08..36f17b85 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs @@ -32,4 +32,13 @@ public partial class FileRepository var path = Path.Combine(dir, "user.json"); File.WriteAllText(path, JsonSerializer.Serialize(user, _options)); } + + public void UpdateUserVerified(string userId) + { + var user = GetUserById(userId); + user.Verified = true; + var dir = Path.Combine(_dbSettings.FileRepository, "users", user.Id); + var path = Path.Combine(dir, "user.json"); + File.WriteAllText(path, JsonSerializer.Serialize(user, _options)); + } } diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 4324b6f7..ae5220b9 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -1,4 +1,6 @@ using BotSharp.Abstraction.Users.Models; +using BotSharp.Abstraction.Users.Settings; +using BotSharp.OpenAPI.ViewModels.Users; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using NanoidDotNet; @@ -12,12 +14,17 @@ public class UserService : IUserService private readonly IServiceProvider _services; private readonly IUserIdentity _user; private readonly ILogger _logger; + private readonly AccountSetting _setting; - public UserService(IServiceProvider services, IUserIdentity user, ILogger logger) + public UserService(IServiceProvider services, + IUserIdentity user, + ILogger logger, + AccountSetting setting) { _services = services; _user = user; _logger = logger; + _setting = setting; } public async Task CreateUser(User user) @@ -51,6 +58,12 @@ public class UserService : IUserService record.Salt = Guid.NewGuid().ToString("N"); record.Password = Utilities.HashText(user.Password, record.Salt); + if (_setting.NewUserVerification) + { + record.VerificationCode = Nanoid.Generate(alphabet: "0123456789", size: 6); + record.Verified = false; + } + db.CreateUser(record); _logger.LogWarning($"Created new user account: {record.Id} {record.UserName}"); @@ -120,6 +133,11 @@ public class UserService : IUserService return default; } + if (_setting.NewUserVerification && !record.Verified) + { + return default; + } + #if !DEBUG if (Utilities.HashText(password, record.Salt) != record.Password) { @@ -206,4 +224,43 @@ public class UserService : IUserService var user = db.GetUserById(id); return user; } + + public async Task ActiveUser(UserActivationModel model) + { + var id = model.UserName; + var db = _services.GetRequiredService(); + var record = id.Contains("@") ? db.GetUserByEmail(id) : db.GetUserByUserName(id); + if (record == null) + { + record = db.GetUserByUserName(id); + } + + if (record == null) + { + return default; + } + + if (record.VerificationCode != model.VerificationCode) + { + return default; + } + + if (record.Verified) + { + return default; + } + + db.UpdateUserVerified(record.Id); + + var accessToken = GenerateJwtToken(record); + var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken); + var token = new Token + { + AccessToken = accessToken, + ExpireTime = jwt.Payload.Exp.Value, + TokenType = "Bearer", + Scope = "api" + }; + return token; + } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs index e4201aa8..317d1fc9 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs @@ -61,6 +61,18 @@ public class UserController : ControllerBase return UserViewModel.FromUser(createdUser); } + [AllowAnonymous] + [HttpPost("/user/activate")] + public async Task> ActivateUser(UserActivationModel model) + { + var token = await _userService.ActiveUser(model); + if (token == null) + { + return Unauthorized(); + } + return Ok(token); + } + [HttpGet("/user/me")] public async Task GetMyUserProfile() { diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserDocument.cs index c21a6e08..c277b9f3 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserDocument.cs @@ -13,7 +13,8 @@ public class UserDocument : MongoBase public string Source { get; set; } = "internal"; public string? ExternalId { get; set; } public string Role { get; set; } - + public string? VerificationCode { get; set; } + public bool Verified { get; set; } public DateTime CreatedTime { get; set; } public DateTime UpdatedTime { get; set; } @@ -30,7 +31,9 @@ public class UserDocument : MongoBase Salt = Salt, Source = Source, ExternalId = ExternalId, - Role = Role + Role = Role, + VerificationCode = VerificationCode, + Verified = Verified, }; } } \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs index 1b6b8b77..1a5211f4 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs @@ -40,10 +40,20 @@ public partial class MongoRepository Source = user.Source, ExternalId = user.ExternalId, Role = user.Role, + VerificationCode = user.VerificationCode, + Verified = user.Verified, CreatedTime = DateTime.UtcNow, UpdatedTime = DateTime.UtcNow }; _dc.Users.InsertOne(userCollection); } + + public void UpdateUserVerified(string userId) + { + var filter = Builders.Filter.Eq(x => x.Id, userId); + var update = Builders.Update.Set(x => x.Verified, true) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + _dc.Users.UpdateOne(filter, update); + } } diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs index 4a0177a0..a769332b 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.HttpRequest.cs @@ -27,6 +27,7 @@ public partial class PlaywrightWebDriver try { + _logger.LogInformation($"SendHttpRequest: {args.Url}"); var response = await EvaluateScript(message.ContextId, script); result.IsSuccess = true; result.Body = JsonSerializer.Serialize(response); From abf519481022925af6ad499ff394c366dd30d6d2 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 20:05:46 -0500 Subject: [PATCH 23/46] fix api controller json serilizer --- .../Controllers/ConversationController.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index fd66b225..6ed27b32 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Options; using BotSharp.Abstraction.Routing; namespace BotSharp.OpenAPI.Controllers; @@ -8,12 +9,16 @@ public class ConversationController : ControllerBase { private readonly IServiceProvider _services; private readonly IUserIdentity _user; + private readonly JsonSerializerOptions _jsonOptions; public ConversationController(IServiceProvider services, - IUserIdentity user) + IUserIdentity user, + BotSharpOptions options) { _services = services; _user = user; + _jsonOptions = InitJsonOptions(options); + } [HttpPost("/conversation/{agentId}")] @@ -312,10 +317,7 @@ public class ConversationController : ControllerBase private async Task OnChunkReceived(HttpResponse response, ChatResponseModel message) { - var json = JsonSerializer.Serialize(message, new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }); + var json = JsonSerializer.Serialize(message, _jsonOptions); var buffer = Encoding.UTF8.GetBytes($"data:{json}\n"); await response.Body.WriteAsync(buffer, 0, buffer.Length); @@ -333,4 +335,24 @@ public class ConversationController : ControllerBase buffer = Encoding.UTF8.GetBytes("\n"); await response.Body.WriteAsync(buffer, 0, buffer.Length); } + + private JsonSerializerOptions InitJsonOptions(BotSharpOptions options) + { + var jsonOption = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + AllowTrailingCommas = true + }; + + if (options?.JsonSerializerOptions != null) + { + foreach (var option in options.JsonSerializerOptions.Converters) + { + jsonOption.Converters.Add(option); + } + } + + return jsonOption; + } } From f355aa3f319c91741977f85b7e135786b6e7d1de Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 20:08:53 -0500 Subject: [PATCH 24/46] move google api setting --- .../BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs index eabdba84..a1a6dad2 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs @@ -11,8 +11,6 @@ using Microsoft.Net.Http.Headers; using Microsoft.OpenApi.Models; using Microsoft.IdentityModel.JsonWebTokens; using BotSharp.OpenAPI.BackgroundServices; -using BotSharp.Abstraction.Settings; -using BotSharp.Abstraction.Google.Settings; namespace BotSharp.OpenAPI; @@ -34,12 +32,6 @@ public static class BotSharpOpenApiExtensions services.AddScoped(); services.AddHostedService(); - services.AddScoped(provider => - { - var settingService = provider.GetRequiredService(); - return settingService.Bind("GoogleApi"); - }); - // Add bearer authentication var schema = "MIXED_SCHEME"; var builder = services.AddAuthentication(options => From c49fcc5dcf2b477d1506a6f1f5dc083b911e1a31 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 20:09:18 -0500 Subject: [PATCH 25/46] minor change --- .../BotSharp.Core/Conversations/ConversationPlugin.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs index 6887622b..90eb3298 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Files; +using BotSharp.Abstraction.Google.Settings; using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Plugins.Models; @@ -34,6 +35,12 @@ public class ConversationPlugin : IBotSharpPlugin return settingService.Bind("Conversation"); }); + services.AddScoped(provider => + { + var settingService = provider.GetRequiredService(); + return settingService.Bind("GoogleApi"); + }); + services.AddScoped(); services.AddScoped(); services.AddScoped(); From 2a456df8465140f1c4026c4a795deb4c3cfc8b65 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 20:40:24 -0500 Subject: [PATCH 26/46] temp save --- .../Conversations/IConversationService.cs | 2 ++ .../BotSharp.Core/BotSharp.Core.csproj | 6 +++- .../Services/ConversationService.Summary.cs | 32 +++++++++++++++++++ .../templates/conversation.summary.liquid | 6 ++++ .../Controllers/ConversationController.cs | 7 ++++ 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs create mode 100644 src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index 9df6ae7f..18cee8fc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -53,4 +53,6 @@ public interface IConversationService /// Append user init words /// Task UpdateBreakpoint(bool resetStates = false, string? reason = null); + + Task GetConversationSummary(string conversationId); } diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 0ddc52e8..10e21b3c 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -56,6 +56,7 @@ + @@ -142,6 +143,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs new file mode 100644 index 00000000..53c6470a --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -0,0 +1,32 @@ +using BotSharp.Abstraction.Infrastructures.Enums; +using BotSharp.Abstraction.Templating; + +namespace BotSharp.Core.Conversations.Services; + +public partial class ConversationService +{ + public async Task GetConversationSummary(string conversationId) + { + if (string.IsNullOrEmpty(conversationId)) return string.Empty; + + var dialogs = _storage.GetDialogs(conversationId); + + return string.Empty; + } + + private IEnumerable BuildConversationContent(List dialogs) + { + + } + + private string GetPrompt(Agent router, List dialogs) + { + var template = router.Templates.First(x => x.Name == "conversation.summary").Content; + + var render = _services.GetRequiredService(); + return render.Render(template, new Dictionary + { + { "conversation", } + }); + } +} diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid new file mode 100644 index 00000000..3b6bb53f --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -0,0 +1,6 @@ +Please follow these steps to summarize the conversation: +1. Read the [CONVERSATION] content. +2. Summarize the conversation in one sentence. + +[CONVERSATION] +{{ conversation }} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index fd66b225..ef44472a 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -134,6 +134,13 @@ public class ConversationController : ControllerBase return result; } + [HttpGet("/conversation/{conversationId}/summary")] + public async Task GetConversationSummary([FromRoute] string conversationId) + { + var service = _services.GetRequiredService(); + return await service.GetConversationSummary(conversationId); + } + [HttpGet("/conversation/{conversationId}/user")] public async Task GetConversationUser([FromRoute] string conversationId) { From 6b5d77604e635b614f836106817c25c4d3957f8c Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 21:30:57 -0500 Subject: [PATCH 27/46] add conversation summary --- .../Services/ConversationService.Summary.cs | 54 ++++++++++++++----- .../Services/ConversationService.cs | 2 + .../templates/conversation.summary.liquid | 7 +-- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 53c6470a..00924b93 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -1,4 +1,4 @@ -using BotSharp.Abstraction.Infrastructures.Enums; +using BotSharp.Abstraction.Conversations.Enums; using BotSharp.Abstraction.Templating; namespace BotSharp.Core.Conversations.Services; @@ -9,24 +9,52 @@ public partial class ConversationService { if (string.IsNullOrEmpty(conversationId)) return string.Empty; + var routing = _services.GetRequiredService(); + var agentService = _services.GetRequiredService(); + var dialogs = _storage.GetDialogs(conversationId); + if (dialogs.IsNullOrEmpty()) return string.Empty; - return string.Empty; + var router = await agentService.LoadAgent(AIAssistant); + var content = await routing.GetConversationContent(dialogs); + var prompt = GetPrompt(router, content); + var summary = await Summarize(router, prompt, dialogs); + + return summary; } - private IEnumerable BuildConversationContent(List dialogs) + private string GetPrompt(Agent agent, string content) { - - } - - private string GetPrompt(Agent router, List dialogs) - { - var template = router.Templates.First(x => x.Name == "conversation.summary").Content; - + var template = agent.Templates.First(x => x.Name == "conversation.summary").Content; var render = _services.GetRequiredService(); - return render.Render(template, new Dictionary + return render.Render(template, new Dictionary { }); + } + + private async Task Summarize(Agent agent, string prompt, List dialogs) + { + var provider = agent.LlmConfig.Provider; + var model = agent.LlmConfig.Model; + + if (provider == null || model == null) { - { "conversation", } - }); + var agentSettings = _services.GetRequiredService(); + provider = agentSettings.LlmConfig.Provider; + model = agentSettings.LlmConfig.Model; + } + + var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model); + var response = await chatCompletion.GetChatCompletions(new Agent + { + Id = agent.Id, + Name = agent.Name, + Instruction = prompt + }, dialogs); + + return response.Content; + } + + private void SaveState(string summary) + { + _state.SetState("conversation_summary", summary, source: StateSource.Application); } } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 4de36b9d..8e113226 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -12,6 +12,8 @@ public partial class ConversationService : IConversationService private readonly IConversationStorage _storage; private readonly IConversationStateService _state; private string _conversationId; + private const string AIAssistant = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a"; + public string ConversationId => _conversationId; public IConversationStateService States => _state; diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid index 3b6bb53f..a935e497 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -1,6 +1 @@ -Please follow these steps to summarize the conversation: -1. Read the [CONVERSATION] content. -2. Summarize the conversation in one sentence. - -[CONVERSATION] -{{ conversation }} \ No newline at end of file +Please summarize the conversation. \ No newline at end of file From 953a53c4bc00eb798b48efb418bb39d6a9ea65aa Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 22:19:06 -0500 Subject: [PATCH 28/46] clean code --- .../Conversations/Services/ConversationService.Summary.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 00924b93..252d1e7f 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -1,4 +1,3 @@ -using BotSharp.Abstraction.Conversations.Enums; using BotSharp.Abstraction.Templating; namespace BotSharp.Core.Conversations.Services; @@ -52,9 +51,4 @@ public partial class ConversationService return response.Content; } - - private void SaveState(string summary) - { - _state.SetState("conversation_summary", summary, source: StateSource.Application); - } } From 6c5be6da631595e83338873ff602d1edd6badad5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 22:20:27 -0500 Subject: [PATCH 29/46] clean code --- .../Conversations/Services/ConversationService.Summary.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 252d1e7f..d76678cc 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -15,14 +15,13 @@ public partial class ConversationService if (dialogs.IsNullOrEmpty()) return string.Empty; var router = await agentService.LoadAgent(AIAssistant); - var content = await routing.GetConversationContent(dialogs); - var prompt = GetPrompt(router, content); + var prompt = GetPrompt(router); var summary = await Summarize(router, prompt, dialogs); return summary; } - private string GetPrompt(Agent agent, string content) + private string GetPrompt(Agent agent) { var template = agent.Templates.First(x => x.Name == "conversation.summary").Content; var render = _services.GetRequiredService(); From b8becca94542c0fabb384df4712f0b72551b67d7 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Sun, 26 May 2024 22:20:56 -0500 Subject: [PATCH 30/46] minor change --- .../Conversations/Services/ConversationService.Summary.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index d76678cc..4a547204 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -30,8 +30,8 @@ public partial class ConversationService private async Task Summarize(Agent agent, string prompt, List dialogs) { - var provider = agent.LlmConfig.Provider; - var model = agent.LlmConfig.Model; + var provider = agent?.LlmConfig?.Provider; + var model = agent?.LlmConfig?.Model; if (provider == null || model == null) { From 245384e8d253fd014ed44d273be9aef7c6830cf0 Mon Sep 17 00:00:00 2001 From: "LAPTOP-3CFGGVOS\\rabbit" Date: Mon, 27 May 2024 20:44:01 +0800 Subject: [PATCH 31/46] optimize UpdateBreakPoint --- .../Services/ConversationService.UpdateBreakpoint.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs index 7453a202..1bee7b89 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs @@ -4,7 +4,7 @@ namespace BotSharp.Core.Conversations.Services; public partial class ConversationService : IConversationService { - public async Task UpdateBreakpoint(bool resetStates = false, string? reason = null) + public async Task UpdateBreakpoint(bool resetStates = false, string? reason = null, params string[] excludedStates) { var db = _services.GetRequiredService(); var routingCtx = _services.GetRequiredService(); @@ -22,7 +22,8 @@ public partial class ConversationService : IConversationService { var states = _services.GetRequiredService(); // keep language state - states.CleanStates(StateConst.LANGUAGE); + if(excludedStates.IsNullOrEmpty()) excludedStates = new string[] { StateConst.LANGUAGE }; + states.CleanStates(excludedStates); } var hooks = _services.GetServices() From ad7b3a41eb43212da1b5dd8abb91f637ee16ea86 Mon Sep 17 00:00:00 2001 From: "LAPTOP-3CFGGVOS\\rabbit" Date: Mon, 27 May 2024 21:17:50 +0800 Subject: [PATCH 32/46] optimize UpdateBreakpoint --- .../Conversations/IConversationService.cs | 3 ++- .../Services/ConversationService.UpdateBreakpoint.cs | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index 9df6ae7f..055db3cc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -51,6 +51,7 @@ public interface IConversationService /// /// Whether to reset all states /// Append user init words + /// /// - Task UpdateBreakpoint(bool resetStates = false, string? reason = null); + Task UpdateBreakpoint(bool resetStates = false, string? reason = null, params string[] excludedStates); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs index 1bee7b89..8f88f44f 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs @@ -22,7 +22,12 @@ public partial class ConversationService : IConversationService { var states = _services.GetRequiredService(); // keep language state - if(excludedStates.IsNullOrEmpty()) excludedStates = new string[] { StateConst.LANGUAGE }; + if (excludedStates == null) excludedStates = new string[] { }; + if (!excludedStates.Contains(StateConst.LANGUAGE)) + { + excludedStates = excludedStates.Append(StateConst.LANGUAGE).ToArray(); + } + states.CleanStates(excludedStates); } From a5dad4dee48b54b369299b205b8e329d6b79a5b5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Mon, 27 May 2024 12:12:39 -0500 Subject: [PATCH 33/46] refine summary prompt --- .../Services/ConversationService.Summary.cs | 28 ++++++++++++++----- .../templates/conversation.summary.liquid | 9 +++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 4a547204..25d754d6 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.MLTasks; using BotSharp.Abstraction.Templating; namespace BotSharp.Core.Conversations.Services; @@ -30,17 +31,30 @@ public partial class ConversationService private async Task Summarize(Agent agent, string prompt, List dialogs) { - var provider = agent?.LlmConfig?.Provider; - var model = agent?.LlmConfig?.Model; + var provider = "openai"; + string? model; - if (provider == null || model == null) + var providerService = _services.GetRequiredService(); + var modelSettings = providerService.GetProviderModels(provider); + var modelSetting = modelSettings.FirstOrDefault(x => x.Name.IsEqualTo("gpt4-turbo") || x.Name.IsEqualTo("gpt-4o")); + + if (modelSetting != null) { - var agentSettings = _services.GetRequiredService(); - provider = agentSettings.LlmConfig.Provider; - model = agentSettings.LlmConfig.Model; + model = modelSetting.Name; + } + else + { + provider = agent?.LlmConfig?.Provider; + model = agent?.LlmConfig?.Model; + if (provider == null || model == null) + { + var agentSettings = _services.GetRequiredService(); + provider = agentSettings.LlmConfig.Provider; + model = agentSettings.LlmConfig.Model; + } } - var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model); + var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider, model); var response = await chatCompletion.GetChatCompletions(new Agent { Id = agent.Id, diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid index a935e497..08792af3 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -1 +1,8 @@ -Please summarize the conversation. \ No newline at end of file +Please summarize the conversation. + +*** Super Important! Please consider the entire conversation. Do not only consider the recent sentences. *** +** Please do not respond to the latest conversation. +** If there are different topics in the conversation, please summarize each topic in different sentences and list them in bullets. +* Please use concise sentences to summarize each topic. +* Please do not include excessive details in the summaries. +* Please use 'user' instead of 'you', 'he' or 'she'. \ No newline at end of file From 520b91507c4e5964aab0c5a2bf7abee157061608 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Mon, 27 May 2024 12:51:00 -0500 Subject: [PATCH 34/46] minor change --- .../templates/conversation.summary.liquid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid index 08792af3..e2ffe5db 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -2,7 +2,7 @@ Please summarize the conversation. *** Super Important! Please consider the entire conversation. Do not only consider the recent sentences. *** ** Please do not respond to the latest conversation. -** If there are different topics in the conversation, please summarize each topic in different sentences and list them in bullets. +** If there are different topics in the conversation, please summarize each topic in different sentences and list them with bullets. * Please use concise sentences to summarize each topic. * Please do not include excessive details in the summaries. * Please use 'user' instead of 'you', 'he' or 'she'. \ No newline at end of file From c3c28e282b745dc5a88180389e06135d20affccc Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Mon, 27 May 2024 19:26:58 -0500 Subject: [PATCH 35/46] Return Instruction for SSE. --- .../BotSharp.OpenAPI/Controllers/ConversationController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 6ed27b32..71d824b3 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -298,6 +298,7 @@ public class ConversationController : ControllerBase MessageId = msg.MessageId, Text = msg.Indication, Function = "indicating", + Instruction = msg.Instruction, States = new Dictionary() }; await OnChunkReceived(Response, indicator); From d6ac3c09ea47ccae8298cfc2dded62d135e56e47 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Mon, 27 May 2024 21:06:05 -0500 Subject: [PATCH 36/46] Fix current agent id for routing rule. --- src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index 6b126a37..31caa932 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -118,6 +118,7 @@ public class RoutingContext : IRoutingContext var message = new RoleDialogModel(AgentRole.User, $"Try to route to agent {agent.Name}") { + CurrentAgentId = currentAgentId, FunctionName = "route_to_agent", FunctionArgs = JsonSerializer.Serialize(new FunctionCallFromLlm { From 0ffabd35aa09364697536979618b2ed87d669a15 Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Tue, 28 May 2024 19:47:48 +0800 Subject: [PATCH 37/46] hdong: #65. --- .../Users/IUserService.cs | 2 ++ .../Users/Services/UserService.cs | 26 +++++++++++++++++++ .../Controllers/UserController.cs | 14 ++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs index 8f314ffa..4071790c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs @@ -10,4 +10,6 @@ public interface IUserService Task ActiveUser(UserActivationModel model); Task GetToken(string authorization); Task GetMyProfile(); + Task VerifyUserUnique(string userName); + Task VerifyEmailUnique(string email); } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index ae5220b9..19242e39 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -263,4 +263,30 @@ public class UserService : IUserService }; return token; } + + public async Task VerifyUserUnique(string userName) + { + if (string.IsNullOrEmpty(userName)) + return false; + + var db = _services.GetRequiredService(); + var user = db.GetUserByUserName(userName); + if (user == null) + return true; + + return false; + } + + public async Task VerifyEmailUnique(string email) + { + if (string.IsNullOrEmpty(email)) + return false; + + var db = _services.GetRequiredService(); + var emailName = db.GetUserByEmail(email); + if (emailName == null) + return true; + + return false; + } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs index 317d1fc9..8228e594 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs @@ -94,4 +94,18 @@ public class UserController : ControllerBase } return UserViewModel.FromUser(user); } + + [AllowAnonymous] + [HttpPost("/user/unique/{username}")] + public async Task VerifyUserUnique([FromRoute] string userName) + { + return await _userService.VerifyUserUnique(userName); + } + + [AllowAnonymous] + [HttpPost("/email/unique/{email}")] + public async Task VerifyEmailUnique([FromRoute]string email) + { + return await _userService.VerifyEmailUnique(email); + } } From b4e7c1ac48fe60f1833a3519bfa5ae6514196352 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Tue, 28 May 2024 10:45:13 -0500 Subject: [PATCH 38/46] Upgrade library, release v1.5-sse --- Directory.Build.props | 2 +- .../BotSharp.OpenAPI/BotSharp.OpenAPI.csproj | 8 ++++---- .../BotSharp.Plugin.MongoStorage.csproj | 2 +- .../BotSharp.Plugin.PaddleSharp.csproj | 8 ++++---- .../BotSharp.Plugin.Qdrant.csproj | 2 +- .../BotSharp.Plugin.SemanticKernel.csproj | 6 +++--- .../SemanticKernelMemoryStoreProvider.cs | 12 ++++++------ .../BotSharp.Plugin.SqlDriver.csproj | 2 +- .../BotSharp.Plugin.Twilio.csproj | 2 +- .../BotSharp.Plugin.WeChat.csproj | 2 +- .../BotSharp.Plugin.WebDriver.csproj | 4 ++-- src/WebStarter/appsettings.json | 1 + .../SemanticKernelPluginTests.cs | 4 ++-- 13 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 068b6e13..4ca87cf3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ net8.0 10.0 - 1.4.0 + 1.5.1 true false diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj index 22fcc9e0..8f0e9fcc 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj +++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj @@ -18,16 +18,16 @@ - + - + - - + + diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj index 41c63ad9..9b1d2178 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj b/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj index 6dcaf95e..ef637413 100644 --- a/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj +++ b/src/Plugins/BotSharp.Plugin.PaddleSharp/BotSharp.Plugin.PaddleSharp.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -12,14 +12,14 @@ - - + + - + diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj index 693c7885..bdcd40d5 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj +++ b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj b/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj index 9d790284..c4051422 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/BotSharp.Plugin.SemanticKernel.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -11,8 +11,8 @@ - - + + diff --git a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs index 444cab1e..7df2c0cd 100644 --- a/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs +++ b/src/Plugins/BotSharp.Plugin.SemanticKernel/SemanticKernelMemoryStoreProvider.cs @@ -9,13 +9,13 @@ namespace BotSharp.Plugin.SemanticKernel { internal class SemanticKernelMemoryStoreProvider : IVectorDb { -#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. private readonly IMemoryStore _memoryStore; -#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. -#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. public SemanticKernelMemoryStoreProvider(IMemoryStore memoryStore) -#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { this._memoryStore = memoryStore; } @@ -50,9 +50,9 @@ namespace BotSharp.Plugin.SemanticKernel public async Task Upsert(string collectionName, int id, float[] vector, string text) { -#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. await _memoryStore.UpsertAsync(collectionName, MemoryRecord.LocalRecord(id.ToString(), text, null, vector)); -#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. } } } diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj index 383a9f4e..afb53ae8 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/BotSharp.Plugin.SqlDriver.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj b/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj index c8f1a6f5..ed99a926 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj +++ b/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj index b2c19ae1..85c04581 100644 --- a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj +++ b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj index b03f585d..96f97705 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj +++ b/src/Plugins/BotSharp.Plugin.WebDriver/BotSharp.Plugin.WebDriver.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 5482e6b1..84e402dc 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -111,6 +111,7 @@ "DataDir": "agents", "TemplateFormat": "liquid", "HostAgentId": "01e2fc5c-2c89-4ec7-8470-7688608b496c", + "EnableTranslator": false, "LlmConfig": { "Provider": "azure-openai", "Model": "gpt-35-turbo" diff --git a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs index 99d41024..62646015 100644 --- a/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs +++ b/tests/BotSharp.Plugin.SemanticKernel.UnitTests/SemanticKernelPluginTests.cs @@ -22,9 +22,9 @@ namespace BotSharp.Plugin.SemanticKernel.Tests var plugin = new SemanticKernelPlugin(); services.AddScoped(x => Mock.Of()); services.AddScoped(x => Mock.Of()); -#pragma warning disable SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. services.AddScoped(x => Mock.Of()); -#pragma warning restore SKEXP0003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. #pragma warning disable SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. services.AddScoped(x => Mock.Of()); #pragma warning restore SKEXP0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. From c9428cd965f472edb291282a2a0a1fdf4ddfd42c Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Wed, 29 May 2024 10:20:38 +0800 Subject: [PATCH 39/46] hdong: clean up code for Pagination size. --- .../BotSharp.Abstraction/Utilities/Pagination.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs index 660c8e26..382bd55d 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs @@ -3,7 +3,7 @@ namespace BotSharp.Abstraction.Utilities; public class Pagination { private int _page; - private int _size => 10; + private int _size; public int Page { @@ -19,11 +19,11 @@ public class Pagination if (_size > 100) return 100; return _size; - } - //set - //{ - // _size = value; - //} + } + set + { + _size = value; + } } /// From 8a9b6f319bde02552990c266da84fcb817c887f0 Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Wed, 29 May 2024 10:36:27 +0800 Subject: [PATCH 40/46] hdong: remove the limit. --- .../BotSharp.Abstraction/Utilities/Pagination.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs index 382bd55d..512d27c4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs @@ -13,11 +13,8 @@ public class Pagination public int Size { - get + get { - if (_size <= 0) return 20; - if (_size > 100) return 100; - return _size; } set From 0b56a18aa682ee237b59c7ca7b168dab7757466a Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Tue, 28 May 2024 21:50:16 -0500 Subject: [PATCH 41/46] summarize multiple conversations --- .../Conversations/IConversationService.cs | 2 +- .../Services/ConversationService.Summary.cs | 61 ++++++++++++++++--- .../templates/conversation.summary.liquid | 14 +++-- .../Controllers/ConversationController.cs | 6 +- .../Conversations/ConversationSummaryModel.cs | 9 +++ 5 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationSummaryModel.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index 2aa8a72f..c8b997ec 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -55,5 +55,5 @@ public interface IConversationService /// Task UpdateBreakpoint(bool resetStates = false, string? reason = null, params string[] excludedStates); - Task GetConversationSummary(string conversationId); + Task GetConversationSummary(IEnumerable conversationId); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 25d754d6..533020f0 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs @@ -5,31 +5,51 @@ namespace BotSharp.Core.Conversations.Services; public partial class ConversationService { - public async Task GetConversationSummary(string conversationId) + public async Task GetConversationSummary(IEnumerable conversationIds) { - if (string.IsNullOrEmpty(conversationId)) return string.Empty; + if (conversationIds.IsNullOrEmpty()) return string.Empty; var routing = _services.GetRequiredService(); var agentService = _services.GetRequiredService(); - var dialogs = _storage.GetDialogs(conversationId); - if (dialogs.IsNullOrEmpty()) return string.Empty; + var contents = new List(); + foreach ( var conversationId in conversationIds) + { + if (string.IsNullOrEmpty(conversationId)) continue; + + var dialogs = _storage.GetDialogs(conversationId); + + if (dialogs.IsNullOrEmpty()) continue; + + var content = GetConversationContent(dialogs); + contents.Add(content); + } var router = await agentService.LoadAgent(AIAssistant); - var prompt = GetPrompt(router); - var summary = await Summarize(router, prompt, dialogs); + var prompt = GetPrompt(router, contents); + var summary = await Summarize(router, prompt); return summary; } - private string GetPrompt(Agent agent) + private string GetPrompt(Agent agent, List contents) { var template = agent.Templates.First(x => x.Name == "conversation.summary").Content; var render = _services.GetRequiredService(); - return render.Render(template, new Dictionary { }); + + var texts = string.Empty; + for (int i = 0; i < contents.Count; i++) + { + texts += $"[Conversation {i+1}]\r\n{contents[i]}"; + } + + return render.Render(template, new Dictionary + { + { "texts", texts } + }); } - private async Task Summarize(Agent agent, string prompt, List dialogs) + private async Task Summarize(Agent agent, string prompt) { var provider = "openai"; string? model; @@ -60,8 +80,29 @@ public partial class ConversationService Id = agent.Id, Name = agent.Name, Instruction = prompt - }, dialogs); + }, new List + { + new RoleDialogModel(AgentRole.User, "Please summarize the conversations.") + }); return response.Content; } + + private string GetConversationContent(List dialogs, int maxDialogCount = 50) + { + var conversation = ""; + + foreach (var dialog in dialogs.TakeLast(maxDialogCount)) + { + var role = dialog.Role; + if (role != AgentRole.User) + { + role = AgentRole.Assistant; + } + + conversation += $"{role}: {dialog.Payload ?? dialog.Content}\r\n"; + } + + return conversation + "\r\n"; + } } diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid index e2ffe5db..d7ffae60 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -1,8 +1,14 @@ -Please summarize the conversation. +Please read each conversation in the [CONVERSATION] section and provide a summary. -*** Super Important! Please consider the entire conversation. Do not only consider the recent sentences. *** +*** Super Important! Please consider every conversation. Do not only consider the recent sentences. *** ** Please do not respond to the latest conversation. -** If there are different topics in the conversation, please summarize each topic in different sentences and list them with bullets. +** If there are different topics in the conversations, please summarize each topic in different sentences and list them in bullets. * Please use concise sentences to summarize each topic. * Please do not include excessive details in the summaries. -* Please use 'user' instead of 'you', 'he' or 'she'. \ No newline at end of file +* Please use 'user' instead of 'you', 'he' or 'she'. + +[CONVERSATIONS] + +{% for text in texts -%} +{{ text }}{{ "\r\n\r\n" }} +{%- endfor %} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index a2c2b3b0..adc37636 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -152,11 +152,11 @@ public class ConversationController : ControllerBase return result; } - [HttpGet("/conversation/{conversationId}/summary")] - public async Task GetConversationSummary([FromRoute] string conversationId) + [HttpPost("/conversation/summary")] + public async Task GetConversationSummary([FromBody] ConversationSummaryModel input) { var service = _services.GetRequiredService(); - return await service.GetConversationSummary(conversationId); + return await service.GetConversationSummary(input.ConversationIds); } [HttpGet("/conversation/{conversationId}/user")] diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationSummaryModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationSummaryModel.cs new file mode 100644 index 00000000..0854ab2a --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationSummaryModel.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.OpenAPI.ViewModels.Conversations; + +public class ConversationSummaryModel +{ + [JsonPropertyName("conversation_ids")] + public List ConversationIds { get; set; } = new List(); +} From 9fc7f1c3b0a2cbd3d34d6f8ae2ac08b661e9d2f5 Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Wed, 29 May 2024 10:50:41 +0800 Subject: [PATCH 42/46] hdong:change request method and API name. --- .../BotSharp.OpenAPI/Controllers/UserController.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs index 8228e594..e413724b 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs @@ -95,16 +95,14 @@ public class UserController : ControllerBase return UserViewModel.FromUser(user); } - [AllowAnonymous] - [HttpPost("/user/unique/{username}")] - public async Task VerifyUserUnique([FromRoute] string userName) + [HttpGet("/user/name/existing")] + public async Task VerifyUserUnique([FromQuery] string userName) { return await _userService.VerifyUserUnique(userName); } - [AllowAnonymous] - [HttpPost("/email/unique/{email}")] - public async Task VerifyEmailUnique([FromRoute]string email) + [HttpGet("/user/email/existing")] + public async Task VerifyEmailUnique([FromQuery] string email) { return await _userService.VerifyEmailUnique(email); } From 11fa2513b1303f4e6508a17e6587adf2bca612a1 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Tue, 28 May 2024 21:51:13 -0500 Subject: [PATCH 43/46] minor change --- .../templates/conversation.summary.liquid | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid index d7ffae60..bb4e764f 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/conversation.summary.liquid @@ -1,4 +1,4 @@ -Please read each conversation in the [CONVERSATION] section and provide a summary. +Please read each conversation in the [CONVERSATIONS] section and provide a summary. *** Super Important! Please consider every conversation. Do not only consider the recent sentences. *** ** Please do not respond to the latest conversation. @@ -10,5 +10,5 @@ Please read each conversation in the [CONVERSATION] section and provide a summar [CONVERSATIONS] {% for text in texts -%} -{{ text }}{{ "\r\n\r\n" }} +{{ text }}{{ "\r\n" }} {%- endfor %} \ No newline at end of file From e9ae471a6571ab622fe9fee4df6226e82b86568c Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Tue, 28 May 2024 22:44:49 -0500 Subject: [PATCH 44/46] Remove openIfNotExist from LaunchBrowser --- .../Browsing/IWebBrowser.cs | 2 +- .../PlaywrightWebDriver.GoToPage.cs | 18 +++++++++++++++++- .../PlaywrightWebDriver.LaunchBrowser.cs | 2 +- .../PlaywrightWebDriver.LocateElement.cs | 4 ++-- .../SeleniumWebDriver.LaunchBrowser.cs | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs index fc907351..e2581ba9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs @@ -4,7 +4,7 @@ namespace BotSharp.Abstraction.Browsing; public interface IWebBrowser { - Task LaunchBrowser(string contextId, string? url, bool openIfNotExist = true); + Task LaunchBrowser(string contextId, string? url); Task ScreenshotAsync(string contextId, string path); Task ScrollPageAsync(BrowserActionParams actionParams); diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs index 5513e89f..f830bc9f 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs @@ -5,13 +5,29 @@ public partial class PlaywrightWebDriver public async Task GoToPage(string contextId, string url, bool openNewTab = false) { var result = new BrowserActionResult(); + var context = await _instance.InitInstance(contextId); try { + // Check if the page is already open + foreach (var p in context.Pages) + { + if (p.Url == url) + { + result.Body = await p.ContentAsync(); + result.IsSuccess = true; + await p.BringToFrontAsync(); + return result; + } + } + var page = openNewTab ? await _instance.NewPage(contextId) : _instance.GetPage(contextId); var response = await page.GotoAsync(url); await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); - await page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await page.WaitForLoadStateAsync(LoadState.NetworkIdle, new PageWaitForLoadStateOptions + { + Timeout = 1000 * 60 * 5 + }); if (response.Status == 200) { diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LaunchBrowser.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LaunchBrowser.cs index b3afd940..df844828 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LaunchBrowser.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LaunchBrowser.cs @@ -2,7 +2,7 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; public partial class PlaywrightWebDriver { - public async Task LaunchBrowser(string contextId, string? url, bool openIfNotExist = true) + public async Task LaunchBrowser(string contextId, string? url) { var result = new BrowserActionResult() { diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs index df6e0a7d..60e0ce95 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs @@ -87,8 +87,8 @@ public partial class PlaywrightWebDriver await locator.EvaluateAsync("element => element.style.opacity = '1.0'"); }*/ - var text = await locator.InnerTextAsync(); - result.Body = text; + var html = await locator.InnerHTMLAsync(); + result.Body = html; result.IsSuccess = true; } else if (count > 1) diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs index 3203b617..73cfa9ee 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/SeleniumDriver/SeleniumWebDriver.LaunchBrowser.cs @@ -2,7 +2,7 @@ namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver; public partial class SeleniumWebDriver { - public async Task LaunchBrowser(string contextId, string? url, bool openIfNotExist = true) + public async Task LaunchBrowser(string contextId, string? url) { var result = new BrowserActionResult() { From 89eb725f971ebf8634f0c46e9ad2f0a0e89d7951 Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Wed, 29 May 2024 19:27:38 -0500 Subject: [PATCH 45/46] clean file controller --- .../Controllers/ConversationController.cs | 78 ++++++++++++++++--- .../Controllers/FileController.cs | 73 ----------------- .../Controllers/UserController.cs | 32 ++++++++ 3 files changed, 101 insertions(+), 82 deletions(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index adc37636..aba09f52 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -219,15 +219,7 @@ public class ConversationController : ControllerBase return response; } - private void SetStates(IConversationService conv, NewMessageModel input) - { - conv.States.SetState("channel", input.Channel, source: StateSource.External) - .SetState("provider", input.Provider, source: StateSource.External) - .SetState("model", input.Model, source: StateSource.External) - .SetState("temperature", input.Temperature, source: StateSource.External) - .SetState("sampling_factor", input.SamplingFactor, source: StateSource.External); - } - + #region Send message [HttpPost("/conversation/{agentId}/{conversationId}")] public async Task SendMessage([FromRoute] string agentId, [FromRoute] string conversationId, @@ -350,6 +342,73 @@ public class ConversationController : ControllerBase // await OnEventCompleted(Response); } + #endregion + + #region Files and attachments + [HttpPost("/conversation/{conversationId}/attachments")] + public IActionResult UploadAttachments([FromRoute] string conversationId, + IFormFile[] files) + { + if (files != null && files.Length > 0) + { + var fileService = _services.GetRequiredService(); + var dir = fileService.GetDirectory(conversationId); + foreach (var file in files) + { + // Save the file, process it, etc. + var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); + var filePath = Path.Combine(dir, fileName); + + using (var stream = new FileStream(filePath, FileMode.Create)) + { + file.CopyTo(stream); + } + } + + return Ok(new { message = "File uploaded successfully." }); + } + + return BadRequest(new { message = "Invalid file." }); + } + + [HttpGet("/conversation/{conversationId}/files/{messageId}")] + public IEnumerable GetMessageFiles([FromRoute] string conversationId, [FromRoute] string messageId) + { + var fileService = _services.GetRequiredService(); + var files = fileService.GetMessageFiles(conversationId, new List { messageId }); + return files?.Select(x => MessageFileViewModel.Transform(x))?.ToList() ?? new List(); + } + + [HttpGet("/conversation/{conversationId}/message/{messageId}/file/{fileName}")] + public IActionResult GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string fileName) + { + var fileService = _services.GetRequiredService(); + var file = fileService.GetMessageFile(conversationId, messageId, fileName); + if (string.IsNullOrEmpty(file)) + { + return NotFound(); + } + return BuildFileResult(file); + } + #endregion + + #region Private methods + private void SetStates(IConversationService conv, NewMessageModel input) + { + conv.States.SetState("channel", input.Channel, source: StateSource.External) + .SetState("provider", input.Provider, source: StateSource.External) + .SetState("model", input.Model, source: StateSource.External) + .SetState("temperature", input.Temperature, source: StateSource.External) + .SetState("sampling_factor", input.SamplingFactor, source: StateSource.External); + } + + private FileContentResult BuildFileResult(string file) + { + using Stream stream = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); + var bytes = new byte[stream.Length]; + stream.Read(bytes, 0, (int)stream.Length); + return File(bytes, "application/octet-stream", Path.GetFileName(file)); + } private async Task OnChunkReceived(HttpResponse response, ChatResponseModel message) { @@ -391,4 +450,5 @@ public class ConversationController : ControllerBase return jsonOption; } + #endregion } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs index 0c7fa255..36dddebd 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/FileController.cs @@ -10,77 +10,4 @@ public class FileController : ControllerBase { _services = services; } - - [HttpPost("/conversation/{conversationId}/attachments")] - public IActionResult UploadAttachments([FromRoute] string conversationId, - IFormFile[] files) - { - if (files != null && files.Length > 0) - { - var fileService = _services.GetRequiredService(); - var dir = fileService.GetDirectory(conversationId); - foreach (var file in files) - { - // Save the file, process it, etc. - var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); - var filePath = Path.Combine(dir, fileName); - - using (var stream = new FileStream(filePath, FileMode.Create)) - { - file.CopyTo(stream); - } - } - - return Ok(new { message = "File uploaded successfully." }); - } - - return BadRequest(new { message = "Invalid file." }); - } - - [HttpGet("/conversation/{conversationId}/files/{messageId}")] - public IEnumerable GetMessageFiles([FromRoute] string conversationId, [FromRoute] string messageId) - { - var fileService = _services.GetRequiredService(); - var files = fileService.GetMessageFiles(conversationId, new List { messageId }); - return files?.Select(x => MessageFileViewModel.Transform(x))?.ToList() ?? new List(); - } - - [HttpGet("/conversation/{conversationId}/message/{messageId}/file/{fileName}")] - public IActionResult GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string fileName) - { - var fileService = _services.GetRequiredService(); - var file = fileService.GetMessageFile(conversationId, messageId, fileName); - if (string.IsNullOrEmpty(file)) - { - return NotFound(); - } - return BuildFileResult(file); - } - - [HttpPost("/user/avatar")] - public bool UploadUserAvatar([FromBody] BotSharpFile file) - { - var fileService = _services.GetRequiredService(); - return fileService.SaveUserAvatar(file); - } - - [HttpGet("/user/avatar")] - public IActionResult GetUserAvatar() - { - var fileService = _services.GetRequiredService(); - var file = fileService.GetUserAvatar(); - if (string.IsNullOrEmpty(file)) - { - return NotFound(); - } - return BuildFileResult(file); - } - - private FileContentResult BuildFileResult(string file) - { - using Stream stream = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); - var bytes = new byte[stream.Length]; - stream.Read(bytes, 0, (int)stream.Length); - return File(bytes, "application/octet-stream", Path.GetFileName(file)); - } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs index e413724b..682b963b 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs @@ -106,4 +106,36 @@ public class UserController : ControllerBase { return await _userService.VerifyEmailUnique(email); } + + #region Avatar + [HttpPost("/user/avatar")] + public bool UploadUserAvatar([FromBody] BotSharpFile file) + { + var fileService = _services.GetRequiredService(); + return fileService.SaveUserAvatar(file); + } + + [HttpGet("/user/avatar")] + public IActionResult GetUserAvatar() + { + var fileService = _services.GetRequiredService(); + var file = fileService.GetUserAvatar(); + if (string.IsNullOrEmpty(file)) + { + return NotFound(); + } + return BuildFileResult(file); + } + #endregion + + + #region Private methods + private FileContentResult BuildFileResult(string file) + { + using Stream stream = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); + var bytes = new byte[stream.Length]; + stream.Read(bytes, 0, (int)stream.Length); + return File(bytes, "application/octet-stream", Path.GetFileName(file)); + } + #endregion } From f3bdc73a4ae35d0321ecaff0f9a264b9076806c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=93=E7=A3=8A?= Date: Thu, 30 May 2024 16:49:55 +0800 Subject: [PATCH 46/46] add Pagination size default value --- src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs index 512d27c4..9ada5f63 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs @@ -15,7 +15,7 @@ public class Pagination { get { - return _size; + return _size > 0 ? _size : 1; } set {