using BotSharp.Abstraction.Routing; using BotSharp.Core.Infrastructures; using MySqlConnector; using static Dapper.SqlMapper; using BotSharp.Abstraction.Agents.Enums; namespace BotSharp.Plugin.Planner.Functions; public class AddDatabaseKnowledgeFn : IFunctionCallback { public string Name => "add_database_knowledge"; private readonly IServiceProvider _services; private object aiAssistant; public AddDatabaseKnowledgeFn(IServiceProvider services) { _services = services; } public async Task Execute(RoleDialogModel message) { var agentService = _services.GetRequiredService(); var sqlDriver = _services.GetRequiredService(); var fn = _services.GetRequiredService(); var settings = _services.GetRequiredService(); using var connection = new MySqlConnection(settings.MySqlConnectionString); var dictionary = new Dictionary(); List allTables = new List(); //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'affiliate_%' or table_name like 'client_%' or table_name like 'data_%' or table_name like 'sms_%') limit 10"; var sql = $"select * from GSMPMetaData.joanna_knowledgebase where id>1057;"; //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and table_name like 'data_%'"; //var sql = $"select table_name from information_schema.tables where table_schema='GSMPMetaData' and (table_name like 'client_%Reactive%' or table_name like 'data_%' or table_name like 'sms_%');"; var result = connection.Query(sql: sql,dictionary); //var result2 = new string[] { "client_ServiceCategory", "client_ServiceCode", "client_ServiceCodeNTE", "client_ServiceType" }; foreach (var item in result) { allTables.Add(item.TABLE_NAME); } message.Data = allTables.Distinct().ToList(); var currentAgent = await agentService.LoadAgent(message.CurrentAgentId); var note = ""; foreach (var item in allTables) { message.Data = new List { item }; await fn.InvokeFunction("get_table_definition", message); var PlanningPrompt = await GetPrompt(message); var plannerAgent = new Agent { Id = "", Name = "database_knowledge", Instruction = PlanningPrompt, TemplateDict = new Dictionary(), LlmConfig = currentAgent.LlmConfig }; var response = await GetAIResponse(plannerAgent); try { var knowledge = response.Content.JsonArrayContent(); foreach (var k in knowledge) { try { message.FunctionArgs = JsonSerializer.Serialize(new ExtractedKnowledge { Question = k.Question, Answer = k.Answer }); await fn.InvokeFunction("memorize_knowledge", message); message.SecondaryContent += $"Table: {item}, Question:{k.Question}, {message.Content} \r\n"; } catch (Exception e) { note += $"Error processing table {item}: {e.Message}\r\n{e.InnerException}"; } } } catch (Exception e) { note += $"Error processing table {item}: {e.Message}\r\n{e.InnerException}"; } } //message.Data = allTables.Distinct().ToList(); return true; } private async Task GetAIResponse(Agent plannerAgent) { var conv = _services.GetRequiredService(); var wholeDialogs = conv.GetDialogHistory(); var completion = CompletionProvider.GetChatCompletion(_services, provider: plannerAgent.LlmConfig.Provider, model: plannerAgent.LlmConfig.Model); //wholeDialogs.Last().Content += "\n\n=========\n\nthe summarized question/answer should:\n1. help user to identify the location of tables to find further information\n2. identify the table structure and data relationship based on the task description\n3. summarize all the table to table relationship information based on the FOREIGN KEY, and include both table in the answer"; return await completion.GetChatCompletions(plannerAgent, wholeDialogs); } private async Task GetPrompt(RoleDialogModel message) { var agentService = _services.GetRequiredService(); var aiAssistant = await agentService.GetAgent(BuiltInAgentId.AIAssistant); var render = _services.GetRequiredService(); var template = aiAssistant.Templates.First(x => x.Name == "database_knowledge").Content; //var responseFormat = JsonSerializer.Serialize(new JsonDocument[] { JsonDocument.Parse("{}") }); var responseFormat = JsonSerializer.Serialize(new ExtractedKnowledge { Question = "question", Answer = "answer" }); return render.Render(template, new Dictionary { { "table_structure", message.Content } }); } }