Merge branch 'SciSharp:master' into master

This commit is contained in:
Haiping 2024-10-11 20:19:37 -05:00 committed by GitHub
commit 6ae74a4dc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 144 additions and 17 deletions

View file

@ -12,6 +12,7 @@ public interface IConversationService
Task<Conversation> GetConversation(string id);
Task<PagedItems<Conversation>> GetConversations(ConversationFilter filter);
Task<Conversation> UpdateConversationTitle(string id, string title);
Task<bool> UpdateConversationMessage(string conversationId, UpdateMessageRequest request);
Task<List<Conversation>> GetLastConversations();
Task<List<string>> GetIdleConversations(int batchSize, int messageLimit, int bufferHours, IEnumerable<string> excludeAgentIds);
Task<bool> DeleteConversations(IEnumerable<string> ids);

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Conversations.Models;
public class UpdateMessageRequest
{
public DialogElement Message { get; set; } = null!;
public int InnderIndex { get; set; }
}

View file

@ -5,6 +5,6 @@ public class InstructResult : ITrackableMessage
[JsonPropertyName("message_id")]
public string MessageId { get; set; }
public string Text { get; set; }
public object Data { get; set; }
public Dictionary<string, string> States { get; set; }
public object? Data { get; set; }
public Dictionary<string, string>? States { get; set; } = new();
}

View file

@ -72,6 +72,7 @@ public interface IBotSharpRepository
Conversation GetConversation(string conversationId);
PagedItems<Conversation> GetConversations(ConversationFilter filter);
void UpdateConversationTitle(string conversationId, string title);
bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request);
void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint);
ConversationBreakpoint? GetConversationBreakpoint(string conversationId);
List<Conversation> GetLastConversations();

View file

@ -50,6 +50,13 @@ public partial class ConversationService : IConversationService
var conversation = db.GetConversation(id);
return conversation;
}
public async Task<bool> UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
return db.UpdateConversationMessage(conversationId, request);
}
public async Task<Conversation> GetConversation(string id)
{
var db = _services.GetRequiredService<IBotSharpRepository>();

View file

@ -156,22 +156,25 @@ public class BotSharpDbContext : Database, IBotSharpRepository
=> throw new NotImplementedException();
public void AppendConversationDialogs(string conversationId, List<DialogElement> dialogs)
=> new NotImplementedException();
=> throw new NotImplementedException();
public void UpdateConversationTitle(string conversationId, string title)
=> new NotImplementedException();
=> throw new NotImplementedException();
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
=> throw new NotImplementedException();
public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint)
=> new NotImplementedException();
=> throw new NotImplementedException();
public ConversationBreakpoint? GetConversationBreakpoint(string conversationId)
=> throw new NotImplementedException();
public void UpdateConversationStates(string conversationId, List<StateKeyValue> states)
=> new NotImplementedException();
=> throw new NotImplementedException();
public void UpdateConversationStatus(string conversationId, string status)
=> new NotImplementedException();
=> throw new NotImplementedException();
public IEnumerable<string> TruncateConversation(string conversationId, string messageId, bool cleanLog = false)
=> throw new NotImplementedException();

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Repositories.Models;
using System.Globalization;
using System.IO;
using System.Xml.Linq;
namespace BotSharp.Core.Repository
{
@ -133,6 +134,38 @@ namespace BotSharp.Core.Repository
}
}
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
if (string.IsNullOrEmpty(conversationId)) return false;
var dialogs = GetConversationDialogs(conversationId);
var candidates = dialogs.Where(x => x.MetaData.MessageId == request.Message.MetaData.MessageId
&& x.MetaData.Role == request.Message.MetaData.Role).ToList();
var found = candidates.Where((_, idx) => idx == request.InnderIndex).FirstOrDefault();
if (found == null) return false;
found.Content = request.Message.Content;
found.RichContent = request.Message.RichContent;
if (!string.IsNullOrEmpty(found.SecondaryContent))
{
found.SecondaryContent = request.Message.Content;
}
if (!string.IsNullOrEmpty(found.SecondaryRichContent))
{
found.SecondaryRichContent = request.Message.RichContent;
}
var convDir = FindConversationDirectory(conversationId);
if (string.IsNullOrEmpty(convDir)) return false;
var dialogFile = Path.Combine(convDir, DIALOG_FILE);
File.WriteAllText(dialogFile, JsonSerializer.Serialize(dialogs, _options));
return true;
}
public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint)
{
var convDir = FindConversationDirectory(conversationId);

View file

@ -221,6 +221,29 @@ public class ConversationController : ControllerBase
return response != null;
}
[HttpPut("/conversation/{conversationId}/update-message")]
public async Task<bool> UpdateConversationMessage([FromRoute] string conversationId, [FromBody] UpdateMessageModel model)
{
var conversationService = _services.GetRequiredService<IConversationService>();
var request = new UpdateMessageRequest
{
Message = new DialogElement
{
MetaData = new DialogMetaData
{
MessageId = model.Message.MessageId,
Role = model.Message.Sender?.Role
},
Content = model.Message.Text,
RichContent = JsonSerializer.Serialize(model.Message.RichContent, _jsonOptions),
},
InnderIndex = model.InnerIndex
};
return await conversationService.UpdateConversationMessage(conversationId, request);
}
[HttpDelete("/conversation/{conversationId}")]
public async Task<bool> DeleteConversation([FromRoute] string conversationId)
{

View file

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace BotSharp.OpenAPI.ViewModels.Conversations;
public class UpdateMessageModel
{
[JsonPropertyName("message")]
public ChatResponseModel Message { get; set; } = null!;
[JsonPropertyName("inner_index")]
public int InnerIndex { get; set; }
}

View file

@ -5,11 +5,11 @@ namespace BotSharp.OpenAPI.ViewModels.Users;
public class UserViewModel
{
public string Id { get; set; } = null!;
public string Id { get; set; } = string.Empty;
[JsonPropertyName("user_name")]
public string UserName { get; set; } = null!;
public string UserName { get; set; } = string.Empty;
[JsonPropertyName("first_name")]
public string FirstName { get; set; } = null!;
public string FirstName { get; set; } = string.Empty;
[JsonPropertyName("last_name")]
public string? LastName { get; set; }
public string? Email { get; set; }
@ -18,7 +18,7 @@ public class UserViewModel
public string Role { get; set; } = UserRole.User;
[JsonPropertyName("full_name")]
public string FullName => $"{FirstName} {LastName}".Trim();
public string Source { get; set; }
public string? Source { get; set; }
[JsonPropertyName("external_id")]
public string? ExternalId { get; set; }
public string Avatar { get; set; } = "/user/avatar";

View file

@ -41,13 +41,22 @@ public class WelcomeHook : ConversationHookBase
});
var richContentService = _services.GetRequiredService<IRichContentService>();
var messages = richContentService.ConvertToMessages(content);
var guid = Guid.NewGuid().ToString();
foreach (var message in messages)
{
var richContent = new RichContent<IRichMessage>(message);
var dialog = new RoleDialogModel(AgentRole.Assistant, message.Text)
{
MessageId = guid,
CurrentAgentId = agent.Id,
RichContent = richContent
};
var json = JsonSerializer.Serialize(new ChatResponseModel()
{
ConversationId = conversation.Id,
MessageId = dialog.MessageId,
Text = message.Text,
RichContent = richContent,
Sender = new UserViewModel()
@ -60,12 +69,7 @@ public class WelcomeHook : ConversationHookBase
await Task.Delay(300);
_storage.Append(conversation.Id, new RoleDialogModel(AgentRole.Assistant, message.Text)
{
MessageId = conversation.Id,
CurrentAgentId = agent.Id,
RichContent = richContent
});
_storage.Append(conversation.Id, dialog);
await _chatHub.Clients.User(_user.Id).SendAsync("OnMessageReceivedFromAssistant", json);
}

View file

@ -108,6 +108,42 @@ public partial class MongoRepository
_dc.Conversations.UpdateOne(filterConv, updateConv);
}
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
if (string.IsNullOrEmpty(conversationId)) return false;
var filter = Builders<ConversationDialogDocument>.Filter.Eq(x => x.ConversationId, conversationId);
var foundDialog = _dc.ConversationDialogs.Find(filter).FirstOrDefault();
if (foundDialog == null || foundDialog.Dialogs.IsNullOrEmpty())
{
return false;
}
var dialogs = foundDialog.Dialogs;
var candidates = dialogs.Where(x => x.MetaData.MessageId == request.Message.MetaData.MessageId
&& x.MetaData.Role == request.Message.MetaData.Role).ToList();
var found = candidates.Where((_, idx) => idx == request.InnderIndex).FirstOrDefault();
if (found == null) return false;
found.Content = request.Message.Content;
found.RichContent = request.Message.RichContent;
if (!string.IsNullOrEmpty(found.SecondaryContent))
{
found.SecondaryContent = request.Message.Content;
}
if (!string.IsNullOrEmpty(found.SecondaryRichContent))
{
found.SecondaryRichContent = request.Message.RichContent;
}
var update = Builders<ConversationDialogDocument>.Update.Set(x => x.Dialogs, dialogs);
_dc.ConversationDialogs.UpdateOne(filter, update);
return true;
}
public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint)
{
if (string.IsNullOrEmpty(conversationId)) return;