Skip to content

Commit 08568e7

Browse files
committed
sql driver execution API
1 parent 15ec243 commit 08568e7

File tree

8 files changed

+114
-10
lines changed

8 files changed

+114
-10
lines changed

src/Plugins/BotSharp.Plugin.ExcelHandler/Functions/ReadExcelFn.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ public async Task<bool> Execute(RoleDialogModel message)
5858
return true;
5959
}
6060

61-
var results = GetResponeFromDialogs(dialogs);
61+
var results = ImportDataFromDialogs(dialogs);
6262
message.Content = GenerateSqlExecutionSummary(results);
63-
states.SetState("excel_import_result", message.Content);
63+
states.SetState("data_import_result", message.Content);
64+
states.SetState("data_import_dbtype", _dbService.Provider.ToString());
6465
dialogs.ForEach(x => x.Files = null);
6566
return true;
6667
}
@@ -116,7 +117,7 @@ private bool AssembleFiles(string conversationId, List<RoleDialogModel> dialogs)
116117
return true;
117118
}
118119

119-
private List<SqlContextOut> GetResponeFromDialogs(List<RoleDialogModel> dialogs)
120+
private List<SqlContextOut> ImportDataFromDialogs(List<RoleDialogModel> dialogs)
120121
{
121122
var sqlCommands = new List<SqlContextOut>();
122123
var dialog = dialogs.Last(x => !x.Files.IsNullOrEmpty());

src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlGenerationFn.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task<bool> Execute(RoleDialogModel message)
3737
var domainKnowledge = states.GetState("planning_result");
3838
domainKnowledge += "\r\n" + states.GetState("domain_knowledges");
3939
var dictionaryItems = states.GetState("dictionary_items");
40-
var excelImportResult = states.GetState("excel_import_result");
40+
var excelImportResult = states.GetState("data_import_result");
4141

4242
foreach (var step in steps)
4343
{
@@ -107,7 +107,7 @@ await HookEmitter.Emit<IPlanningHook>(_services, async x =>
107107
{ "domain_knowledges", domainKnowledge },
108108
{ "dictionary_items", dictionaryItems },
109109
{ "table_structure", ddlStatement },
110-
{ "excel_import_result", excelImportResult }
110+
{ "data_import_result", excelImportResult }
111111
});
112112
}
113113
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)

src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Functions/SummaryPlanFn.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public async Task<bool> Execute(RoleDialogModel message)
3535
var domainKnowledge = states.GetState("planning_result");
3636
domainKnowledge += "\r\n" + states.GetState("domain_knowledges");
3737
var dictionaryItems = states.GetState("dictionary_items");
38-
var excelImportResult = states.GetState("excel_import_result");
38+
var excelImportResult = states.GetState("data_import_result");
3939

4040
foreach (var step in steps)
4141
{
@@ -106,7 +106,7 @@ await HookEmitter.Emit<IPlanningHook>(_services, async x =>
106106
{ "domain_knowledges", domainKnowledge },
107107
{ "dictionary_items", dictionaryItems },
108108
{ "table_structure", ddlStatement },
109-
{ "excel_import_result", excelImportResult }
109+
{ "data_import_result", excelImportResult }
110110
});
111111
}
112112
private async Task<RoleDialogModel> GetAiResponse(Agent plannerAgent)

src/Plugins/BotSharp.Plugin.Planner/data/agents/282a7128-69a1-44b0-878c-a9159b88f3b9/templates/two_stage.summarize.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ Table Structure:
2626

2727
=====
2828
Attached Excel Information:
29-
{{ excel_import_result }}
29+
{{ data_import_result }}

src/Plugins/BotSharp.Plugin.Planner/data/agents/da7aad2c-8112-48a2-ab7b-1f87da524741/templates/sql.generation.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ Table Structure:
2626

2727
=====
2828
Attached Excel Information:
29-
{{ excel_import_result }}
29+
{{ data_import_result }}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using BotSharp.Plugin.SqlDriver.Controllers.ViewModels;
2+
using Microsoft.AspNetCore.Authorization;
3+
using Microsoft.AspNetCore.Mvc;
4+
using System.Text.RegularExpressions;
5+
using static Dapper.SqlMapper;
6+
7+
namespace BotSharp.Plugin.SqlDriver.Controllers;
8+
9+
[Authorize]
10+
[ApiController]
11+
public class SqlDriverController : ControllerBase
12+
{
13+
private readonly IServiceProvider _services;
14+
15+
public SqlDriverController(IServiceProvider services)
16+
{
17+
_services = services;
18+
}
19+
20+
[HttpPost]
21+
[Route("/sql-driver/{conversationId}/execute")]
22+
public async Task<IActionResult> ExecuteSqlQuery([FromRoute] string conversationId, [FromBody] SqlQueryRequest sqlQueryRequest)
23+
{
24+
var match = Regex.Match(sqlQueryRequest.SqlStatement, @"```sql\s*([\s\S]*?)\s*```", RegexOptions.IgnoreCase);
25+
if (match.Success)
26+
{
27+
sqlQueryRequest.SqlStatement = match.Groups[1].Value.Trim();
28+
}
29+
30+
var fn = _services.GetRequiredService<IRoutingService>();
31+
var msg = new RoleDialogModel(AgentRole.User, sqlQueryRequest.SqlStatement);
32+
msg.FunctionArgs = JsonSerializer.Serialize(new ExecuteQueryArgs
33+
{
34+
SqlStatements = [sqlQueryRequest.SqlStatement],
35+
FormattingResult = sqlQueryRequest.FormattingResult
36+
});
37+
var result = await fn.InvokeFunction("execute_sql", msg);
38+
return Ok(msg.Content);
39+
}
40+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BotSharp.Plugin.SqlDriver.Controllers.ViewModels;
2+
3+
public class SqlQueryRequest
4+
{
5+
public string DbType { get; set; } = null!;
6+
public string SqlStatement { get; set; } = null!;
7+
public bool FormattingResult { get; set; } = true;
8+
}

src/Plugins/BotSharp.Plugin.SqlDriver/Functions/ExecuteQueryFn.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.Data.Sqlite;
55
using MySqlConnector;
66
using Npgsql;
7+
using System.Text;
78

89
namespace BotSharp.Plugin.SqlDriver.Functions;
910

@@ -53,7 +54,8 @@ public async Task<bool> Execute(RoleDialogModel message)
5354
return true;
5455
}
5556

56-
message.Content = JsonSerializer.Serialize(results);
57+
message.Content = FormatResultsToCsv(results);
58+
message.Data = results;
5759
}
5860
catch (DbException ex)
5961
{
@@ -97,6 +99,59 @@ public async Task<bool> Execute(RoleDialogModel message)
9799
return true;
98100
}
99101

102+
private string FormatResultsToCsv(IEnumerable<dynamic> results)
103+
{
104+
if (results == null || !results.Any())
105+
{
106+
return string.Empty;
107+
}
108+
109+
var sb = new StringBuilder();
110+
var firstRow = results.First() as IDictionary<string, object>;
111+
112+
if (firstRow == null)
113+
{
114+
return string.Empty;
115+
}
116+
117+
// Write CSV header
118+
var headers = firstRow.Keys.ToList();
119+
sb.AppendLine(string.Join(",", headers.Select(h => EscapeCsvField(h))));
120+
121+
// Write CSV rows
122+
foreach (var row in results)
123+
{
124+
var rowDict = row as IDictionary<string, object>;
125+
if (rowDict != null)
126+
{
127+
var values = headers.Select(h =>
128+
{
129+
var value = rowDict.ContainsKey(h) ? rowDict[h] : null;
130+
return EscapeCsvField(value?.ToString() ?? string.Empty);
131+
});
132+
sb.AppendLine(string.Join(",", values));
133+
}
134+
}
135+
136+
return sb.ToString().TrimEnd();
137+
}
138+
139+
private string EscapeCsvField(string field)
140+
{
141+
if (string.IsNullOrEmpty(field))
142+
{
143+
return string.Empty;
144+
}
145+
146+
// If field contains comma, quote, or newline, wrap in quotes and escape quotes
147+
if (field.Contains(',') || field.Contains('"') || field.Contains('\n') || field.Contains('\r'))
148+
{
149+
return $"\"{field.Replace("\"", "\"\"")}\"";
150+
}
151+
152+
return field;
153+
}
154+
100155
private IEnumerable<dynamic> RunQueryInMySql(string[] sqlTexts)
101156
{
102157
var settings = _services.GetRequiredService<SqlDriverSetting>();

0 commit comments

Comments
 (0)