Skip to content

Commit 3513eab

Browse files
authored
Merge pull request #315 from iceljc/features/save-rich-content-in-dialog
Features/save rich content in dialog
2 parents f16e50c + 0d23f06 commit 3513eab

File tree

12 files changed

+126
-45
lines changed

12 files changed

+126
-45
lines changed

src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,24 @@ public class Conversation
3030

3131
public class DialogElement
3232
{
33-
public DialogMeta MetaData { get; set; }
33+
public DialogMetaData MetaData { get; set; }
3434
public string Content { get; set; }
35+
public string? RichContent { get; set; }
3536

3637
public DialogElement()
3738
{
3839

3940
}
4041

41-
public DialogElement(DialogMeta meta, string content)
42+
public DialogElement(DialogMetaData meta, string content, string? richContent = null)
4243
{
4344
MetaData = meta;
4445
Content = content;
46+
RichContent = richContent;
4547
}
4648
}
4749

48-
public class DialogMeta
50+
public class DialogMetaData
4951
{
5052
public string Role { get; set; }
5153
public string AgentId { get; set; }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace BotSharp.Abstraction.Loggers.Enums;
2+
3+
public static class ContentLogSource
4+
{
5+
public const string UserInput = "user input";
6+
public const string Prompt = "prompt";
7+
public const string FunctionCall = "function call";
8+
public const string AgentResponse = "agent response";
9+
}

src/Infrastructure/BotSharp.Abstraction/Loggers/Models/ConversationContentLogModel.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ public class ConversationContentLogModel
44
{
55
[JsonPropertyName("conversation_id")]
66
public string ConversationId { get; set; }
7+
78
[JsonPropertyName("message_id")]
89
public string MessageId { get; set; }
10+
911
[JsonPropertyName("name")]
1012
public string? Name { get; set; }
13+
1114
[JsonPropertyName("role")]
1215
public string Role { get; set; }
1316

17+
[JsonPropertyName("source")]
18+
public string Source { get; set; }
19+
1420
[JsonPropertyName("content")]
1521
public string Content { get; set; }
1622

src/Infrastructure/BotSharp.Abstraction/Messaging/JsonConverters/RichContentJsonConverter .cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
12
using System.Text.Json;
23

34
namespace BotSharp.Abstraction.Messaging.JsonConverters;
@@ -6,7 +7,22 @@ public class RichContentJsonConverter : JsonConverter<IRichMessage>
67
{
78
public override IRichMessage? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
89
{
9-
throw new NotImplementedException();
10+
using var jsonDoc = JsonDocument.ParseValue(ref reader);
11+
var root = jsonDoc.RootElement;
12+
var jsonText = root.GetRawText();
13+
JsonElement element;
14+
object? res = null;
15+
16+
if (root.TryGetProperty("buttons", out element))
17+
{
18+
res = JsonSerializer.Deserialize<ButtonTemplateMessage>(jsonText, options);
19+
}
20+
else if (root.TryGetProperty("options", out element))
21+
{
22+
res = JsonSerializer.Deserialize<MultiSelectTemplateMessage>(jsonText, options);
23+
}
24+
25+
return res as IRichMessage;
1026
}
1127

1228
public override void Write(Utf8JsonWriter writer, IRichMessage value, JsonSerializerOptions options)

src/Infrastructure/BotSharp.Abstraction/Messaging/JsonConverters/TemplateMessageJsonConverter.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
12
using System.Text.Json;
23

34
namespace BotSharp.Abstraction.Messaging.JsonConverters;
@@ -6,7 +7,22 @@ public class TemplateMessageJsonConverter : JsonConverter<ITemplateMessage>
67
{
78
public override ITemplateMessage? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
89
{
9-
throw new NotImplementedException();
10+
using var jsonDoc = JsonDocument.ParseValue(ref reader);
11+
var root = jsonDoc.RootElement;
12+
var jsonText = root.GetRawText();
13+
JsonElement element;
14+
object? res = null;
15+
16+
if (root.TryGetProperty("buttons", out element))
17+
{
18+
res = JsonSerializer.Deserialize<ButtonTemplateMessage>(jsonText, options);
19+
}
20+
else if (root.TryGetProperty("options", out element))
21+
{
22+
res = JsonSerializer.Deserialize<MultiSelectTemplateMessage>(jsonText, options);
23+
}
24+
25+
return res as ITemplateMessage;
1026
}
1127

1228
public override void Write(Utf8JsonWriter writer, ITemplateMessage value, JsonSerializerOptions options)

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using BotSharp.Abstraction.Messaging;
2+
using BotSharp.Abstraction.Messaging.JsonConverters;
3+
using BotSharp.Abstraction.Messaging.Models.RichContent;
14
using BotSharp.Abstraction.Repositories;
25
using System;
36
using System.IO;
@@ -8,12 +11,25 @@ public class ConversationStorage : IConversationStorage
811
{
912
private readonly BotSharpDatabaseSettings _dbSettings;
1013
private readonly IServiceProvider _services;
14+
private readonly JsonSerializerOptions _options;
15+
1116
public ConversationStorage(
1217
BotSharpDatabaseSettings dbSettings,
1318
IServiceProvider services)
1419
{
1520
_dbSettings = dbSettings;
1621
_services = services;
22+
_options = new JsonSerializerOptions
23+
{
24+
PropertyNameCaseInsensitive = true,
25+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
26+
AllowTrailingCommas = true,
27+
Converters =
28+
{
29+
new RichContentJsonConverter(),
30+
new TemplateMessageJsonConverter(),
31+
}
32+
};
1733
}
1834

1935
public void Append(string conversationId, RoleDialogModel dialog)
@@ -24,7 +40,7 @@ public void Append(string conversationId, RoleDialogModel dialog)
2440

2541
if (dialog.Role == AgentRole.Function)
2642
{
27-
var meta = new DialogMeta
43+
var meta = new DialogMetaData
2844
{
2945
Role = dialog.Role,
3046
AgentId = agentId,
@@ -42,7 +58,7 @@ public void Append(string conversationId, RoleDialogModel dialog)
4258
}
4359
else
4460
{
45-
var meta = new DialogMeta
61+
var meta = new DialogMetaData
4662
{
4763
Role = dialog.Role,
4864
AgentId = agentId,
@@ -56,8 +72,8 @@ public void Append(string conversationId, RoleDialogModel dialog)
5672
{
5773
return;
5874
}
59-
60-
dialogElements.Add(new DialogElement(meta, content));
75+
var richContent = dialog.RichContent != null ? JsonSerializer.Serialize(dialog.RichContent, _options) : null;
76+
dialogElements.Add(new DialogElement(meta, content, richContent));
6177
}
6278

6379
db.AppendConversationDialogs(conversationId, dialogElements);
@@ -80,14 +96,17 @@ public List<RoleDialogModel> GetDialogs(string conversationId)
8096
var function = role == AgentRole.Function ? meta.FunctionName : null;
8197
var senderId = role == AgentRole.Function ? currentAgentId : meta.SenderId;
8298
var createdAt = meta.CreateTime;
99+
var richContent = !string.IsNullOrEmpty(dialog.RichContent) ?
100+
JsonSerializer.Deserialize<RichContent<IRichMessage>>(dialog.RichContent, _options) : null;
83101

84102
var record = new RoleDialogModel(role, content)
85103
{
86104
CurrentAgentId = currentAgentId,
87105
MessageId = messageId,
88106
CreatedAt = createdAt,
89107
SenderId = senderId,
90-
FunctionName = function
108+
FunctionName = function,
109+
RichContent = richContent
91110
};
92111
results.Add(record);
93112

src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ private List<DialogElement> CollectDialogElements(string dialogDir)
317317
var blocks = rawDialogs[i].Split("|");
318318
var content = rawDialogs[i + 1];
319319
var trimmed = content.Substring(4);
320-
var meta = new DialogMeta
320+
var meta = new DialogMetaData
321321
{
322322
Role = blocks[1],
323323
AgentId = blocks[2],
@@ -326,7 +326,13 @@ private List<DialogElement> CollectDialogElements(string dialogDir)
326326
SenderId = blocks[1] == AgentRole.Function ? null : blocks[4],
327327
CreateTime = DateTime.Parse(blocks[0])
328328
};
329-
dialogs.Add(new DialogElement(meta, trimmed));
329+
330+
string? richContent = null;
331+
if (blocks.Count() > 5)
332+
{
333+
richContent = blocks[5];
334+
}
335+
dialogs.Add(new DialogElement(meta, trimmed, richContent));
330336
}
331337
}
332338
return dialogs;
@@ -342,7 +348,7 @@ private List<string> ParseDialogElements(List<DialogElement> dialogs)
342348
var meta = element.MetaData;
343349
var createTime = meta.CreateTime.ToString("MM/dd/yyyy hh:mm:ss.fff tt", CultureInfo.InvariantCulture);
344350
var source = meta.FunctionName ?? meta.SenderId;
345-
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}";
351+
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}|{element.RichContent}";
346352
dialogTexts.Add(metaStr);
347353
var content = $" - {element.Content}";
348354
dialogTexts.Add(content);

src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ public async Task<IEnumerable<ChatResponseModel>> GetDialogs([FromRoute] string
102102
{
103103
FirstName = agent.Name,
104104
Role = message.Role,
105-
}
105+
},
106+
RichContent = message.RichContent
106107
});
107108
}
108109
}

src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using BotSharp.Abstraction.Agents.Models;
22
using BotSharp.Abstraction.Functions.Models;
33
using BotSharp.Abstraction.Loggers;
4+
using BotSharp.Abstraction.Loggers.Enums;
45
using BotSharp.Abstraction.Loggers.Models;
56
using BotSharp.Abstraction.Repositories;
6-
using BotSharp.Abstraction.Repositories.Filters;
7-
using BotSharp.Abstraction.Routing.Settings;
87
using Microsoft.AspNetCore.SignalR;
8+
using Serilog;
99

1010
namespace BotSharp.Plugin.ChatHub.Hooks;
1111

@@ -37,11 +37,13 @@ public StreamingLogHook(
3737
AllowTrailingCommas = true
3838
};
3939
}
40+
4041
public override async Task OnMessageReceived(RoleDialogModel message)
4142
{
4243
var conversationId = _state.GetConversationId();
4344
var log = $"MessageId: {message.MessageId} ==>\r\n{message.Role}: {message.Content}";
44-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, _user.UserName, log, message));
45+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
46+
BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message));
4547
}
4648

4749
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
@@ -62,7 +64,8 @@ public override async Task OnFunctionExecuted(RoleDialogModel message)
6264
var agent = await agentService.LoadAgent(message.CurrentAgentId);
6365
var log = $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs}) => {message.Content}";
6466
log += $"\r\n<== MessageId: {message.MessageId}";
65-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, message));
67+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
68+
BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.FunctionCall, message));
6669
}
6770

6871
/// <summary>
@@ -78,30 +81,25 @@ public async Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenS
7881
var agentService = _services.GetRequiredService<IAgentService>();
7982
var conversationId = _state.GetConversationId();
8083
var agent = await agentService.LoadAgent(message.CurrentAgentId);
84+
var logSource = string.Empty;
8185

8286
// Log routing output
8387
try
8488
{
8589
var inst = message.Content.JsonContent<FunctionCallFromLlm>();
86-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, message.Content, message));
90+
logSource = ContentLogSource.AgentResponse;
91+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
92+
BuildContentLog(conversationId, agent?.Name, message.Content, logSource, message));
8793
}
8894
catch
8995
{
9096
// ignore
9197
}
9298

93-
string log;
94-
if (message.Role == AgentRole.Function)
95-
{
96-
log = $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs}) => {message.Content}";
97-
log += $"\r\n<== MessageId: {message.MessageId}";
98-
}
99-
else
100-
{
101-
log = tokenStats.Prompt;
102-
}
103-
104-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, message));
99+
var log = tokenStats.Prompt;
100+
logSource = ContentLogSource.Prompt;
101+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
102+
BuildContentLog(conversationId, agent?.Name, log, logSource, message));
105103
}
106104

107105
/// <summary>
@@ -127,19 +125,21 @@ public override async Task OnResponseGenerated(RoleDialogModel message)
127125
log += $"\r\n{richContent}";
128126
}
129127
log += $"\r\n<== MessageId: {message.MessageId}";
130-
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conv.ConversationId, agent?.Name, log, message));
128+
await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated",
129+
BuildContentLog(conv.ConversationId, agent?.Name, log, ContentLogSource.AgentResponse, message));
131130
}
132131
}
133132

134-
private string BuildContentLog(string conversationId, string? name, string content, RoleDialogModel message)
133+
private string BuildContentLog(string conversationId, string? name, string logContent, string logSource, RoleDialogModel message)
135134
{
136135
var log = new ConversationContentLogModel
137136
{
138137
ConversationId = conversationId,
139138
MessageId = message.MessageId,
140139
Name = name,
141140
Role = message.Role,
142-
Content = content,
141+
Content = logContent,
142+
Source = logSource,
143143
CreateTime = DateTime.UtcNow
144144
};
145145

src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationContentLogDocument.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public class ConversationContentLogDocument : MongoBase
66
public string MessageId { get; set; }
77
public string? Name { get; set; }
88
public string Role { get; set; }
9+
public string Source { get; set; }
910
public string Content { get; set; }
1011
public DateTime CreateTime { get; set; }
1112
}

0 commit comments

Comments
 (0)