This commit is contained in:
Jicheng Lu 2025-06-30 23:07:58 -05:00
parent 3bef027b22
commit 3da73d6fce
18 changed files with 254 additions and 10 deletions

View file

@ -143,6 +143,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.LLM.Tests", "tests
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Test.RealtimeVoice", "tests\BotSharp.Test.RealtimeVoice\BotSharp.Test.RealtimeVoice.csproj", "{B067B126-88CD-4282-BEEF-7369B64423EF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.ChartHandler", "src\Plugins\BotSharp.Plugin.ChartHandler\BotSharp.Plugin.ChartHandler.csproj", "{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -599,6 +601,14 @@ Global
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|Any CPU.Build.0 = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x64.ActiveCfg = Release|Any CPU
{B067B126-88CD-4282-BEEF-7369B64423EF}.Release|x64.Build.0 = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x64.ActiveCfg = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Debug|x64.Build.0 = Debug|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|Any CPU.Build.0 = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x64.ActiveCfg = Release|Any CPU
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -668,6 +678,7 @@ Global
{7D0DB012-9798-4BB9-B15B-A5B0B7B3B094} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{7C0C7D13-D161-4AB0-9C29-83A0F1FF990E} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{B067B126-88CD-4282-BEEF-7369B64423EF} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{0428DEAA-E4FE-4259-A6D8-6EDD1A9D0702} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}

View file

@ -38,6 +38,10 @@ public static class BotSharpMessageParser
{
targetType = typeof(TextMessage);
}
else if (richType == RichTypeEnum.JsCode)
{
targetType = typeof(JsCodeTemplateMessage);
}
else if (richType == RichTypeEnum.GenericTemplate)
{
if (root.TryGetProperty("element_type", out element))

View file

@ -9,4 +9,6 @@ public static class RichTypeEnum
public const string QuickReply = "quick_reply";
public const string Text = "text";
public const string Attachment = "attachment";
public const string JsCode = "js_code";
}

View file

@ -0,0 +1,10 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
public class JsCodeTemplateMessage : IRichMessage
{
[JsonPropertyName("rich_type")]
public string RichType => RichTypeEnum.JsCode;
[JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
}

View file

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-chart-generate_chart.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-generate_chart.fn.liquid" />
</ItemGroup>
<ItemGroup>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-chart-generate_chart.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-generate_chart.fn.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\util-chart-plot-instruction.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,18 @@
using Microsoft.Extensions.Configuration;
namespace BotSharp.Plugin.ChartHandler;
public class ChartHandlerPlugin : IBotSharpPlugin
{
public string Id => "9dacac1d-2e29-4f01-9d66-b0201f05a9fa";
public string Name => "Chart Plotter";
public string Description => "AI plots chart";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/423/423786.png";
public string[] AgentIds => [];
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddScoped<IAgentUtilityHook, ChartHandlerUtilityHook>();
}
}

View file

@ -0,0 +1,6 @@
namespace BotSharp.Plugin.ChartHandler.Enums;
public class UtilityName
{
public const string ChartGenerator = "chart-generator";
}

View file

@ -0,0 +1,80 @@
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
namespace BotSharp.Plugin.ChartHandler.Functions;
public class GenerateChartFn : IFunctionCallback
{
private readonly IServiceProvider _services;
private readonly ILogger<GenerateChartFn> _logger;
public string Name => "util-chart-generate_chart";
public string Indication => "Generating chart";
public GenerateChartFn(
IServiceProvider services,
ILogger<GenerateChartFn> logger)
{
_services = services;
_logger = logger;
}
public async Task<bool> Execute(RoleDialogModel message)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var agentService = _services.GetRequiredService<IAgentService>();
var convService = _services.GetRequiredService<IConversationService>();
var args = JsonSerializer.Deserialize<LlmContextIn>(message.FunctionArgs);
var agent = await agentService.GetAgent(message.CurrentAgentId);
var inst = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, "util-chart-plot-instruction");
var innerAgent = new Agent
{
Id = agent.Id,
Name = agent.Name,
Instruction = inst,
TemplateDict = new Dictionary<string, object>
{
{ "plotting_requirement", args?.PlottingRequirement ?? string.Empty },
{ "chart_element_id", $"chart-{message.MessageId}" }
}
};
var response = await GetChatCompletion(innerAgent, [
new RoleDialogModel(AgentRole.User, "Please follow the instruction to generate the javascript code.")
{
CurrentAgentId = message.CurrentAgentId,
MessageId = message.MessageId
}
]);
message.Content = response;
message.RichContent = new RichContent<IRichMessage>
{
Recipient = new Recipient { Id = convService.ConversationId },
Message = new JsCodeTemplateMessage
{
Text = response
}
};
message.StopCompletion = true;
return true;
}
private async Task<string> GetChatCompletion(Agent agent, List<RoleDialogModel> dialogs)
{
try
{
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
var completion = CompletionProvider.GetChatCompletion(_services, provider: "openai", model: "gpt-4.1");
var response = await completion.GetChatCompletions(agent, dialogs);
return response.Content;
}
catch (Exception ex)
{
var error = $"Error when plotting chart. {ex.Message}";
_logger.LogWarning(ex, error);
return error;
}
}
}

View file

@ -0,0 +1,24 @@
namespace BotSharp.Plugin.ChartHandler.Hooks;
public class ChartHandlerUtilityHook : IAgentUtilityHook
{
private const string GENERATE_CHART_FN = "util-chart-generate_chart";
public void AddUtilities(List<AgentUtility> utilities)
{
var item = new AgentUtility
{
Category = "chart",
Name = UtilityName.ChartGenerator,
Items = [
new UtilityItem
{
FunctionName = GENERATE_CHART_FN,
TemplateName = $"{GENERATE_CHART_FN}.fn"
}
]
};
utilities.Add(item);
}
}

View file

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace BotSharp.Plugin.ChartHandler.LlmContext;
public class LlmContextIn
{
[JsonPropertyName("plotting_requirement")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? PlottingRequirement { get; set; }
}

View file

@ -0,0 +1,32 @@
global using System;
global using System.Collections.Generic;
global using System.Text;
global using System.Linq;
global using System.Text.Json;
global using System.Net.Mime;
global using System.Threading.Tasks;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Logging;
global using BotSharp.Abstraction.Agents;
global using BotSharp.Abstraction.Conversations;
global using BotSharp.Abstraction.Plugins;
global using BotSharp.Abstraction.Conversations.Models;
global using BotSharp.Abstraction.Functions;
global using BotSharp.Abstraction.Agents.Models;
global using BotSharp.Abstraction.Agents.Enums;
global using BotSharp.Abstraction.Files.Enums;
global using BotSharp.Abstraction.Files.Models;
global using BotSharp.Abstraction.Files;
global using BotSharp.Abstraction.MLTasks;
global using BotSharp.Abstraction.Utilities;
global using BotSharp.Abstraction.Agents.Settings;
global using BotSharp.Abstraction.Functions.Models;
global using BotSharp.Abstraction.Repositories;
global using BotSharp.Abstraction.Settings;
global using BotSharp.Abstraction.Messaging;
global using BotSharp.Abstraction.Messaging.Models.RichContent;
global using BotSharp.Abstraction.Options;
global using BotSharp.Core.Infrastructures;
global using BotSharp.Plugin.ChartHandler.Enums;
global using BotSharp.Plugin.ChartHandler.LlmContext;
global using BotSharp.Plugin.ChartHandler.Hooks;

View file

@ -0,0 +1,14 @@
{
"name": "util-chart-generate_chart",
"description": "If the user requests you plotting or generating chart, you can call this function to generate chart in any format that user requested.",
"parameters": {
"type": "object",
"properties": {
"plotting_requirement": {
"type": "string",
"description": "The requirement that user posted for plotting or generating chart."
}
},
"required": [ "plotting_requirement" ]
}
}

View file

@ -0,0 +1 @@
Please call function util-chart-generate_chart if user wants to generate a chart.

View file

@ -0,0 +1,9 @@
Please take a look at "Requirement" and generate a javascript code that can be used to render a pie chart on a canvas element with id {{ chart_element_id }}.
=== Requirement ===
{{ plotting_requirement }}
*** Important ***
** You must not create any new html element.
** You must output the js code only, and wrap it between the script tags.

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
@ -9,10 +9,6 @@
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
<OutputPath>$(SolutionDir)packages</OutputPath>
</PropertyGroup>
<ItemGroup>
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\select_edit_image_prompt.liquid" />
</ItemGroup>
<ItemGroup>
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\functions\util-file-generate_image.json" />

View file

@ -12,10 +12,6 @@ public class LlmContextIn
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ImageDescription { get; set; }
//[JsonPropertyName("image_url")]
//[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
//public string? ImageUrl { get; set; }
[JsonPropertyName("image_urls")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IEnumerable<string>? ImageUrls { get; set; }

View file

@ -36,11 +36,11 @@
<ItemGroup>
<ProjectReference Include="..\..\tests\BotSharp.Plugin.PizzaBot\BotSharp.Plugin.PizzaBot.csproj" />
<ProjectReference Include="..\BotSharp.ServiceDefaults\BotSharp.ServiceDefaults.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core.Realtime\BotSharp.Core.Realtime.csproj" />
</ItemGroup>
<ItemGroup Condition="$(SolutionName)==BotSharp">
<ProjectReference Include="..\Infrastructure\BotSharp.Core\BotSharp.Core.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core.Realtime\BotSharp.Core.Realtime.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core.Rules\BotSharp.Core.Rules.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core.Crontab\BotSharp.Core.Crontab.csproj" />
<ProjectReference Include="..\Infrastructure\BotSharp.Core.SideCar\BotSharp.Core.SideCar.csproj" />
@ -75,6 +75,7 @@
<ProjectReference Include="..\Plugins\BotSharp.Plugin.FileHandler\BotSharp.Plugin.FileHandler.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.EmailHandler\BotSharp.Plugin.EmailHandler.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.AudioHandler\BotSharp.Plugin.AudioHandler.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.ChartHandler\BotSharp.Plugin.ChartHandler.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.MetaGLM\BotSharp.Plugin.MetaGLM.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.Planner\BotSharp.Plugin.Planner.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.TencentCos\BotSharp.Plugin.TencentCos.csproj" />

View file

@ -539,6 +539,7 @@
"BotSharp.Plugin.FileHandler",
"BotSharp.Plugin.EmailHandler",
"BotSharp.Plugin.AudioHandler",
"BotSharp.Plugin.ChartHandler",
"BotSharp.Plugin.TencentCos"
],
"ExcludedFunctions": [