Skip to content

Commit 780bb4e

Browse files
author
Wenbo Cao
committed
Add PaddleOcrConverter
2 parents 14d9066 + 7e95be0 commit 780bb4e

19 files changed

+164
-77
lines changed

docs/llm/prompt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Prompt Engineering
22

3-
LLM uses prompt as input, and the model produces different outputs according to the input.
3+
LLM uses prompt as input, and the model produces different outputs according to the input.

docs/llm/template.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
# Template
22

3-
We can define the prompt as a template, and the template can be changed according to variables, so that a instruction file can be used to generate a dynamic prompt.
3+
We can define the prompt as a template, and the template can be changed according to variables, so that a instruction file can be used to generate a dynamic prompt.
4+
`BotSharp` uses [liquid](https://shopify.github.io/liquid/) templates to support various complex dynamic prompt engineering.
5+
6+
`ITemplateRender`
7+
```csharp
8+
bool Render(Agent agent, Dictionary<string, object> dict)
9+
```

src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ public interface IAgentRouting
44
{
55
Task<Agent> LoadRouter();
66
Task<Agent> LoadCurrentAgent();
7+
RoutingRecord[] GetRoutingRecords();
78
}

src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingTable.cs renamed to src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingRecord.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,25 @@
22

33
namespace BotSharp.Abstraction.Agents.Models;
44

5-
public class RoutingTable
5+
public class RoutingRecord
66
{
77
[JsonPropertyName("agent_id")]
88
public string AgentId { get; set; }
99

1010
[JsonPropertyName("name")]
11-
public string AgentName { get; set; }
11+
public string Name { get; set; }
12+
13+
[JsonPropertyName("description")]
14+
public string Description { get; set; }
1215

1316
[JsonPropertyName("required")]
1417
public List<string> RequiredFields { get; set; }
1518

19+
[JsonPropertyName("redirect_to")]
20+
public string RedirectTo { get; set; }
21+
1622
public override string ToString()
1723
{
18-
return AgentName;
24+
return Name;
1925
}
2026
}

src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ public class AgentSettings
88
public string RouterId { get; set; }
99
public string DataDir { get; set; }
1010
public string TemplateFormat { get; set; }
11+
public int MaxRecursiveDepth { get; set; } = 3;
1112
}

src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>netstandard2.1</TargetFramework>
55
<Nullable>enable</Nullable>
66
<LangVersion>10.0</LangVersion>
7-
<VersionPrefix>0.9.0</VersionPrefix>
7+
<VersionPrefix>0.9.4</VersionPrefix>
88
<PackageIcon>Icon.png</PackageIcon>
99
</PropertyGroup>
1010

src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionValidationResult.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace BotSharp.Abstraction.Templating;
2+
3+
public interface ITemplateRender
4+
{
5+
bool Render(Agent agent, Dictionary<string, object> dict);
6+
}

src/Infrastructure/BotSharp.Core/Agents/Services/AgentHookBase.cs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
using BotSharp.Abstraction.Agents.Models;
2-
using Fluid;
32

43
namespace BotSharp.Core.Agents.Services;
54

65
public abstract class AgentHookBase : IAgentHook
76
{
87
protected Agent _agent;
98
public Agent Agent => _agent;
10-
private static readonly FluidParser _parser = new FluidParser();
119

12-
private readonly IServiceProvider _services;
10+
protected readonly IServiceProvider _services;
11+
protected readonly AgentSettings _settings;
1312

14-
public AgentHookBase(IServiceProvider services)
13+
public AgentHookBase(IServiceProvider services, AgentSettings settings)
1514
{
1615
_services = services;
16+
_settings = settings;
1717
}
1818

1919
public void SetAget(Agent agent)
@@ -28,27 +28,7 @@ public virtual bool OnAgentLoading(ref string id)
2828

2929
public virtual bool OnInstructionLoaded(string template, Dictionary<string, object> dict)
3030
{
31-
if (_parser.TryParse(template, out var t, out var error))
32-
{
33-
PopulateStateTokens(dict);
34-
var context = new TemplateContext(dict);
35-
_agent.Instruction = t.Render(context);
36-
return true;
37-
}
38-
else
39-
{
40-
return false;
41-
}
42-
}
43-
44-
private void PopulateStateTokens(Dictionary<string, object> dict)
45-
{
46-
var stateService = _services.GetRequiredService<IConversationStateService>();
47-
var state = stateService.Load();
48-
foreach (var t in state)
49-
{
50-
dict[t.Key] = t.Value;
51-
}
31+
return true;
5232
}
5333

5434
public virtual bool OnFunctionsLoaded(ref string functions)

src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using BotSharp.Abstraction.Agents;
21
using BotSharp.Abstraction.Agents.Models;
2+
using System.IO;
33

44
namespace BotSharp.Core.Agents.Services;
55

@@ -42,4 +42,12 @@ public async Task<Agent> LoadCurrentAgent()
4242

4343
return agent;
4444
}
45+
46+
public RoutingRecord[] GetRoutingRecords()
47+
{
48+
var agentSettings = _services.GetRequiredService<AgentSettings>();
49+
var dbSettings = _services.GetRequiredService<MyDatabaseSettings>();
50+
var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, agentSettings.RouterId, "route.json");
51+
return JsonSerializer.Deserialize<RoutingRecord[]>(File.ReadAllText(filePath));
52+
}
4553
}

src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BotSharp.Abstraction.Agents.Models;
2+
using BotSharp.Core.Templating;
23

34
namespace BotSharp.Core.Agents.Services;
45

@@ -15,6 +16,8 @@ public async Task<Agent> LoadAgent(string id)
1516
}
1617

1718
var agent = await GetAgent(id);
19+
var templateDict = new Dictionary<string, object>();
20+
PopulateState(templateDict);
1821

1922
// After agent is loaded
2023
foreach (var hook in hooks)
@@ -23,7 +26,7 @@ public async Task<Agent> LoadAgent(string id)
2326

2427
if (!string.IsNullOrEmpty(agent.Instruction))
2528
{
26-
hook.OnInstructionLoaded(agent.Instruction, new Dictionary<string, object>());
29+
hook.OnInstructionLoaded(agent.Instruction, templateDict);
2730
}
2831

2932
if (!string.IsNullOrEmpty(agent.Functions))
@@ -41,8 +44,22 @@ public async Task<Agent> LoadAgent(string id)
4144
hook.OnAgentLoaded(agent);
4245
}
4346

47+
// render liquid template
48+
var render = _services.GetRequiredService<TemplateRender>();
49+
render.Render(agent, templateDict);
50+
4451
_logger.LogInformation($"Loaded agent {agent}.");
4552

4653
return agent;
4754
}
55+
56+
private void PopulateState(Dictionary<string, object> dict)
57+
{
58+
var stateService = _services.GetRequiredService<IConversationStateService>();
59+
var state = stateService.Load();
60+
foreach (var t in state)
61+
{
62+
dict[t.Key] = t.Value;
63+
}
64+
}
4865
}

src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>netstandard2.1</TargetFramework>
55
<LangVersion>10.0</LangVersion>
66
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
7-
<VersionPrefix>0.9.0</VersionPrefix>
7+
<VersionPrefix>0.9.4</VersionPrefix>
88
</PropertyGroup>
99

1010
<PropertyGroup Label="Globals">

src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using BotSharp.Abstraction.Functions;
22
using BotSharp.Core.Functions;
3+
using BotSharp.Core.Hooks;
4+
using BotSharp.Core.Templating;
35
using BotSharp.Core.Plugins.Knowledges.Services;
46
using Microsoft.AspNetCore.Builder;
57
using Microsoft.Extensions.Configuration;
@@ -36,10 +38,18 @@ public static IServiceCollection AddBotSharp(this IServiceCollection services, I
3638

3739
RegisterPlugins(services, config);
3840

41+
// Register template render
42+
services.AddSingleton<TemplateRender>();
43+
44+
// Register router
3945
services.AddScoped<IAgentRouting, AgentRouter>();
4046

47+
// Register function callback
4148
services.AddScoped<IFunctionCallback, RouteToAgentFn>();
4249

50+
// Register Hooks
51+
services.AddScoped<IAgentHook, AgentHook>();
52+
4353
return services;
4454
}
4555

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.CallFunctions.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,17 @@ private async Task CallFunctions(RoleDialogModel msg)
2929
await hook.OnFunctionExecuting(msg);
3030
}
3131

32-
// Execute function
33-
await fn.Execute(msg);
34-
32+
try
33+
{
34+
// Execute function
35+
await fn.Execute(msg);
36+
}
37+
catch (Exception ex)
38+
{
39+
msg.ExecutionResult = ex.Message;
40+
_logger.LogError(msg.ExecutionResult);
41+
}
42+
3543
// After functions have been executed
3644
foreach (var hook in hooks)
3745
{

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ namespace BotSharp.Core.Conversations.Services;
77

88
public partial class ConversationService
99
{
10-
const int maxRecursiveDepth = 3;
1110
int currentRecursiveDepth = 0;
1211

1312
private async Task<bool> GetChatCompletionsAsyncRecursively(IChatCompletion chatCompletion,
1413
string conversationId,
1514
Agent agent,
1615
List<RoleDialogModel> wholeDialogs,
16+
int maxRecursiveDepth,
1717
Func<RoleDialogModel, Task> onMessageReceived,
1818
Func<RoleDialogModel, Task> onFunctionExecuting,
1919
Func<RoleDialogModel, Task> onFunctionExecuted)
@@ -83,6 +83,7 @@ await GetChatCompletionsAsyncRecursively(chatCompletion,
8383
conversationId,
8484
agent,
8585
wholeDialogs,
86+
maxRecursiveDepth,
8687
onMessageReceived,
8788
onFunctionExecuting,
8889
onFunctionExecuted);

src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ public async Task<bool> SendMessage(string agentId, string conversationId,
6565
await hook.BeforeCompletion();
6666
}
6767

68+
var agentSettings = _services.GetRequiredService<AgentSettings>();
69+
6870
var chatCompletion = GetChatCompletion();
6971
var result = await GetChatCompletionsAsyncRecursively(chatCompletion,
7072
conversationId,
7173
agent,
7274
wholeDialogs,
75+
agentSettings.MaxRecursiveDepth,
7376
onMessageReceived,
7477
onFunctionExecuting,
7578
onFunctionExecuted);

src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ public async Task<bool> Execute(RoleDialogModel message)
2828
}
2929
else
3030
{
31-
if (!HasMissingRequiredField(message, out var agentId))
31+
var missingfield = HasMissingRequiredField(message, out var agentId);
32+
if (missingfield && message.CurrentAgentId != agentId)
33+
{
34+
message.CurrentAgentId = agentId;
35+
}
36+
else
3237
{
3338
message.CurrentAgentId = agentId;
3439
message.ExecutionResult = $"Routed to {args.AgentName}";
@@ -45,23 +50,23 @@ public async Task<bool> Execute(RoleDialogModel message)
4550
private bool HasMissingRequiredField(RoleDialogModel message, out string agentId)
4651
{
4752
var args = JsonSerializer.Deserialize<RoutingArgs>(message.FunctionArgs);
53+
var router = _services.GetRequiredService<IAgentRouting>();
54+
var records = router.GetRoutingRecords();
55+
var routingRule = records.FirstOrDefault(x => x.Name.ToLower() == args.AgentName.ToLower());
4856

49-
var routes = GetRoutingTable();
50-
var agent = routes.FirstOrDefault(x => x.AgentName.ToLower() == args.AgentName.ToLower());
51-
52-
if (agent == null)
57+
if (routingRule == null)
5358
{
5459
agentId = message.CurrentAgentId;
5560
message.ExecutionResult = $"Can't find agent {args.AgentName}";
5661
return true;
5762
}
5863

59-
agentId = agent.AgentId;
64+
agentId = routingRule.AgentId;
6065

6166
// Check required fields
6267
var jo = JsonSerializer.Deserialize<object>(message.FunctionArgs);
6368
bool hasMissingField = false;
64-
foreach (var field in agent.RequiredFields)
69+
foreach (var field in routingRule.RequiredFields)
6570
{
6671
if (jo is JsonElement root)
6772
{
@@ -71,17 +76,21 @@ private bool HasMissingRequiredField(RoleDialogModel message, out string agentId
7176
hasMissingField = true;
7277
break;
7378
}
79+
else if (root.EnumerateObject().Any(x => x.Name == field) &&
80+
string.IsNullOrEmpty(root.EnumerateObject().FirstOrDefault(x => x.Name == field).Value.ToString()))
81+
{
82+
message.ExecutionResult = $"missing {field}.";
83+
hasMissingField = true;
84+
break;
85+
}
7486
}
7587
}
7688

77-
return hasMissingField;
78-
}
89+
if (hasMissingField && !string.IsNullOrEmpty(routingRule.RedirectTo))
90+
{
91+
agentId = routingRule.RedirectTo;
92+
}
7993

80-
private RoutingTable[] GetRoutingTable()
81-
{
82-
var agentSettings = _services.GetRequiredService<AgentSettings>();
83-
var dbSettings = _services.GetRequiredService<MyDatabaseSettings>();
84-
var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, agentSettings.RouterId, "route.json");
85-
return JsonSerializer.Deserialize<RoutingTable[]>(File.ReadAllText(filePath));
94+
return hasMissingField;
8695
}
8796
}

0 commit comments

Comments
 (0)