From 23d0d5a763110ea1fc0e9129018795da6d33feba Mon Sep 17 00:00:00 2001 From: YouWeiDH Date: Sun, 6 Oct 2024 17:49:34 +0800 Subject: [PATCH 01/13] hdong: Add send verify code API with none login and login when reset password. --- .../Users/IUserService.cs | 3 +- .../Users/Services/UserService.cs | 60 +++++++++++++------ .../Controllers/UserController.cs | 12 +++- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs index 750858a7..5a3315b7 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs @@ -13,7 +13,8 @@ public interface IUserService Task GetMyProfile(); Task VerifyUserNameExisting(string userName); Task VerifyEmailExisting(string email); - Task SendVerificationCodeResetPassword(User user); + Task SendVerificationCodeResetPasswordNoLogin(User user); + Task SendVerificationCodeResetPasswordLogin(); Task ResetUserPassword(User user); Task ModifyUserEmail(string email); Task ModifyUserPhone(string phone); diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index c0cf9588..bc6fc317 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -412,7 +412,48 @@ public class UserService : IUserService return false; } - public async Task SendVerificationCodeResetPassword(User user) + public async Task SendVerificationCodeResetPasswordNoLogin(User user) + { + var db = _services.GetRequiredService(); + + User? record = null; + + if (!string.IsNullOrEmpty(user.Email) && !string.IsNullOrEmpty(user.Phone)) + { + return false; + } + + if (!string.IsNullOrEmpty(user.Phone)) + { + record = db.GetUserByPhone(user.Phone); + } + + if (!string.IsNullOrEmpty(user.Email)) + { + record = db.GetUserByEmail(user.Email); + } + + if (record == null) + { + return false; + } + + record.VerificationCode = Nanoid.Generate(alphabet: "0123456789", size: 6); + + //update current verification code. + db.UpdateUserVerificationCode(record.Id, record.VerificationCode); + + //send code to user Email. + var hooks = _services.GetServices(); + foreach (var hook in hooks) + { + hook.VerificationCodeResetPassword(record); + } + + return true; + } + + public async Task SendVerificationCodeResetPasswordLogin() { var db = _services.GetRequiredService(); @@ -422,23 +463,6 @@ public class UserService : IUserService { record = db.GetUserById(_user.Id); } - else - { - if (!string.IsNullOrEmpty(user.Email) && !string.IsNullOrEmpty(user.Phone)) - { - return false; - } - - if (!string.IsNullOrEmpty(user.Email)) - { - record = db.GetUserByEmail(user.Email); - } - - if (!string.IsNullOrEmpty(user.Phone)) - { - record = db.GetUserByPhone(user.Phone); - } - } if (record == null) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs index 281de3e8..bf15a33b 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs @@ -108,12 +108,20 @@ public class UserController : ControllerBase { return await _userService.VerifyEmailExisting(email); } + [AllowAnonymous] - [HttpPost("/user/verifycode")] + [HttpPost("/user/verifycode-out")] public async Task SendVerificationCodeResetPassword([FromBody] UserCreationModel user) { - return await _userService.SendVerificationCodeResetPassword(user.ToUser()); + return await _userService.SendVerificationCodeResetPasswordNoLogin(user.ToUser()); } + + [HttpPost("/user/verifycode-in")] + public async Task SendVerificationCodeResetPasswordLogined() + { + return await _userService.SendVerificationCodeResetPasswordLogin(); + } + [AllowAnonymous] [HttpPost("/user/resetpassword")] public async Task ResetUserPassword([FromBody] UserResetPasswordModel user) From 70babdac7c5d3f2e89c1ac2a00ba467c07ca1e69 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 7 Oct 2024 13:10:48 -0500 Subject: [PATCH 02/13] fix vector db --- .../Services/KnowledgeService.Document.cs | 48 ++++++++++++------- .../BotSharp.Plugin.Qdrant/QdrantDb.cs | 27 ++++++----- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs index 74469177..3959f45d 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs @@ -60,7 +60,20 @@ public partial class KnowledgeService } // Save to vector db - var dataIds = await SaveToVectorDb(collectionName, fileId, file.FileName, contents, file.FileSource); + var payload = new Dictionary() + { + { KnowledgePayloadName.DataSource, VectorDataSource.File }, + { KnowledgePayloadName.FileId, fileId.ToString() }, + { KnowledgePayloadName.FileName, file.FileName }, + { KnowledgePayloadName.FileSource, file.FileSource } + }; + + if (!string.IsNullOrWhiteSpace(file.FileUrl)) + { + payload[KnowledgePayloadName.FileUrl] = file.FileUrl; + } + + var dataIds = await SaveToVectorDb(collectionName, fileId, file.FileName, contents, payload); if (!dataIds.IsNullOrEmpty()) { db.SaveKnolwedgeBaseFileMeta(new KnowledgeDocMetaData @@ -119,7 +132,20 @@ public partial class KnowledgeService var fileId = Guid.NewGuid(); var contentType = FileUtility.GetFileContentType(fileName); - var dataIds = await SaveToVectorDb(collectionName, fileId, fileName, contents, fileSource, fileUrl: refData?.Url); + var payload = new Dictionary() + { + { KnowledgePayloadName.DataSource, VectorDataSource.File }, + { KnowledgePayloadName.FileId, fileId.ToString() }, + { KnowledgePayloadName.FileName, fileName }, + { KnowledgePayloadName.FileSource, fileSource } + }; + + if (!string.IsNullOrWhiteSpace(refData?.Url)) + { + payload[KnowledgePayloadName.FileUrl] = refData.Url; + } + + var dataIds = await SaveToVectorDb(collectionName, fileId, fileName, contents, payload); db.SaveKnolwedgeBaseFileMeta(new KnowledgeDocMetaData { Collection = collectionName, @@ -386,8 +412,7 @@ public partial class KnowledgeService } private async Task> SaveToVectorDb( - string collectionName, Guid fileId, string fileName, IEnumerable contents, - string fileSource = KnowledgeDocSource.Api, string vectorDataSource = VectorDataSource.File, string? fileUrl = null) + string collectionName, Guid fileId, string fileName, IEnumerable contents, Dictionary? payload = null) { if (contents.IsNullOrEmpty()) { @@ -398,25 +423,12 @@ public partial class KnowledgeService var vectorDb = GetVectorDb(); var textEmbedding = GetTextEmbedding(collectionName); - var payload = new Dictionary - { - { KnowledgePayloadName.DataSource, vectorDataSource }, - { KnowledgePayloadName.FileId, fileId.ToString() }, - { KnowledgePayloadName.FileName, fileName }, - { KnowledgePayloadName.FileSource, fileSource } - }; - - if (!string.IsNullOrWhiteSpace(fileUrl)) - { - payload[KnowledgePayloadName.FileUrl] = fileUrl; - } - for (int i = 0; i < contents.Count(); i++) { var content = contents.ElementAt(i); var vector = await textEmbedding.GetVectorAsync(content); var dataId = Guid.NewGuid(); - var saved = await vectorDb.Upsert(collectionName, dataId, vector, content, payload); + var saved = await vectorDb.Upsert(collectionName, dataId, vector, content, payload ?? new Dictionary()); if (!saved) continue; diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs index 9dde5b35..ef9faa93 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs +++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs @@ -212,42 +212,45 @@ public class QdrantDb : IVectorDb { foreach (var item in payload) { - if (item.Value is string str) - { - point.Payload[item.Key] = str; - } - else if (item.Value is bool b) + var value = item.Value?.ToString(); + if (value == null) continue; + + if (bool.TryParse(value, out var b)) { point.Payload[item.Key] = b; } - else if (item.Value is byte int8) + else if (byte.TryParse(value, out var int8)) { point.Payload[item.Key] = int8; } - else if (item.Value is short int16) + else if (short.TryParse(value, out var int16)) { point.Payload[item.Key] = int16; } - else if (item.Value is int int32) + else if (int.TryParse(value, out var int32)) { point.Payload[item.Key] = int32; } - else if (item.Value is long int64) + else if (long.TryParse(value, out var int64)) { point.Payload[item.Key] = int64; } - else if (item.Value is float f32) + else if (float.TryParse(value, out var f32)) { point.Payload[item.Key] = f32; } - else if (item.Value is double f64) + else if (double.TryParse(value, out var f64)) { point.Payload[item.Key] = f64; } - else if (item.Value is DateTime dt) + else if (DateTime.TryParse(value, out var dt)) { point.Payload[item.Key] = dt.ToUniversalTime().ToString("o"); } + else + { + point.Payload[item.Key] = value; + } } } From 1fcd93fd01b99b496ad4a96b7527af1961b4ae46 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 7 Oct 2024 16:35:39 -0500 Subject: [PATCH 03/13] add notification and message type --- .../Conversations/ConversationHookBase.cs | 3 ++ .../Conversations/Enums/MessageTypeName.cs | 7 ++++ .../Conversations/IConversationHook.cs | 9 ++++- .../Conversations/IConversationService.cs | 4 +- .../Conversations/IConversationStorage.cs | 1 - .../Conversations/Models/Conversation.cs | 3 ++ .../Conversations/Models/RoleDialogModel.cs | 9 +++++ .../Loggers/Enums/ContentLogSource.cs | 1 + .../Services/ConversationService.Summary.cs | 2 + .../Services/ConversationService.cs | 9 ++++- .../Services/ConversationStorage.cs | 23 ++--------- .../Controllers/ConversationController.cs | 40 +++++++++++++++++++ .../Hooks/ChatHubConversationHook.cs | 31 ++++++++++++++ .../Models/DialogMongoElement.cs | 3 ++ 14 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Conversations/Enums/MessageTypeName.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index 06a97174..9239b865 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -79,4 +79,7 @@ public abstract class ConversationHookBase : IConversationHook public virtual Task OnBreakpointUpdated(string conversationId, bool resetStates) => Task.CompletedTask; + + public virtual Task OnNotificationGenerated(RoleDialogModel message) + => Task.CompletedTask; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Enums/MessageTypeName.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Enums/MessageTypeName.cs new file mode 100644 index 00000000..c4e73d69 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Enums/MessageTypeName.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Conversations.Enums; + +public static class MessageTypeName +{ + public const string Plain = "plain"; + public const string Notification = "notification"; +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs index 9ed47c61..34371ba5 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs @@ -1,5 +1,3 @@ -using BotSharp.Abstraction.Functions.Models; - namespace BotSharp.Abstraction.Conversations; public interface IConversationHook @@ -107,4 +105,11 @@ public interface IConversationHook /// /// Task OnBreakpointUpdated(string conversationId, bool resetStates); + + /// + /// Generate a notification + /// + /// + /// + Task OnNotificationGenerated(RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index bddc5426..a52b9f07 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -8,7 +8,7 @@ public interface IConversationService IConversationStateService States { get; } string ConversationId { get; } Task NewConversation(Conversation conversation); - void SetConversationId(string conversationId, List states); + void SetConversationId(string conversationId, List states, bool isReadOnly = false); Task GetConversation(string id); Task> GetConversations(ConversationFilter filter); Task UpdateConversationTitle(string id, string title); @@ -41,7 +41,7 @@ public interface IConversationService PostbackMessageModel? replyMessage, Func onResponseReceived); - List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true); + List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? excludeMessageTypes = null); Task CleanHistory(string agentId); /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs index 5f7066d2..a586e217 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs @@ -2,7 +2,6 @@ namespace BotSharp.Abstraction.Conversations; public interface IConversationStorage { - void InitStorage(string conversationId); void Append(string conversationId, RoleDialogModel dialog); List GetDialogs(string conversationId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs index ad7ffd04..890f3211 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs @@ -83,6 +83,9 @@ public class DialogMetaData [JsonPropertyName("message_id")] public string MessageId { get; set; } + [JsonPropertyName("message_type")] + public string MessageType { get; set; } + [JsonPropertyName("function_name")] public string? FunctionName { get; set; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index 5b8f7017..679527a3 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Conversations.Enums; using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Messaging.Models.RichContent; @@ -11,6 +12,11 @@ public class RoleDialogModel : ITrackableMessage /// public string MessageId { get; set; } + /// + /// The message type + /// + public string MessageType { get; set; } = MessageTypeName.Plain; + /// /// user, system, assistant, function /// @@ -101,6 +107,7 @@ public class RoleDialogModel : ITrackableMessage public List GeneratedImages { get; set; } = new List(); + private RoleDialogModel() { } @@ -110,6 +117,7 @@ public class RoleDialogModel : ITrackableMessage Role = role; Content = text; MessageId = Guid.NewGuid().ToString(); + MessageType = MessageTypeName.Plain; } public override string ToString() @@ -132,6 +140,7 @@ public class RoleDialogModel : ITrackableMessage { CurrentAgentId = source.CurrentAgentId, MessageId = source.MessageId, + MessageType = source.MessageType, FunctionArgs = source.FunctionArgs, FunctionName = source.FunctionName, ToolCallId = source.ToolCallId, diff --git a/src/Infrastructure/BotSharp.Abstraction/Loggers/Enums/ContentLogSource.cs b/src/Infrastructure/BotSharp.Abstraction/Loggers/Enums/ContentLogSource.cs index 45d74a51..78ab19ad 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Loggers/Enums/ContentLogSource.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Loggers/Enums/ContentLogSource.cs @@ -7,4 +7,5 @@ public static class ContentLogSource public const string FunctionCall = "function call"; public const string AgentResponse = "agent response"; public const string HardRule = "hard rule"; + public const string Notification = "notification"; } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.Summary.cs index 0983e2ed..88d3a52d 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.Conversations.Enums; using BotSharp.Abstraction.MLTasks; using BotSharp.Abstraction.Templating; @@ -21,6 +22,7 @@ public partial class ConversationService if (dialogs.IsNullOrEmpty()) continue; + dialogs = dialogs.Where(x => x.MessageType != MessageTypeName.Notification).ToList(); var content = GetConversationContent(dialogs); if (string.IsNullOrWhiteSpace(content)) continue; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 6e0f97d1..40f412d9 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -106,7 +106,7 @@ public partial class ConversationService : IConversationService throw new NotImplementedException(); } - public List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true) + public List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? excludeMessageTypes = null) { if (string.IsNullOrEmpty(_conversationId)) { @@ -115,6 +115,11 @@ public partial class ConversationService : IConversationService var dialogs = _storage.GetDialogs(_conversationId); + if (!excludeMessageTypes.IsNullOrEmpty()) + { + dialogs = dialogs.Where(x => !excludeMessageTypes.Contains(x.MessageType)).ToList(); + } + if (fromBreakpoint) { var db = _services.GetRequiredService(); @@ -134,7 +139,7 @@ public partial class ConversationService : IConversationService .ToList(); } - public void SetConversationId(string conversationId, List states) + public void SetConversationId(string conversationId, List states, bool isReadOnly = false) { _conversationId = conversationId; _state.Load(_conversationId); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 5abc4fc5..ea145ac0 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -41,6 +41,7 @@ public class ConversationStorage : IConversationStorage Role = dialog.Role, AgentId = agentId, MessageId = dialog.MessageId, + MessageType = dialog.MessageType, FunctionName = dialog.FunctionName, CreateTime = dialog.CreatedAt }; @@ -65,6 +66,7 @@ public class ConversationStorage : IConversationStorage Role = dialog.Role, AgentId = agentId, MessageId = dialog.MessageId, + MessageType = dialog.MessageType, SenderId = dialog.SenderId, FunctionName = dialog.FunctionName, CreateTime = dialog.CreatedAt @@ -108,6 +110,7 @@ public class ConversationStorage : IConversationStorage var role = meta.Role; var currentAgentId = meta.AgentId; var messageId = meta.MessageId; + var messageType = meta.MessageType; var function = meta.FunctionName; var senderId = role == AgentRole.Function ? currentAgentId : meta.SenderId; var createdAt = meta.CreateTime; @@ -120,6 +123,7 @@ public class ConversationStorage : IConversationStorage { CurrentAgentId = currentAgentId, MessageId = messageId, + MessageType = messageType, CreatedAt = createdAt, SenderId = senderId, FunctionName = function, @@ -143,23 +147,4 @@ public class ConversationStorage : IConversationStorage return results; } - - public void InitStorage(string conversationId) - { - var file = GetStorageFile(conversationId); - if (!File.Exists(file)) - { - File.WriteAllLines(file, new string[0]); - } - } - - private string GetStorageFile(string conversationId) - { - var dir = Path.Combine(_dbSettings.FileRepository, "conversations", conversationId); - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - return Path.Combine(dir, "dialogs.txt"); - } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 5521b5e6..a020a490 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,8 +1,10 @@ +using Azure; using BotSharp.Abstraction.Files.Constants; using BotSharp.Abstraction.Files.Enums; using BotSharp.Abstraction.Options; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Users.Enums; +using BotSharp.Core.Infrastructures; namespace BotSharp.OpenAPI.Controllers; @@ -251,6 +253,44 @@ public class ConversationController : ControllerBase return isSuccess ? newMessageId : string.Empty; } + #region Send notification + [HttpPost("/conversation/{conversationId}/notification")] + public async Task SendNotification([FromRoute] string conversationId, [FromBody] NewMessageModel input) + { + var conv = _services.GetRequiredService(); + var routing = _services.GetRequiredService(); + var userService = _services.GetRequiredService(); + + conv.SetConversationId(conversationId, new List(), isReadOnly: true); + + var inputMsg = new RoleDialogModel(AgentRole.User, input.Text) + { + MessageId = Guid.NewGuid().ToString(), + CreatedAt = DateTime.UtcNow + }; + + var user = await userService.GetUser(_user.Id); + var response = new ChatResponseModel() + { + ConversationId = conversationId, + MessageId = inputMsg.MessageId, + Sender = new UserViewModel + { + Id = user?.Id ?? string.Empty, + FirstName = user?.FirstName ?? string.Empty, + LastName = user?.LastName ?? string.Empty + }, + CreatedAt = DateTime.UtcNow + }; + + await HookEmitter.Emit(_services, async hook => + await hook.OnNotificationGenerated(inputMsg) + ); + + return response; + } + #endregion + #region Send message [HttpPost("/conversation/{agentId}/{conversationId}")] public async Task SendMessage([FromRoute] string agentId, diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index bf2292ea..80ee2299 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -15,6 +15,7 @@ public class ChatHubConversationHook : ConversationHookBase private const string RECEIVE_ASSISTANT_MESSAGE = "OnMessageReceivedFromAssistant"; private const string GENERATE_SENDER_ACTION = "OnSenderActionGenerated"; private const string DELETE_MESSAGE = "OnMessageDeleted"; + private const string GENERATE_NOTIFICATION = "OnNotificationGenerated"; #endregion public ChatHubConversationHook( @@ -117,6 +118,31 @@ public class ChatHubConversationHook : ConversationHookBase await base.OnResponseGenerated(message); } + + public override async Task OnNotificationGenerated(RoleDialogModel message) + { + var conv = _services.GetRequiredService(); + var json = JsonSerializer.Serialize(new ChatResponseModel() + { + ConversationId = conv.ConversationId, + MessageId = message.MessageId, + Text = !string.IsNullOrEmpty(message.SecondaryContent) ? message.SecondaryContent : message.Content, + Function = message.FunctionName, + RichContent = message.SecondaryRichContent ?? message.RichContent, + Data = message.Data, + Sender = new UserViewModel() + { + FirstName = "AI", + LastName = "Assistant", + Role = AgentRole.Assistant + } + }, _options.JsonSerializerOptions); + + await GenerateNotification(json); + await base.OnNotificationGenerated(message); + } + + public override async Task OnMessageDeleted(string conversationId, string messageId) { var model = new ChatResponseModel @@ -153,5 +179,10 @@ public class ChatHubConversationHook : ConversationHookBase { await _chatHub.Clients.User(_user.Id).SendAsync(DELETE_MESSAGE, model); } + + private async Task GenerateNotification(string? json) + { + await _chatHub.Clients.User(_user.Id).SendAsync(GENERATE_NOTIFICATION, json); + } #endregion } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/DialogMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/DialogMongoElement.cs index 5c2a1698..1179d3cd 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/DialogMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/DialogMongoElement.cs @@ -48,6 +48,7 @@ public class DialogMetaDataMongoElement public string Role { get; set; } public string AgentId { get; set; } public string MessageId { get; set; } + public string MessageType { get; set; } public string? FunctionName { get; set; } public string? SenderId { get; set; } public DateTime CreateTime { get; set; } @@ -64,6 +65,7 @@ public class DialogMetaDataMongoElement Role = meta.Role, AgentId = meta.AgentId, MessageId = meta.MessageId, + MessageType = meta.MessageType, FunctionName = meta.FunctionName, SenderId = meta.SenderId, CreateTime = meta.CreateTime, @@ -77,6 +79,7 @@ public class DialogMetaDataMongoElement Role = meta.Role, AgentId = meta.AgentId, MessageId = meta.MessageId, + MessageType = meta.MessageType, FunctionName = meta.FunctionName, SenderId = meta.SenderId, CreateTime = meta.CreateTime, From 3271ce65f7e559c601505a5a4f5d34af5dd65b9a Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 7 Oct 2024 16:42:20 -0500 Subject: [PATCH 04/13] change param name --- .../Conversations/IConversationService.cs | 2 +- .../Conversations/Services/ConversationService.cs | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index a52b9f07..7e7e372e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -41,7 +41,7 @@ public interface IConversationService PostbackMessageModel? replyMessage, Func onResponseReceived); - List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? excludeMessageTypes = null); + List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? includeMessageTypes = null); Task CleanHistory(string agentId); /// diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 40f412d9..8511b873 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -106,7 +106,7 @@ public partial class ConversationService : IConversationService throw new NotImplementedException(); } - public List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? excludeMessageTypes = null) + public List GetDialogHistory(int lastCount = 100, bool fromBreakpoint = true, IEnumerable? includeMessageTypes = null) { if (string.IsNullOrEmpty(_conversationId)) { @@ -115,9 +115,13 @@ public partial class ConversationService : IConversationService var dialogs = _storage.GetDialogs(_conversationId); - if (!excludeMessageTypes.IsNullOrEmpty()) + if (!includeMessageTypes.IsNullOrEmpty()) { - dialogs = dialogs.Where(x => !excludeMessageTypes.Contains(x.MessageType)).ToList(); + dialogs = dialogs.Where(x => string.IsNullOrEmpty(x.MessageType) || includeMessageTypes.Contains(x.MessageType)).ToList(); + } + else + { + dialogs = dialogs.Where(x => string.IsNullOrEmpty(x.MessageType) || x.MessageType.IsEqualTo(MessageTypeName.Plain)).ToList(); } if (fromBreakpoint) From e3c00490f2dc57f368f82cfea8ddb26be4e08dff Mon Sep 17 00:00:00 2001 From: Jicheng Lu Date: Mon, 7 Oct 2024 19:15:01 -0500 Subject: [PATCH 05/13] remove params --- .../Services/KnowledgeService.Document.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs index 3959f45d..01e3be07 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs @@ -73,7 +73,7 @@ public partial class KnowledgeService payload[KnowledgePayloadName.FileUrl] = file.FileUrl; } - var dataIds = await SaveToVectorDb(collectionName, fileId, file.FileName, contents, payload); + var dataIds = await SaveToVectorDb(collectionName, contents, payload); if (!dataIds.IsNullOrEmpty()) { db.SaveKnolwedgeBaseFileMeta(new KnowledgeDocMetaData @@ -145,7 +145,7 @@ public partial class KnowledgeService payload[KnowledgePayloadName.FileUrl] = refData.Url; } - var dataIds = await SaveToVectorDb(collectionName, fileId, fileName, contents, payload); + var dataIds = await SaveToVectorDb(collectionName, contents, payload); db.SaveKnolwedgeBaseFileMeta(new KnowledgeDocMetaData { Collection = collectionName, @@ -411,8 +411,7 @@ public partial class KnowledgeService return saved; } - private async Task> SaveToVectorDb( - string collectionName, Guid fileId, string fileName, IEnumerable contents, Dictionary? payload = null) + private async Task> SaveToVectorDb(string collectionName, IEnumerable contents, Dictionary? payload = null) { if (contents.IsNullOrEmpty()) { From 468f84981c202511e63ee595b1803bd99dea73ef Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Mon, 7 Oct 2024 20:20:48 -0500 Subject: [PATCH 06/13] ReadInnerHTMLAsBody option --- .../Browsing/Models/PageActionArgs.cs | 2 ++ .../PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs index d260a09d..aa4154ff 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs @@ -43,4 +43,6 @@ public class PageActionArgs /// Wait time in seconds after page is opened /// public int WaitTime { get; set; } + + public bool ReadInnerHTMLAsBody { get; set; } = false; } 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 cc1a0009..108ff433 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs @@ -67,9 +67,13 @@ public partial class PlaywrightWebDriver result.ResponseStatusCode = response.Status; if (response.Status == 200) { - // Disable this due to performance issue, some page is too large - // result.Body = await page.InnerHTMLAsync("body"); result.IsSuccess = true; + + // Be careful if page is too large, it will cause performance issue + if (args.ReadInnerHTMLAsBody) + { + result.Body = await page.InnerHTMLAsync("body"); + } } else { From f919ad7c426295981e1d77dc52df2206687a9a18 Mon Sep 17 00:00:00 2001 From: "jason.wang" Date: Tue, 8 Oct 2024 20:59:55 +0800 Subject: [PATCH 07/13] add root role --- src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs index 22a8eb95..cddabe10 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Enums/UserRole.cs @@ -33,4 +33,6 @@ public class UserRole /// AI Assistant /// public const string Assistant = "assistant"; + + public const string Root = "root"; } From 9300ec103e13d56f597e82aaf930cc8ef521dad1 Mon Sep 17 00:00:00 2001 From: Joanna Ren <101223@smsassist.com> Date: Tue, 8 Oct 2024 10:43:52 -0500 Subject: [PATCH 08/13] minor fix --- .../functions/sql_dictionary_lookup.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/sql_dictionary_lookup.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/sql_dictionary_lookup.json index 40a86c13..66abe705 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/sql_dictionary_lookup.json +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/sql_dictionary_lookup.json @@ -19,7 +19,8 @@ "type": "string", "description": "table name" } - }, + } + }, "required": [ "sql_statement", "reason", "tables" ] } } \ No newline at end of file From dce84522bf5edeca2527722707d2fcbf350b4ea8 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Tue, 8 Oct 2024 11:01:20 -0500 Subject: [PATCH 09/13] Upgrade Anthropic.SDK to v4 --- .../BotSharp.Plugin.AnthropicAI.csproj | 2 +- .../Providers/ChatCompletionProvider.cs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj b/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj index 5574afe5..c5bd88d0 100644 --- a/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj +++ b/src/Plugins/BotSharp.Plugin.AnthropicAI/BotSharp.Plugin.AnthropicAI.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs index dc9df32a..047cc246 100644 --- a/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AnthropicAI/Providers/ChatCompletionProvider.cs @@ -179,8 +179,15 @@ public class ChatCompletionProvider : IChatCompletion Model = settings.Name, Stream = false, Temperature = temperature, - SystemMessage = instruction, - Tools = new List() { } + Tools = new List() + }; + + if (!string.IsNullOrEmpty(instruction)) + { + parameters.System = new List() + { + new SystemMessage(instruction) + }; }; JsonSerializerOptions jsonSerializationOptions = new() @@ -221,7 +228,7 @@ public class ChatCompletionProvider : IChatCompletion private string GetPrompt(MessageParameters parameters) { - var prompt = $"{parameters.SystemMessage}\r\n"; + var prompt = $"{string.Join("\r\n", parameters.System.Select(x => x.Text))}\r\n"; prompt += "\r\n[CONVERSATION]"; var verbose = string.Join("\r\n", parameters.Messages @@ -264,7 +271,7 @@ public class ChatCompletionProvider : IChatCompletion { var functions = string.Join("\r\n", parameters.Tools.Select(x => { - return $"\r\n{x.Name}: {x.Description}\r\n{JsonSerializer.Serialize(x.Parameters)}"; + return $"\r\n{x.Function.Name}: {x.Function.Description}\r\n{JsonSerializer.Serialize(x.Function.Parameters)}"; })); prompt += $"\r\n[FUNCTIONS]\r\n{functions}\r\n"; } From b81e162bf4dd32b50bfe1297bf88410395688743 Mon Sep 17 00:00:00 2001 From: Haiping Date: Tue, 8 Oct 2024 16:49:34 +0000 Subject: [PATCH 10/13] Add template_name to states for instruction mode --- .../BotSharp.OpenAPI/Controllers/InstructModeController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index bc02e846..61862781 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -29,7 +29,8 @@ public class InstructModeController : ControllerBase .SetState("model", input.Model, source: StateSource.External) .SetState("model_id", input.ModelId, source: StateSource.External) .SetState("instruction", input.Instruction, source: StateSource.External) - .SetState("input_text", input.Text,source: StateSource.External); + .SetState("input_text", input.Text, source: StateSource.External) + .SetState("template_name", input.Template, source: StateSource.External); var instructor = _services.GetRequiredService(); var result = await instructor.Execute(agentId, From edc0df0f46ec35e6dd648f0af8737c70a6745778 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Tue, 8 Oct 2024 19:22:00 -0500 Subject: [PATCH 11/13] translate long text --- .../Models/TranslationRequestModel.cs | 14 +++- .../Controllers/TranslationController.cs | 74 ++++++++++++++++++- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationRequestModel.cs b/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationRequestModel.cs index 588dedfc..d3d6a453 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationRequestModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Translation/Models/TranslationRequestModel.cs @@ -1,5 +1,3 @@ -using BotSharp.Abstraction.Infrastructures.Enums; - namespace BotSharp.OpenAPI.ViewModels.Translations; public class TranslationRequestModel @@ -7,3 +5,15 @@ public class TranslationRequestModel public string Text { get; set; } = null!; public string ToLang { get; set; } = LanguageType.CHINESE; } + +public class TranslationScriptTimestamp +{ + public string Text { set; get; } = null!; + public string Timestamp { get; set; } = null!; +} + +public class TranslationLongTextRequestModel +{ + public TranslationScriptTimestamp[] Texts { get; set; } = null!; + public string ToLang { get; set; } = LanguageType.CHINESE; +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs index ac7686a1..17e9ff53 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs @@ -1,4 +1,4 @@ -using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Options; using BotSharp.Abstraction.Translation; using BotSharp.OpenAPI.ViewModels.Translations; @@ -9,10 +9,13 @@ namespace BotSharp.OpenAPI.Controllers; public class TranslationController : ControllerBase { private readonly IServiceProvider _services; + private readonly JsonSerializerOptions _jsonOptions; - public TranslationController(IServiceProvider services) + public TranslationController(IServiceProvider services, + BotSharpOptions options) { _services = services; + _jsonOptions = InitJsonOptions(options); } [HttpPost("/translate")] @@ -27,4 +30,71 @@ public class TranslationController : ControllerBase Text = text }; } + + [HttpPost("/translate/long-text")] + public async Task SendMessageSse([FromBody] TranslationLongTextRequestModel model) + { + var agentService = _services.GetRequiredService(); + var agent = await agentService.LoadAgent(BuiltInAgentId.AIAssistant); + var translator = _services.GetRequiredService(); + + Response.StatusCode = 200; + Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "text/event-stream"); + Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.CacheControl, "no-cache"); + Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.Connection, "keep-alive"); + + foreach (var script in model.Texts) + { + var translatedText = await translator.Translate(agent, Guid.NewGuid().ToString(), script.Text, language: model.ToLang); + + var json = JsonSerializer.Serialize(new TranslationScriptTimestamp + { + Text = translatedText, + Timestamp = script.Timestamp + }, _jsonOptions); + + await OnChunkReceived(Response, json); + } + + await OnEventCompleted(Response); + } + + private async Task OnChunkReceived(HttpResponse response, string text) + { + var buffer = Encoding.UTF8.GetBytes($"data:{text}\n"); + await response.Body.WriteAsync(buffer, 0, buffer.Length); + await Task.Delay(10); + + buffer = Encoding.UTF8.GetBytes("\n"); + await response.Body.WriteAsync(buffer, 0, buffer.Length); + } + + private async Task OnEventCompleted(HttpResponse response) + { + var buffer = Encoding.UTF8.GetBytes("data:[DONE]\n"); + await response.Body.WriteAsync(buffer, 0, buffer.Length); + + 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 76aa397e99528e83e4959804b0e5c3b076067b68 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 10 Oct 2024 12:55:44 -0500 Subject: [PATCH 12/13] add processor --- .../Knowledges/IKnowledgeService.cs | 3 +- .../Processors/IBaseProcessor.cs | 12 ++++++++ .../Processors/Models/LlmBaseRequest.cs | 9 ++++++ .../BotSharp.Core/BotSharp.Core.csproj | 2 +- .../BotSharp.Core/BotSharpCoreExtensions.cs | 2 ++ .../ConversationService.SendMessage.cs | 15 ++++++++++ .../Processors/ProcessorFactory.cs | 29 +++++++++++++++++++ .../Hooks/ChatHubConversationHook.cs | 1 + .../BotSharp.Plugin.KnowledgeBase.csproj | 2 +- .../Services/KnowledgeService.Document.cs | 24 +++++++++------ 10 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Processors/IBaseProcessor.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Processors/Models/LlmBaseRequest.cs create mode 100644 src/Infrastructure/BotSharp.Core/Processors/ProcessorFactory.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs index 0b1c06b5..2313b2ba 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs @@ -40,7 +40,8 @@ public interface IKnowledgeService /// /// /// - Task ImportDocumentContentToKnowledge(string collectionName, string fileName, string fileSource, IEnumerable contents, DocMetaRefData? refData = null); + Task ImportDocumentContentToKnowledge(string collectionName, string fileName, string fileSource, IEnumerable contents, + DocMetaRefData? refData = null, Dictionary? payload = null); /// /// Delete one document and its related knowledge in the collection /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Processors/IBaseProcessor.cs b/src/Infrastructure/BotSharp.Abstraction/Processors/IBaseProcessor.cs new file mode 100644 index 00000000..f8899c51 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Processors/IBaseProcessor.cs @@ -0,0 +1,12 @@ +using BotSharp.Abstraction.Processors.Models; + +namespace BotSharp.Abstraction.Processors; + +public interface IBaseProcessor where TInput : LlmBaseRequest where TOutput : class +{ + string Provider { get; } + string Name => string.Empty; + int Order { get; } + + Task Execute(TInput input); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Processors/Models/LlmBaseRequest.cs b/src/Infrastructure/BotSharp.Abstraction/Processors/Models/LlmBaseRequest.cs new file mode 100644 index 00000000..d14a234b --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Processors/Models/LlmBaseRequest.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Abstraction.Processors.Models; + +public class LlmBaseRequest +{ + public string Provider { get; set; } + public string Model { get; set; } + public string? AgentId { get; set; } + public string? TemplateName { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 99f8b6ae..90ac40e8 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -1,4 +1,4 @@ - + $(TargetFramework) diff --git a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs index 26a5ccb5..4bdfe0d7 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpCoreExtensions.cs @@ -8,6 +8,7 @@ using BotSharp.Abstraction.Messaging.JsonConverters; using BotSharp.Abstraction.Users.Settings; using BotSharp.Abstraction.Interpreters.Settings; using BotSharp.Abstraction.Infrastructures; +using BotSharp.Core.Processors; namespace BotSharp.Core; @@ -23,6 +24,7 @@ public static class BotSharpCoreExtensions services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddSingleton(); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 610c1ab4..59ce88c2 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -46,6 +46,7 @@ public partial class ConversationService } // Before chat completion hook + hooks = ReOrderConversationHooks(hooks); foreach (var hook in hooks) { hook.SetAgent(agent) @@ -173,4 +174,18 @@ public partial class ConversationService // Add to dialog history _storage.Append(_conversationId, response); } + + private List ReOrderConversationHooks(List hooks) + { + var target = "ChatHubConversationHook"; + var chathub = hooks.FirstOrDefault(x => x.GetType().Name == target); + var otherHooks = hooks.Where(x => x.GetType().Name != target).ToList(); + + if (chathub != null) + { + var newHooks = new List { chathub }.Concat(otherHooks); + return newHooks.ToList(); + } + return hooks; + } } diff --git a/src/Infrastructure/BotSharp.Core/Processors/ProcessorFactory.cs b/src/Infrastructure/BotSharp.Core/Processors/ProcessorFactory.cs new file mode 100644 index 00000000..f78bb559 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Processors/ProcessorFactory.cs @@ -0,0 +1,29 @@ +using BotSharp.Abstraction.Processors; +using BotSharp.Abstraction.Processors.Models; + +namespace BotSharp.Core.Processors; + +public class ProcessorFactory +{ + private readonly IServiceProvider _services; + + public ProcessorFactory(IServiceProvider services) + { + _services = services; + } + + public IEnumerable> Create(string provider) + where TInput : LlmBaseRequest where TOutput : class + { + var processors = _services.GetServices>(); + processors = processors.Where(x => x.Provider == provider); + return processors.OrderBy(x => x.Order); + } + + public IBaseProcessor? Create(string provider, string name) + where TInput : LlmBaseRequest where TOutput : class + { + var processors = _services.GetServices>(); + return processors.FirstOrDefault(x => x.Provider == provider && x.Name == name); + } +} diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index 80ee2299..29c6df82 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -54,6 +54,7 @@ public class ChatHubConversationHook : ConversationHookBase { ConversationId = conv.ConversationId, MessageId = message.MessageId, + Payload = message.Payload, Text = !string.IsNullOrEmpty(message.SecondaryContent) ? message.SecondaryContent : message.Content, Sender = UserViewModel.FromUser(sender) }; diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj index 29c81ec7..42663445 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj @@ -1,4 +1,4 @@ - + $(TargetFramework) diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs index 01e3be07..dd7e0d1a 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Document.cs @@ -112,7 +112,7 @@ public partial class KnowledgeService public async Task ImportDocumentContentToKnowledge(string collectionName, string fileName, string fileSource, - IEnumerable contents, DocMetaRefData? refData = null) + IEnumerable contents, DocMetaRefData? refData = null, Dictionary? payload = null) { if (string.IsNullOrWhiteSpace(collectionName) || string.IsNullOrWhiteSpace(fileName) @@ -132,20 +132,26 @@ public partial class KnowledgeService var fileId = Guid.NewGuid(); var contentType = FileUtility.GetFileContentType(fileName); - var payload = new Dictionary() + var innerPayload = new Dictionary(); + if (payload != null) { - { KnowledgePayloadName.DataSource, VectorDataSource.File }, - { KnowledgePayloadName.FileId, fileId.ToString() }, - { KnowledgePayloadName.FileName, fileName }, - { KnowledgePayloadName.FileSource, fileSource } - }; + foreach (var item in payload) + { + innerPayload[item.Key] = item.Value; + } + } + + innerPayload[KnowledgePayloadName.DataSource] = VectorDataSource.File; + innerPayload[KnowledgePayloadName.FileId] = fileId.ToString(); + innerPayload[KnowledgePayloadName.FileName] = fileName; + innerPayload[KnowledgePayloadName.FileSource] = fileSource; if (!string.IsNullOrWhiteSpace(refData?.Url)) { - payload[KnowledgePayloadName.FileUrl] = refData.Url; + innerPayload[KnowledgePayloadName.FileUrl] = refData.Url; } - var dataIds = await SaveToVectorDb(collectionName, contents, payload); + var dataIds = await SaveToVectorDb(collectionName, contents, innerPayload); db.SaveKnolwedgeBaseFileMeta(new KnowledgeDocMetaData { Collection = collectionName, From 730cc8b143cf8260acde461a4d4ebb080309c289 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Thu, 10 Oct 2024 19:32:22 -0500 Subject: [PATCH 13/13] Translate --- .../Translation/TranslationService.cs | 10 +++++++--- .../templates/translation_prompt.liquid | 17 +++++++++++++++-- .../Controllers/TranslationController.cs | 6 ++++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs index f9aa73e3..453b2277 100644 --- a/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs +++ b/src/Infrastructure/BotSharp.Core/Translation/TranslationService.cs @@ -101,12 +101,12 @@ public class TranslationService : ITranslationService { var translatedStringList = await InnerTranslate(texts, language, template); - int retry = 0; + /*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(); @@ -119,7 +119,7 @@ public class TranslationService : ITranslationService var translatedTexts = translatedStringList.Texts; var memoryInputs = new List(); - for (var i = 0; i < texts.Count; i++) + for (var i = 0; i < Math.Min(texts.Count, translatedTexts.Length); i++) { map[outOfMemoryList[i].OriginalText] = translatedTexts[i].Text; memoryInputs.Add(new TranslationMemoryInput @@ -375,6 +375,8 @@ public class TranslationService : ITranslationService var render = _services.GetRequiredService(); var prompt = render.Render(template, translator.TemplateDict); + _logger.LogInformation($"Translation prompt: {prompt}"); + var translationDialogs = new List { new RoleDialogModel(AgentRole.User, prompt) @@ -384,6 +386,8 @@ public class TranslationService : ITranslationService } }; var response = await _completion.GetChatCompletions(translator, translationDialogs); + + _logger.LogInformation(response.Content); return response.Content.JsonContent(); } 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 6b3a8677..fd67a5fd 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 @@ -1,6 +1,19 @@ {{ text_list }} ===== +{% if language == "Chinese" %} +将以上所有句子翻译成中文。 + +要求: +* 以 JSON 格式输出翻译后的文本 {"input_lang":"原始文本语言", "output_count": {{ text_list_size }}, "output_lang":"{{ language }}", "texts":[{"id": 1, "text":""},{"id": 2, "text":""}]}。 +* output_count 必须等于输出中texts数组的长度。 +{% else %} 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":""},{"id": 2, "text":""}]}. -The "output_count" must equal the length of the "texts" array in the output. + +Requirements: +* 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. +{% endif %} + + + diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs index 17e9ff53..7845e8cf 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs @@ -24,10 +24,12 @@ public class TranslationController : ControllerBase var agentService = _services.GetRequiredService(); var agent = await agentService.LoadAgent(BuiltInAgentId.AIAssistant); var translator = _services.GetRequiredService(); - var text = await translator.Translate(agent, Guid.NewGuid().ToString(), model.Text, language: model.ToLang); + var states = _services.GetRequiredService(); + states.SetState("max_tokens", "8192"); + var text = await translator.Translate(agent, Guid.NewGuid().ToString(), model.Text.Split("\r\n"), language: model.ToLang); return new TranslationResponseModel { - Text = text + Text = string.Join("\r\n", text) }; }