Merge pull request #348 from iceljc/features/add-botsharp-json-option

add botsharp options
This commit is contained in:
C. Oceania 2024-03-18 14:54:06 -05:00 committed by GitHub
commit a6e34b8dbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 111 additions and 60 deletions

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>

View file

@ -47,4 +47,4 @@ public class RichContentJsonConverter : JsonConverter<IRichMessage>
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
}

View file

@ -0,0 +1,42 @@
using BotSharp.Abstraction.Messaging.JsonConverters;
using System.Text.Json;
namespace BotSharp.Abstraction.Options;
public class BotSharpOptions
{
private readonly static JsonSerializerOptions defaultJsonOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
AllowTrailingCommas = true,
WriteIndented = true
};
private JsonSerializerOptions _jsonSerializerOptions;
public JsonSerializerOptions JsonSerializerOptions
{
get
{
return _jsonSerializerOptions ?? defaultJsonOptions;
}
set
{
if (value == null)
{
_jsonSerializerOptions = defaultJsonOptions;
}
else
{
_jsonSerializerOptions = value;
}
}
}
public BotSharpOptions()
{
}
}

View file

@ -1,21 +1,25 @@
using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Repositories;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using BotSharp.Abstraction.Routing;
using BotSharp.Core.Plugins;
using BotSharp.Abstraction.Settings;
using BotSharp.Abstraction.Options;
using BotSharp.Abstraction.Messaging;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Options;
using BotSharp.Abstraction.Messaging.JsonConverters;
namespace BotSharp.Core;
public static class BotSharpCoreExtensions
{
public static IServiceCollection AddBotSharpCore(this IServiceCollection services, IConfiguration config)
public static IServiceCollection AddBotSharpCore(this IServiceCollection services, IConfiguration config, Action<BotSharpOptions>? configOptions = null)
{
services.AddScoped<ISettingService, SettingService>();
services.AddScoped<IUserService, UserService>();
RegisterPlugins(services, config);
ConfigureBotSharpOptions(services, configOptions);
return services;
}
@ -53,6 +57,24 @@ public static class BotSharpCoreExtensions
return app;
}
private static void ConfigureBotSharpOptions(IServiceCollection services, Action<BotSharpOptions>? configure)
{
var options = new BotSharpOptions();
if (configure != null)
{
configure(options);
}
AddDefaultJsonConverters(options);
services.AddSingleton(options);
}
private static void AddDefaultJsonConverters(BotSharpOptions options)
{
options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter());
options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter());
}
public static void RegisterPlugins(IServiceCollection services, IConfiguration config)
{
var pluginSettings = new PluginSettings();

View file

@ -1,4 +1,3 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Routing.Settings;

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.JsonConverters;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Options;
using BotSharp.Abstraction.Repositories;
using System;
using System.IO;
@ -15,6 +16,7 @@ public class ConversationStorage : IConversationStorage
public ConversationStorage(
BotSharpDatabaseSettings dbSettings,
BotSharpOptions options,
IServiceProvider services)
{
_dbSettings = dbSettings;
@ -64,6 +66,7 @@ public class ConversationStorage : IConversationStorage
AgentId = agentId,
MessageId = dialog.MessageId,
SenderId = dialog.SenderId,
FunctionName = dialog.FunctionName,
CreateTime = dialog.CreatedAt
};
@ -93,7 +96,7 @@ public class ConversationStorage : IConversationStorage
var role = meta.Role;
var currentAgentId = meta.AgentId;
var messageId = meta.MessageId;
var function = role == AgentRole.Function ? meta.FunctionName : null;
var function = meta.FunctionName;
var senderId = role == AgentRole.Function ? currentAgentId : meta.SenderId;
var createdAt = meta.CreateTime;
var richContent = !string.IsNullOrEmpty(dialog.RichContent) ?

View file

@ -408,16 +408,12 @@ namespace BotSharp.Core.Repository
Role = blocks[1],
AgentId = blocks[2],
MessageId = blocks[3],
FunctionName = blocks[1] == AgentRole.Function ? blocks[4] : null,
SenderId = blocks[1] == AgentRole.Function ? null : blocks[4],
SenderId = !string.IsNullOrWhiteSpace(blocks[4]) ? blocks[4] : null,
FunctionName = !string.IsNullOrWhiteSpace(blocks[5]) ? blocks[5] : null,
CreateTime = DateTime.Parse(blocks[0])
};
string? richContent = null;
if (blocks.Count() > 5)
{
richContent = blocks[5];
}
var richContent = blocks.Count() > 6 ? blocks[6] : null;
dialogs.Add(new DialogElement(meta, trimmed, richContent));
}
}
@ -433,8 +429,7 @@ namespace BotSharp.Core.Repository
{
var meta = element.MetaData;
var createTime = meta.CreateTime.ToString("MM/dd/yyyy hh:mm:ss.fff tt", CultureInfo.InvariantCulture);
var source = meta.FunctionName ?? meta.SenderId;
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{source}|{element.RichContent}";
var metaStr = $"{createTime}|{meta.Role}|{meta.AgentId}|{meta.MessageId}|{meta.SenderId}|{meta.FunctionName}|{element.RichContent}";
dialogTexts.Add(metaStr);
var content = $" - {element.Content}";
dialogTexts.Add(content);

View file

@ -1,5 +1,5 @@
using BotSharp.Abstraction.Messaging.Enums;
using BotSharp.Abstraction.Messaging.JsonConverters;
using BotSharp.Abstraction.Options;
using Microsoft.AspNetCore.SignalR;
namespace BotSharp.Plugin.ChatHub.Hooks;
@ -9,24 +9,16 @@ public class ChatHubConversationHook : ConversationHookBase
private readonly IServiceProvider _services;
private readonly IHubContext<SignalRHub> _chatHub;
private readonly IUserIdentity _user;
private readonly JsonSerializerOptions _serializerOptions;
private readonly BotSharpOptions _options;
public ChatHubConversationHook(IServiceProvider services,
IHubContext<SignalRHub> chatHub,
BotSharpOptions options,
IUserIdentity user)
{
_services = services;
_chatHub = chatHub;
_user = user;
_serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters =
{
new RichContentJsonConverter(),
new TemplateMessageJsonConverter(),
}
};
_options = options;
}
public override async Task OnConversationInitialized(Conversation conversation)
@ -67,6 +59,11 @@ public class ChatHubConversationHook : ConversationHookBase
await base.OnMessageReceived(message);
}
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)
{
await this.OnMessageReceived(message);
}
public override async Task OnResponseGenerated(RoleDialogModel message)
{
var conv = _services.GetRequiredService<IConversationService>();
@ -84,7 +81,7 @@ public class ChatHubConversationHook : ConversationHookBase
LastName = "Assistant",
Role = AgentRole.Assistant
}
}, _serializerOptions);
}, _options.JsonSerializerOptions);
// Send typing-off to client
await _chatHub.Clients.User(_user.Id).SendAsync("OnSenderActionGenerated", new ConversationSenderActionModel

View file

@ -3,6 +3,7 @@ using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Loggers;
using BotSharp.Abstraction.Loggers.Enums;
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Options;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Routing;
using Microsoft.AspNetCore.SignalR;
@ -12,7 +13,7 @@ namespace BotSharp.Plugin.ChatHub.Hooks;
public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IRoutingHook
{
private readonly ConversationSetting _convSettings;
private readonly JsonSerializerOptions _serializerOptions;
private readonly BotSharpOptions _options;
private readonly IServiceProvider _services;
private readonly IHubContext<SignalRHub> _chatHub;
private readonly IConversationStateService _state;
@ -22,6 +23,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
public StreamingLogHook(
ConversationSetting convSettings,
BotSharpOptions options,
IServiceProvider serivces,
IHubContext<SignalRHub> chatHub,
IConversationStateService state,
@ -30,19 +32,13 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
IRoutingContext routingCtx)
{
_convSettings = convSettings;
_options = options;
_services = serivces;
_chatHub = chatHub;
_state = state;
_user = user;
_agentService = agentService;
_routingCtx = routingCtx;
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
AllowTrailingCommas = true,
WriteIndented = true,
};
}
public override async Task OnMessageReceived(RoleDialogModel message)
@ -63,7 +59,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
{
var conversationId = _state.GetConversationId();
var log = $"{message.Content}";
var replyContent = JsonSerializer.Serialize(replyMsg, _serializerOptions);
var replyContent = JsonSerializer.Serialize(replyMsg, _options.JsonSerializerOptions);
log += $"\r\n```json\r\n{replyContent}\r\n```";
var input = new ContentLogInputModel(conversationId, message)
@ -90,7 +86,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
message.FunctionArgs = message.FunctionArgs ?? "{}";
var args = JsonSerializer.Serialize(JsonDocument.Parse(message.FunctionArgs), _serializerOptions);
var args = JsonSerializer.Serialize(JsonDocument.Parse(message.FunctionArgs), _options.JsonSerializerOptions);
var log = $"*{message.FunctionName}*\r\n```json\r\n{args}\r\n```\r\n=> {message.Content?.Trim()}";
var input = new ContentLogInputModel(conversationId, message)
@ -145,7 +141,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
var log = $"{message.Content}";
if (message.RichContent != null && message.RichContent.Message.RichType != "text")
{
var richContent = JsonSerializer.Serialize(message.RichContent, _serializerOptions);
var richContent = JsonSerializer.Serialize(message.RichContent, _options.JsonSerializerOptions);
log += $"\r\n```json\r\n{richContent}\r\n```";
}
@ -248,7 +244,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
{
var conversationId = _state.GetConversationId();
var agent = await _agentService.LoadAgent(message.CurrentAgentId);
var log = JsonSerializer.Serialize(instruct, _serializerOptions);
var log = JsonSerializer.Serialize(instruct, _options.JsonSerializerOptions);
log = $"```json\r\n{log}\r\n```";
var input = new ContentLogInputModel(conversationId, message)
@ -293,7 +289,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
CreateTime = DateTime.UtcNow
};
var json = JsonSerializer.Serialize(output, _serializerOptions);
var json = JsonSerializer.Serialize(output, _options.JsonSerializerOptions);
var convSettings = _services.GetRequiredService<ConversationSetting>();
if (convSettings.EnableContentLog)
@ -322,6 +318,6 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
db.SaveConversationStateLog(log);
}
return JsonSerializer.Serialize(log, _serializerOptions);
return JsonSerializer.Serialize(log, _options.JsonSerializerOptions);
}
}

View file

@ -1,8 +1,8 @@
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Templating;
using BotSharp.Abstraction.Messaging.JsonConverters;
using Microsoft.AspNetCore.SignalR;
using BotSharp.Abstraction.Options;
namespace BotSharp.Plugin.ChatHub.Hooks;
@ -12,26 +12,19 @@ public class WelcomeHook : ConversationHookBase
private readonly IHubContext<SignalRHub> _chatHub;
private readonly IUserIdentity _user;
private readonly IConversationStorage _storage;
private readonly JsonSerializerOptions _serializerOptions;
private readonly BotSharpOptions _options;
public WelcomeHook(IServiceProvider services,
IHubContext<SignalRHub> chatHub,
IUserIdentity user,
IConversationStorage storage)
IConversationStorage storage,
BotSharpOptions options)
{
_services = services;
_chatHub = chatHub;
_user = user;
_storage = storage;
_serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters =
{
new RichContentJsonConverter(),
new TemplateMessageJsonConverter(),
}
};
_options = options;
}
public override async Task OnUserAgentConnectedInitially(Conversation conversation)
@ -66,7 +59,7 @@ public class WelcomeHook : ConversationHookBase
LastName = "",
Role = AgentRole.Assistant
}
}, _serializerOptions);
}, _options.JsonSerializerOptions);
await Task.Delay(300);

View file

@ -3,6 +3,7 @@ using BotSharp.OpenAPI;
using BotSharp.Logger;
using BotSharp.Plugin.ChatHub;
using Serilog;
using BotSharp.Abstraction.Messaging.JsonConverters;
var builder = WebApplication.CreateBuilder(args);
@ -28,9 +29,12 @@ string[] allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get
};
// Add BotSharp
builder.Services.AddBotSharpCore(builder.Configuration)
.AddBotSharpOpenAPI(builder.Configuration, allowedOrigins, builder.Environment, true)
.AddBotSharpLogger(builder.Configuration);
builder.Services.AddBotSharpCore(builder.Configuration, options =>
{
options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter());
options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter());
}).AddBotSharpOpenAPI(builder.Configuration, allowedOrigins, builder.Environment, true)
.AddBotSharpLogger(builder.Configuration);
// Add SignalR for WebSocket
builder.Services.AddSignalR();