diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index 804e21ef..4664d4e7 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -15,7 +15,15 @@ public class RoleDialogModel : ITrackableMessage /// user, system, assistant, function /// public string Role { get; set; } + + /// + /// User id when Role is User + /// + public string SenderId { get; set; } + + [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public string Content { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs index c1d702ac..3b9c0a0f 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs @@ -21,9 +21,22 @@ public static class StringExtensions public static string[] SplitByNewLine(this string input) { + if (input == null) + { + return new string[0]; + } return input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); } + public static string RemoveNewLine(this string input) + { + if (input == null) + { + return null; + } + return input.Replace("\r", " ").Replace("\n", " ").Trim(); + } + public static bool IsEqualTo(this string str1, string str2, StringComparison option = StringComparison.OrdinalIgnoreCase) { return str1.Equals(str2, option); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index f67307c4..704e317b 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -28,6 +28,7 @@ public partial class ConversationService #endif message.CurrentAgentId = agent.Id; + message.SenderId = _user.Id; _storage.Append(_conversationId, message); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 92022dca..f2c7e298 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -1,6 +1,5 @@ using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Users.Enums; -using BotSharp.Abstraction.Users.Models; namespace BotSharp.Core.Conversations.Services; @@ -82,6 +81,11 @@ public partial class ConversationService : IConversationService public List GetDialogHistory(int lastCount = 50) { + if (string.IsNullOrEmpty(_conversationId)) + { + throw new ArgumentNullException("ConversationId is null."); + } + var dialogs = _storage.GetDialogs(_conversationId); return dialogs .Where(x => x.CreatedAt > DateTime.UtcNow.AddHours(-24)) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 3d8b3085..2912979d 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -24,12 +24,12 @@ public class ConversationStorage : IConversationStorage if (dialog.Role == AgentRole.Function) { - var args = dialog.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim(); + // var args = dialog.FunctionArgs.RemoveNewLine(); - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}|{agentId}"); var content = dialog.Content; - content = content.Replace("\r", " ").Replace("\n", " ").Trim(); + content = content.RemoveNewLine(); if (string.IsNullOrEmpty(content)) { return; @@ -38,8 +38,8 @@ public class ConversationStorage : IConversationStorage } else { - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}"); - var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{dialog.MessageId}|{dialog.SenderId}"); + var content = dialog.Content.RemoveNewLine(); if (string.IsNullOrEmpty(content)) { return; @@ -62,10 +62,12 @@ public class ConversationStorage : IConversationStorage { var meta = dialogs[i]; var dialog = dialogs[i + 1]; - var createdAt = DateTime.Parse(meta.Split('|')[0]); - var role = meta.Split('|')[1]; - var currentAgentId = meta.Split('|')[2]; - var messageId = meta.Split('|')[3]; + var blocks = meta.Split('|'); + var createdAt = DateTime.Parse(blocks[0]); + var role = blocks[1]; + var currentAgentId = blocks[2]; + var messageId = blocks[3]; + var senderId = blocks[4]; var text = dialog.Substring(4); results.Add(new RoleDialogModel(role, text) @@ -73,7 +75,8 @@ public class ConversationStorage : IConversationStorage CurrentAgentId = currentAgentId, MessageId = messageId, Content = text, - CreatedAt = createdAt + CreatedAt = createdAt, + SenderId = senderId, }); } return results; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 7ef15481..ba7107cd 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -4,6 +4,7 @@ using BotSharp.Abstraction.Models; using BotSharp.OpenAPI.ViewModels.Conversations; using BotSharp.OpenAPI.ViewModels.Users; using Microsoft.AspNetCore.Http; +using Microsoft.VisualBasic; using System.Net.Http.Headers; namespace BotSharp.OpenAPI.Controllers; @@ -65,8 +66,35 @@ public class ConversationController : ControllerBase, IApiAdapter return list; } - [HttpDelete("/conversation/{agentId}/{conversationId}")] - public async Task DeleteConversation([FromRoute] string agentId, [FromRoute] string conversationId) + [HttpGet("/conversation/{conversationId}/dialogs")] + public async Task> GetDialogs([FromRoute] string conversationId) + { + var conv = _services.GetRequiredService(); + conv.SetConversationId(conversationId, new List()); + var history = conv.GetDialogHistory(); + + var userService = _services.GetRequiredService(); + + var dialogs = new List(); + foreach (var message in history) + { + var user = await userService.GetUser(message.SenderId); + + dialogs.Add(new ChatResponseModel + { + ConversationId = conversationId, + MessageId = message.MessageId, + CreatedAt = message.CreatedAt, + Text = message.Content, + Sender = UserViewModel.FromUser(user) + }); + } + + return dialogs; + } + + [HttpDelete("/conversation/{conversationId}")] + public async Task DeleteConversation([FromRoute] string conversationId) { var service = _services.GetRequiredService(); } @@ -107,13 +135,13 @@ public class ConversationController : ControllerBase, IApiAdapter var state = _services.GetRequiredService(); response.States = state.GetStates(); response.MessageId = inputMsg.MessageId; + response.ConversationId = conversationId; return response; } - [HttpPost("/conversation/{agentId}/{conversationId}/attachments")] - public IActionResult UploadAttachments([FromRoute] string agentId, - [FromRoute] string conversationId, + [HttpPost("/conversation/{conversationId}/attachments")] + public IActionResult UploadAttachments([FromRoute] string conversationId, IFormFile[] files) { if (files != null && files.Length > 0) diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ChatResponseModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ChatResponseModel.cs index af85fd24..6fda2ade 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ChatResponseModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ChatResponseModel.cs @@ -27,5 +27,6 @@ public class ChatResponseModel : InstructResult [JsonPropertyName("rich_content")] public object? RichContent { get; set; } + [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } = DateTime.UtcNow; } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs index a2dbf5bf..4e15091d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs @@ -1,16 +1,19 @@ using BotSharp.Abstraction.Users.Enums; using BotSharp.Abstraction.Users.Models; +using System.Text.Json.Serialization; namespace BotSharp.OpenAPI.ViewModels.Users; public class UserViewModel { public string Id { get; set; } + [JsonPropertyName("first_name")] public string FirstName { get; set; } + [JsonPropertyName("last_name")] public string LastName { get; set; } public string Email { get; set; } public string Role { get; set; } = UserRole.Client; - + [JsonPropertyName("full_name")] public string FullName => $"{FirstName} {LastName}"; public static UserViewModel FromUser(User user)