forked from SciSharp/BotSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJsonRepairService.cs
More file actions
133 lines (111 loc) · 4.16 KB
/
JsonRepairService.cs
File metadata and controls
133 lines (111 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Settings;
using BotSharp.Abstraction.Shared;
using BotSharp.Abstraction.Shared.Options;
using BotSharp.Abstraction.Templating;
namespace BotSharp.Core.Shared;
/// <summary>
/// Service for repairing malformed JSON using LLM.
/// </summary>
public class JsonRepairService : IJsonRepairService
{
private readonly IServiceProvider _services;
private readonly ILogger<JsonRepairService> _logger;
private const string DEFAULT_TEMPLATE_NAME = "json_repair";
public JsonRepairService(
IServiceProvider services,
ILogger<JsonRepairService> logger)
{
_services = services;
_logger = logger;
}
public async Task<string> RepairAsync(string malformedJson, JsonRepairOptions? options = null)
{
if (string.IsNullOrWhiteSpace(malformedJson))
{
return string.Empty;
}
var json = malformedJson.CleanJsonStr();
if (IsValidJson(json))
{
return json;
}
var repairedJson = await RepairByLLMAsync(json, options);
if (IsValidJson(repairedJson))
{
return repairedJson;
}
// Try repairing again if still invalid
repairedJson = await RepairByLLMAsync(json, options);
return IsValidJson(repairedJson) ? repairedJson : json;
}
public async Task<T?> RepairAndDeserializeAsync<T>(string malformedJson, JsonRepairOptions? options = null)
{
var json = await RepairAsync(malformedJson, options);
return json.Json<T>();
}
#region Private methods
private bool IsValidJson(string malformedJson)
{
if (string.IsNullOrWhiteSpace(malformedJson))
{
return false;
}
try
{
JsonDocument.Parse(malformedJson);
return true;
}
catch (JsonException ex)
{
_logger.LogWarning(ex, $"Error when parse json {malformedJson}");
return false;
}
}
private async Task<string> RepairByLLMAsync(string malformedJson, JsonRepairOptions? options)
{
var agentId = options?.AgentId ?? BuiltInAgentId.AIAssistant;
var templateName = options?.TemplateName ?? DEFAULT_TEMPLATE_NAME;
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.GetAgent(agentId);
var template = agent?.Templates?.FirstOrDefault(x => x.Name == templateName)?.Content;
if (string.IsNullOrEmpty(template))
{
_logger.LogWarning($"Template '{templateName}' cannot be found in agent '{agent?.Name ?? agentId}'");
return malformedJson;
}
var render = _services.GetRequiredService<ITemplateRender>();
var data = options?.Data ?? new Dictionary<string, object>();
data["input"] = malformedJson;
var prompt = render.Render(template, data);
var settingService = _services.GetRequiredService<ISettingService>();
try
{
var completion = CompletionProvider.GetChatCompletion(_services,
provider: options?.Provider ?? agent?.LlmConfig?.Provider ?? "openai",
model: options?.Model ?? agent?.LlmConfig?.Model ?? settingService.GetUpgradeModel(Gpt4xModelConstants.GPT_4o_Mini));
var innerAgent = new Agent
{
Id = Guid.Empty.ToString(),
Name = "JsonRepair",
Instruction = "You are a JSON repair expert."
};
var dialogs = new List<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, prompt)
{
FunctionName = templateName
}
};
var response = await completion.GetChatCompletions(innerAgent, dialogs);
_logger.LogInformation($"JSON repair result: {response.Content}");
return response.Content.CleanJsonStr();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to repair and deserialize JSON.");
return malformedJson;
}
}
#endregion
}