diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index c8b997ec..8434359e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -56,4 +56,6 @@ public interface IConversationService Task UpdateBreakpoint(bool resetStates = false, string? reason = null, params string[] excludedStates); Task GetConversationSummary(IEnumerable conversationId); + + Task GetConversationRecordOrCreateNew(string agentId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs index cd4aad61..294fab04 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/IncomingMessageModel.cs @@ -5,6 +5,9 @@ public class IncomingMessageModel : MessageConfig public string Text { get; set; } = string.Empty; public virtual string Channel { get; set; } = string.Empty; + [JsonPropertyName("input_message_id")] + public string? InputMessageId { get; set; } + /// /// Postback message /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs index 088697cd..a08a5770 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/TruncateMessageRequest.cs @@ -2,5 +2,6 @@ namespace BotSharp.Abstraction.Conversations.Models; public class TruncateMessageRequest { - public string? TruncateMessageId { get; set; } + [JsonPropertyName("is_new_message")] + public bool isNewMessage { get; set; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs index 7df09b5e..357a13aa 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs @@ -1,6 +1,6 @@ namespace BotSharp.Abstraction.Models; -public class MessageConfig : TruncateMessageRequest +public class MessageConfig { /// /// Completion Provider diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 3489d260..045a1275 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -14,13 +14,7 @@ public partial class ConversationService Func onFunctionExecuting, Func onFunctionExecuted) { - var conversation = await GetConversationRecord(agentId); - - // Save message files - var fileService = _services.GetRequiredService(); - fileService.SaveMessageFiles(_conversationId, message.MessageId, FileSourceType.User, message.Files); - message.Files?.Clear(); - + var conversation = await GetConversationRecordOrCreateNew(agentId); var agentService = _services.GetRequiredService(); Agent agent = await agentService.LoadAgent(agentId); @@ -99,27 +93,6 @@ public partial class ConversationService return true; } - private async Task GetConversationRecord(string agentId) - { - var converation = await GetConversation(_conversationId); - - // Create conversation if this conversation does not exist - if (converation == null) - { - var state = _services.GetRequiredService(); - var channel = state.GetState("channel"); - var sess = new Conversation - { - Id = _conversationId, - Channel = channel, - AgentId = agentId - }; - converation = await NewConversation(sess); - } - - return converation; - } - private async Task HandleAssistantMessage(RoleDialogModel response, Func onResponseReceived) { var agentService = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 8e113226..5142133a 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -140,4 +140,25 @@ public partial class ConversationService : IConversationService _state.Load(_conversationId); states.ForEach(x => _state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External)); } + + public async Task GetConversationRecordOrCreateNew(string agentId) + { + var converation = await GetConversation(_conversationId); + + // Create conversation if this conversation does not exist + if (converation == null) + { + var state = _services.GetRequiredService(); + var channel = state.GetState("channel"); + var sess = new Conversation + { + Id = _conversationId, + Channel = channel, + AgentId = agentId + }; + converation = await NewConversation(sess); + } + + return converation; + } } diff --git a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs index 99c42999..61e12145 100644 --- a/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Files/BotSharpFileService.Conversation.cs @@ -230,7 +230,6 @@ public partial class BotSharpFileService using var fs = new FileStream(Path.Combine(subDir, file.FileName), FileMode.Create); fs.Write(bytes, 0, bytes.Length); fs.Flush(true); - Thread.Sleep(2000); } return true; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index cd0e4c37..aea3bf34 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Files.Enums; using BotSharp.Abstraction.Options; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Users.Enums; @@ -142,7 +143,7 @@ public class ConversationController : ControllerBase { return null; } - + var result = ConversationViewModel.FromSession(conversations.Items.First()); var state = _services.GetRequiredService(); result.States = state.Load(conversationId, isReadOnly: true); @@ -211,11 +212,12 @@ public class ConversationController : ControllerBase } [HttpDelete("/conversation/{conversationId}/message/{messageId}")] - public async Task DeleteConversationMessage([FromRoute] string conversationId, [FromRoute] string messageId) + public async Task DeleteConversationMessage([FromRoute] string conversationId, [FromRoute] string messageId, [FromBody] TruncateMessageRequest request) { var conversationService = _services.GetRequiredService(); - var response = await conversationService.TruncateConversation(conversationId, messageId); - return response; + var newMessageId = request.isNewMessage ? Guid.NewGuid().ToString() : null; + var isSuccess = await conversationService.TruncateConversation(conversationId, messageId, newMessageId); + return isSuccess ? newMessageId : string.Empty; } #region Send message @@ -227,15 +229,10 @@ public class ConversationController : ControllerBase var conv = _services.GetRequiredService(); var inputMsg = new RoleDialogModel(AgentRole.User, input.Text) { - Files = input.Files, + MessageId = !string.IsNullOrWhiteSpace(input.InputMessageId) ? input.InputMessageId : Guid.NewGuid().ToString(), CreatedAt = DateTime.UtcNow }; - if (!string.IsNullOrEmpty(input.TruncateMessageId)) - { - await conv.TruncateConversation(conversationId, input.TruncateMessageId, inputMsg.MessageId); - } - var routing = _services.GetRequiredService(); routing.Context.SetMessageId(conversationId, inputMsg.MessageId); @@ -243,7 +240,7 @@ public class ConversationController : ControllerBase SetStates(conv, input); var response = new ChatResponseModel(); - + await conv.SendMessage(agentId, inputMsg, replyMessage: input.Postback, async msg => @@ -273,15 +270,10 @@ public class ConversationController : ControllerBase var conv = _services.GetRequiredService(); var inputMsg = new RoleDialogModel(AgentRole.User, input.Text) { - Files = input.Files, + MessageId = !string.IsNullOrWhiteSpace(input.InputMessageId) ? input.InputMessageId : Guid.NewGuid().ToString(), CreatedAt = DateTime.UtcNow }; - if (!string.IsNullOrEmpty(input.TruncateMessageId)) - { - await conv.TruncateConversation(conversationId, input.TruncateMessageId, inputMsg.MessageId); - } - var state = _services.GetRequiredService(); var routing = _services.GetRequiredService(); @@ -322,7 +314,7 @@ public class ConversationController : ControllerBase { ConversationId = conversationId, MessageId = msg.MessageId, - Text = msg.Indication, + Text = msg.Indication, Function = "indicating", Instruction = msg.Instruction, States = new Dictionary() @@ -370,8 +362,20 @@ public class ConversationController : ControllerBase return BadRequest(new { message = "Invalid file." }); } + [HttpPost("/agent/{agentId}/conversation/{conversationId}/upload")] + public async Task UploadConversationMessageFiles([FromRoute] string agentId, [FromRoute] string conversationId, [FromBody] NewMessageModel input) + { + var convService = _services.GetRequiredService(); + convService.SetConversationId(conversationId, input.States); + var conv = await convService.GetConversationRecordOrCreateNew(agentId); + var fileService = _services.GetRequiredService(); + var messageId = Guid.NewGuid().ToString(); + var isSaved = fileService.SaveMessageFiles(conv.Id, messageId, FileSourceType.User, input.Files); + return isSaved ? messageId : string.Empty; + } + [HttpGet("/conversation/{conversationId}/files/{messageId}/{source}")] - public IEnumerable GetMessageFiles([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string source) + public IEnumerable GetConversationMessageFiles([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string source) { var fileService = _services.GetRequiredService(); var files = fileService.GetMessageFiles(conversationId, new List { messageId }, source, imageOnly: false);