Merge branch 'SciSharp:master' into master
This commit is contained in:
commit
a36a4a763d
|
|
@ -17,6 +17,18 @@ public class UserRole
|
|||
/// </summary>
|
||||
public const string Client = "client";
|
||||
|
||||
/// <summary>
|
||||
/// Back office operations
|
||||
/// </summary>
|
||||
public const string Operation = "operation";
|
||||
|
||||
public const string Technician = "technician";
|
||||
|
||||
/// <summary>
|
||||
/// Software Developers, Data Engineer, Business Analyst
|
||||
/// </summary>
|
||||
public const string Engineer = "engineer";
|
||||
|
||||
/// <summary>
|
||||
/// AI Assistant
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ public static class VectorStorageExtension
|
|||
{
|
||||
if (data?.Data == null) return string.Empty;
|
||||
|
||||
return $"Question: {data.Data[KnowledgePayloadName.Text]}\r\nAnswer: {data.Data[KnowledgePayloadName.Answer]}";
|
||||
if (data.Data.TryGetValue(KnowledgePayloadName.Text, out var question)) { }
|
||||
|
||||
if (data.Data.TryGetValue(KnowledgePayloadName.Answer, out var answer)) { }
|
||||
|
||||
return $"Question: {question}\r\nAnswer: {answer}";
|
||||
}
|
||||
|
||||
public static string ToPayloadPair(this VectorSearchResult data, IList<string> payloads)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public partial class AgentService : IAgentService
|
|||
public string GetAgentDataDir(string agentId)
|
||||
{
|
||||
var dbSettings = _services.GetRequiredService<BotSharpDatabaseSettings>();
|
||||
var dir = Path.Combine(dbSettings.FileRepository, _agentSettings.DataDir, agentId);
|
||||
var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dbSettings.FileRepository, _agentSettings.DataDir, agentId);
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using BotSharp.Abstraction.Routing.Planning;
|
|||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using BotSharp.Core.Instructs;
|
||||
using BotSharp.Core.Knowledges.Services;
|
||||
using BotSharp.Core.Messaging;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using BotSharp.Core.Templating;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
if (message.FunctionName != null)
|
||||
{
|
||||
var msg = RoleDialogModel.From(message, role: AgentRole.Function);
|
||||
var ret = await routing.InvokeFunction(message.FunctionName, msg);
|
||||
await routing.InvokeFunction(message.FunctionName, msg);
|
||||
}
|
||||
|
||||
var agentId = routing.Context.GetCurrentAgentId();
|
||||
|
|
@ -83,9 +83,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
{
|
||||
var content = $"This agent ({agent.Name}) is disabled, please install the corresponding plugin ({agent.Plugin.Name}) to activate this agent.";
|
||||
|
||||
message = RoleDialogModel.From(message,
|
||||
role: AgentRole.Assistant,
|
||||
content: content);
|
||||
message = RoleDialogModel.From(message, role: AgentRole.Assistant, content: content);
|
||||
_dialogs.Add(message);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public partial class TwoStagePlanner
|
||||
{
|
||||
private async Task<FirstStagePlan[]> GetFirstStagePlanAsync(Agent router, string messageId, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router);
|
||||
|
||||
var plan = new FirstStagePlan[0];
|
||||
|
||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||
var provider = router.LlmConfig.Provider ?? "openai";
|
||||
var model = llmProviderService.GetProviderModel(provider, router.LlmConfig.Model ?? "gpt-4o");
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: provider,
|
||||
model: model.Name);
|
||||
|
||||
string text = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var response = await completion.GetChatCompletions(new Agent
|
||||
{
|
||||
Id = router.Id,
|
||||
Name = nameof(TwoStagePlanner),
|
||||
Instruction = firstStagePlanPrompt
|
||||
}, dialogs);
|
||||
|
||||
text = response.Content;
|
||||
plan = response.Content.JsonArrayContent<FirstStagePlan>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {text}");
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
private async Task<string> GetFirstStagePlanPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "two_stage.1st.plan").Content;
|
||||
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
|
||||
{
|
||||
Parameters = new JsonDocument[]{ JsonDocument.Parse("{}") },
|
||||
Results = new string[] { "" }
|
||||
});
|
||||
|
||||
var relevantKnowledges = new List<string>();
|
||||
var hooks = _services.GetServices<IKnowledgeHook>();
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
var k = await hook.GetRelevantKnowledges();
|
||||
relevantKnowledges.AddRange(k);
|
||||
}
|
||||
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "response_format", responseFormat },
|
||||
{ "relevant_knowledges", relevantKnowledges.ToArray() }
|
||||
});
|
||||
}
|
||||
|
||||
private string GetFirstStageNextPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "first_stage.next").Content;
|
||||
var responseFormat = JsonSerializer.Serialize(new FirstStagePlan
|
||||
{
|
||||
});
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "response_format", responseFormat },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public partial class TwoStagePlanner
|
||||
{
|
||||
public string GetContext()
|
||||
{
|
||||
var content = "";
|
||||
foreach (var c in _executionContext)
|
||||
{
|
||||
content += $"* {c}\r\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public partial class TwoStagePlanner
|
||||
{
|
||||
private async Task<SecondStagePlan[]> GetSecondStagePlanAsync(Agent router, string messageId, FirstStagePlan plan1st, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var secondStagePrompt = GetSecondStagePlanPrompt(router, plan1st);
|
||||
var firstStageSystemPrompt = await GetFirstStagePlanPrompt(router);
|
||||
|
||||
var plan = new SecondStagePlan[0];
|
||||
|
||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||
var model = llmProviderService.GetProviderModel("azure-openai", "gpt-4");
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: "azure-openai",
|
||||
model: model.Name);
|
||||
|
||||
string text = string.Empty;
|
||||
|
||||
var conversations = dialogs.Where(x => x.Role != AgentRole.Function).ToList();
|
||||
conversations.Add(new RoleDialogModel(AgentRole.User, secondStagePrompt)
|
||||
{
|
||||
CurrentAgentId = router.Id,
|
||||
MessageId = messageId,
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
var response = await completion.GetChatCompletions(new Agent
|
||||
{
|
||||
Id = router.Id,
|
||||
Name = nameof(TwoStagePlanner),
|
||||
Instruction = firstStageSystemPrompt
|
||||
}, conversations);
|
||||
|
||||
text = response.Content;
|
||||
plan = response.Content.JsonArrayContent<SecondStagePlan>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {text}");
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
private string GetSecondStageTaskPrompt(Agent router, SecondStagePlan plan)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.task").Content;
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "task_description", plan.Description },
|
||||
{ "related_tables", plan.Tables },
|
||||
{ "input_arguments", JsonSerializer.Serialize(plan.Parameters) },
|
||||
{ "output_results", JsonSerializer.Serialize(plan.Results) },
|
||||
});
|
||||
}
|
||||
|
||||
private string GetSecondStagePlanPrompt(Agent router, FirstStagePlan plan)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "planner_prompt.two_stage.2nd.plan").Content;
|
||||
var responseFormat = JsonSerializer.Serialize(new SecondStagePlan
|
||||
{
|
||||
Tool = "tool name if task solution provided",
|
||||
Parameters = new JsonDocument[] { JsonDocument.Parse("{}") },
|
||||
Results = new string[] { "" }
|
||||
});
|
||||
var context = GetContext();
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
return render.Render(template, new Dictionary<string, object>
|
||||
{
|
||||
{ "task_description", plan.Task },
|
||||
{ "response_format", responseFormat }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
using BotSharp.Abstraction.Routing.Planning;
|
||||
|
||||
namespace BotSharp.Core.Routing.Planning;
|
||||
|
||||
public partial class TwoStagePlanner : IRoutingPlaner
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
public int MaxLoopCount => 100;
|
||||
private bool _isTaskCompleted;
|
||||
private string _md5;
|
||||
|
||||
private Queue<FirstStagePlan> _plan1st = new Queue<FirstStagePlan>();
|
||||
private Queue<SecondStagePlan> _plan2nd = new Queue<SecondStagePlan>();
|
||||
|
||||
private List<string> _executionContext = new List<string>();
|
||||
|
||||
public TwoStagePlanner(IServiceProvider services, ILogger<TwoStagePlanner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<FunctionCallFromLlm> GetNextInstruction(Agent router, string messageId, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
if (_plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty())
|
||||
{
|
||||
FirstStagePlan[] items = await GetFirstStagePlanAsync(router, messageId, dialogs);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
_plan1st.Enqueue(item);
|
||||
};
|
||||
}
|
||||
|
||||
// Get Second Stage Plan
|
||||
if (_plan2nd.IsNullOrEmpty())
|
||||
{
|
||||
var plan1 = _plan1st.Dequeue();
|
||||
|
||||
if (plan1.ContainMultipleSteps)
|
||||
{
|
||||
SecondStagePlan[] items = await GetSecondStagePlanAsync(router, messageId, plan1, dialogs);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
_plan2nd.Enqueue(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_plan2nd.Enqueue(new SecondStagePlan
|
||||
{
|
||||
Description = plan1.Task,
|
||||
Tables = plan1.Tables,
|
||||
Parameters = plan1.Parameters,
|
||||
Results = plan1.Results,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var plan2 = _plan2nd.Dequeue();
|
||||
|
||||
var secondStagePrompt = GetSecondStageTaskPrompt(router, plan2);
|
||||
var inst = new FunctionCallFromLlm
|
||||
{
|
||||
AgentName = "SQL Driver",
|
||||
Response = secondStagePrompt,
|
||||
Function = "route_to_agent"
|
||||
};
|
||||
|
||||
inst.HandleDialogsByPlanner = true;
|
||||
_isTaskCompleted = _plan1st.IsNullOrEmpty() && _plan2nd.IsNullOrEmpty();
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
public List<RoleDialogModel> BeforeHandleContext(FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var question = inst.Response;
|
||||
if (_executionContext.Count > 0)
|
||||
{
|
||||
var content = GetContext();
|
||||
question = $"CONTEXT:\r\n{content}\r\n" + inst.Response;
|
||||
}
|
||||
else
|
||||
{
|
||||
question = $"CONTEXT:\r\n{question}";
|
||||
}
|
||||
|
||||
var taskAgentDialogs = new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, question)
|
||||
{
|
||||
MessageId = message.MessageId,
|
||||
}
|
||||
};
|
||||
|
||||
return taskAgentDialogs;
|
||||
}
|
||||
|
||||
public bool AfterHandleContext(List<RoleDialogModel> dialogs, List<RoleDialogModel> taskAgentDialogs)
|
||||
{
|
||||
dialogs.AddRange(taskAgentDialogs.Skip(1));
|
||||
|
||||
// Keep execution context
|
||||
_executionContext.Add(taskAgentDialogs.Last().Content);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
dialogs.Add(new RoleDialogModel(AgentRole.User, inst.Response)
|
||||
{
|
||||
MessageId = message.MessageId,
|
||||
CurrentAgentId = router.Id
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var context = _services.GetRequiredService<IRoutingContext>();
|
||||
|
||||
if (message.StopCompletion || _isTaskCompleted)
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStagePlanner)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
routing.ResetRecursiveCounter();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
using BotSharp.Abstraction.Knowledges.Settings;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Helpers;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Helpers;
|
||||
|
||||
public static class KnowledgeSettingHelper
|
||||
{
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using BotSharp.Abstraction.Knowledges.Models;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Helpers;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Helpers;
|
||||
|
||||
public static class TextChopper
|
||||
{
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
using BotSharp.Abstraction.Plugins.Models;
|
||||
using BotSharp.Abstraction.Settings;
|
||||
using BotSharp.Core.Knowledges.Services;
|
||||
using BotSharp.Plugin.KnowledgeBase.Converters;
|
||||
using BotSharp.Plugin.KnowledgeBase.Hooks;
|
||||
using BotSharp.Plugin.KnowledgeBase.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace BotSharp.Plugin.KnowledgeBase;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using BotSharp.Abstraction.Knowledges.Models;
|
||||
using BotSharp.Abstraction.VectorStorage.Models;
|
||||
using BotSharp.Core.Knowledges.Helpers;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Services;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace BotSharp.Core.Knowledges.Services;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService
|
||||
{
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
using BotSharp.Abstraction.Graph.Models;
|
||||
using BotSharp.Abstraction.Knowledges.Models;
|
||||
using BotSharp.Abstraction.VectorStorage.Models;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Services;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService
|
||||
{
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
using BotSharp.Abstraction.VectorStorage.Models;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Services;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService
|
||||
{
|
||||
|
|
@ -1,10 +1,4 @@
|
|||
using BotSharp.Abstraction.Graph;
|
||||
using BotSharp.Abstraction.Knowledges.Settings;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.VectorStorage;
|
||||
using BotSharp.Core.Knowledges.Helpers;
|
||||
|
||||
namespace BotSharp.Core.Knowledges.Services;
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService : IKnowledgeService
|
||||
{
|
||||
|
|
@ -20,6 +20,7 @@ global using BotSharp.Abstraction.Knowledges.Settings;
|
|||
global using BotSharp.Abstraction.Knowledges.Enums;
|
||||
global using BotSharp.Abstraction.VectorStorage;
|
||||
global using BotSharp.Abstraction.VectorStorage.Models;
|
||||
global using BotSharp.Abstraction.Graph.Models;
|
||||
global using BotSharp.Abstraction.Knowledges.Models;
|
||||
global using BotSharp.Abstraction.MLTasks;
|
||||
global using BotSharp.Abstraction.Functions;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BotSharp.Plugin.Planner.TwoStaging;
|
||||
|
||||
|
|
@ -8,7 +9,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger _logger;
|
||||
public int MaxLoopCount => 100;
|
||||
public int MaxLoopCount => 10;
|
||||
private bool _isTaskCompleted;
|
||||
|
||||
private Queue<FirstStagePlan> _plan1st = new Queue<FirstStagePlan>();
|
||||
|
|
@ -16,7 +17,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
|
||||
private List<string> _executionContext = new List<string>();
|
||||
|
||||
public TwoStageTaskPlanner(IServiceProvider services, ILogger<TwoStagePlanner> logger)
|
||||
public TwoStageTaskPlanner(IServiceProvider services, ILogger<TwoStageTaskPlanner> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
|
|
@ -27,15 +28,14 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
// push agent to routing context
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
routing.Context.Push(BuiltInAgentId.Planner, "Make plan in TwoStage planner");
|
||||
|
||||
return new FunctionCallFromLlm
|
||||
{
|
||||
AgentName = "Planner",
|
||||
UserGoal = "",
|
||||
Response = "",
|
||||
AgentName = router.Name,
|
||||
Response = dialogs.Last().Content,
|
||||
Function = "route_to_agent"
|
||||
};
|
||||
|
||||
|
||||
/*FirstStagePlan[] items = await GetFirstStagePlanAsync(router, messageId, dialogs);
|
||||
|
||||
foreach (var item in items)
|
||||
|
|
@ -130,7 +130,13 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
|
||||
if (message.StopCompletion || _isTaskCompleted)
|
||||
{
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStagePlanner)}");
|
||||
context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStageTaskPlanner)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dialogs.Last().Role == AgentRole.Assistant)
|
||||
{
|
||||
context.Empty();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -149,47 +155,6 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
return content;
|
||||
}
|
||||
|
||||
private async Task<FirstStagePlan[]> GetFirstStagePlanAsync(Agent router, string messageId, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
/*var fn = _services.GetRequiredService<IRoutingService>();
|
||||
await fn.InvokeFunction("plan_primary_stage", message);
|
||||
var items = message.Content.JsonArrayContent<SecondStagePlan>();*/
|
||||
|
||||
var firstStagePlanPrompt = await GetFirstStagePlanPrompt(router);
|
||||
|
||||
var plan = new FirstStagePlan[0];
|
||||
|
||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||
var provider = router.LlmConfig.Provider ?? "openai";
|
||||
var model = llmProviderService.GetProviderModel(provider, router.LlmConfig.Model ?? "gpt-4o");
|
||||
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: provider,
|
||||
model: model.Name);
|
||||
|
||||
string text = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var response = await completion.GetChatCompletions(new Agent
|
||||
{
|
||||
Id = router.Id,
|
||||
Name = nameof(TwoStagePlanner),
|
||||
Instruction = firstStagePlanPrompt
|
||||
}, dialogs);
|
||||
|
||||
text = response.Content;
|
||||
plan = response.Content.JsonArrayContent<FirstStagePlan>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{ex.Message}: {text}");
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
private async Task<string> GetFirstStagePlanPrompt(Agent router)
|
||||
{
|
||||
var template = router.Templates.First(x => x.Name == "two_stage.1st.plan").Content;
|
||||
|
|
@ -257,7 +222,7 @@ public partial class TwoStageTaskPlanner : IRoutingPlaner
|
|||
var response = await completion.GetChatCompletions(new Agent
|
||||
{
|
||||
Id = router.Id,
|
||||
Name = nameof(TwoStagePlanner),
|
||||
Name = nameof(TwoStageTaskPlanner),
|
||||
Instruction = firstStageSystemPrompt
|
||||
}, conversations);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"iconUrl": "https://e7.pngegg.com/pngimages/775/350/png-clipart-action-plan-computer-icons-plan-miscellaneous-text-thumbnail.png",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"profiles": [ "tool" ],
|
||||
"profiles": [ "planning" ],
|
||||
"utilities": [ "two-stage-planner" ],
|
||||
"llmConfig": {
|
||||
"provider": "openai",
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@ Global Knowledge:
|
|||
{% for k in global_knowledges %}
|
||||
{{ k }}
|
||||
{% endfor %}
|
||||
=====
|
||||
{%- endif %}
|
||||
|
|
@ -36,22 +36,14 @@ public class GetTableDefinitionFn : IFunctionCallback
|
|||
{
|
||||
try
|
||||
{
|
||||
var sql = $"select * from information_schema.tables where table_name = @tableName";
|
||||
var escapedTableName = MySqlHelper.EscapeString(table);
|
||||
var sql = $"SHOW CREATE TABLE `{escapedTableName}`";
|
||||
|
||||
var result = connection.QueryFirstOrDefault(sql, new
|
||||
{
|
||||
tableName = escapedTableName
|
||||
});
|
||||
|
||||
if (result == null) continue;
|
||||
|
||||
sql = $"SHOW CREATE TABLE `{escapedTableName}`";
|
||||
using var command = new MySqlCommand(sql, connection);
|
||||
using var reader = command.ExecuteReader();
|
||||
if (reader.Read())
|
||||
{
|
||||
result = reader.GetString(1);
|
||||
var result = reader.GetString(1);
|
||||
tableDdls.Add(result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,13 +91,13 @@ public class DbKnowledgeService
|
|||
private string GetTableStructure(string table)
|
||||
{
|
||||
var settings = _services.GetRequiredService<SqlDriverSetting>();
|
||||
using var connection = new MySqlConnection(settings.MySqlConnectionString);
|
||||
connection.Open();
|
||||
|
||||
|
||||
var ddl = string.Empty;
|
||||
var escapedTableName = MySqlHelper.EscapeString(table);
|
||||
var sql = $"SHOW CREATE TABLE `{escapedTableName}`";
|
||||
|
||||
using var connection = new MySqlConnection(settings.MySqlConnectionString);
|
||||
connection.Open();
|
||||
using var command = new MySqlCommand(sql, connection);
|
||||
using var reader = command.ExecuteReader();
|
||||
if (reader.Read())
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"updatedDateTime": "2023-11-15T13:49:00Z",
|
||||
"disabled": false,
|
||||
"isPublic": true,
|
||||
"profiles": [ "tool", "sql" ],
|
||||
"profiles": [ "database" ],
|
||||
"llmConfig": {
|
||||
"model": "gpt-4-0125",
|
||||
"model3": "gpt-35-turbo-1106",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class TwilioVoiceController : TwilioController
|
|||
string conversationId = $"TwilioVoice_{request.CallSid}";
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
var url = $"twilio/voice/{conversationId}/receive/0?states={states}";
|
||||
var response = twilio.ReturnNoninterruptedInstructions(new List<string> { "twilio/welcome.mp3" }, url, true);
|
||||
var response = twilio.ReturnNoninterruptedInstructions(new List<string> { "twilio/welcome.mp3" }, url, true, timeout: 2);
|
||||
return TwiML(response);
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +82,16 @@ public class TwilioVoiceController : TwilioController
|
|||
}
|
||||
}
|
||||
|
||||
await messageQueue.EnqueueAsync(callerMessage);
|
||||
|
||||
response = new VoiceResponse().Redirect(new Uri($"{_settings.CallbackHost}/twilio/voice/{conversationId}/reply/{seqNum}?states={states}"), HttpMethod.Post);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attempts >= 3)
|
||||
if (attempts >= 2)
|
||||
{
|
||||
var speechPaths = new List<string>();
|
||||
|
||||
if (seqNum == 0)
|
||||
{
|
||||
speechPaths.Add("twilio/welcome.mp3");
|
||||
|
|
@ -96,6 +99,7 @@ public class TwilioVoiceController : TwilioController
|
|||
else
|
||||
{
|
||||
var lastRepy = await sessionManager.GetAssistantReplyAsync(conversationId, seqNum - 1);
|
||||
speechPaths.Add($"twilio/say-it-again-{Random.Shared.Next(1, 5)}.mp3");
|
||||
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{lastRepy.SpeechFileName}");
|
||||
}
|
||||
response = twilio.ReturnInstructions(speechPaths, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
|
||||
|
|
@ -103,14 +107,14 @@ public class TwilioVoiceController : TwilioController
|
|||
else
|
||||
{
|
||||
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}&attempts={++attempts}", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return TwiML(response);
|
||||
}
|
||||
|
||||
[ValidateRequest]
|
||||
[HttpPost("twilio/voice/{conversationId}/reply/{seqNum}")]
|
||||
public async Task<TwiMLResult> ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
|
||||
public async Task<TwiMLResult> ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
|
||||
[FromQuery] string states, VoiceRequest request)
|
||||
{
|
||||
var nextSeqNum = seqNum + 1;
|
||||
|
|
@ -148,6 +152,8 @@ public class TwilioVoiceController : TwilioController
|
|||
var fileName = $"indication_{seqNum}_{segIndex}.mp3";
|
||||
fileStorage.SaveSpeechFile(conversationId, fileName, data);
|
||||
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{fileName}");
|
||||
// add typing
|
||||
speechPaths.Add($"twilio/typing-{Random.Shared.Next(1, 4)}.mp3");
|
||||
segIndex++;
|
||||
}
|
||||
}
|
||||
|
|
@ -156,16 +162,20 @@ public class TwilioVoiceController : TwilioController
|
|||
}
|
||||
else
|
||||
{
|
||||
response = twilio.ReturnInstructions(new List<string>
|
||||
response = twilio.ReturnInstructions(new List<string>
|
||||
{
|
||||
$"twilio/hold-on-{Random.Shared.Next(1, 5)}.mp3",
|
||||
$"twilio/typing-{Random.Shared.Next(2, 4)}.mp3"
|
||||
$"twilio/hold-on-{Random.Shared.Next(1, 6)}.mp3",
|
||||
$"twilio/typing-{Random.Shared.Next(1, 4)}.mp3"
|
||||
}, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reply.ConversationEnd)
|
||||
if (reply.HumanIntervationNeeded)
|
||||
{
|
||||
response = twilio.DialCsrAgent($"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}");
|
||||
}
|
||||
else if (reply.ConversationEnd)
|
||||
{
|
||||
response = twilio.HangUp($"twilio/voice/speeches/{conversationId}/{reply.SpeechFileName}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ namespace BotSharp.Plugin.Twilio.Models
|
|||
public class AssistantMessage
|
||||
{
|
||||
public bool ConversationEnd { get; set; }
|
||||
public bool HumanIntervationNeeded { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string MessageId { get; set; }
|
||||
public string SpeechFileName { get; set; }
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ namespace BotSharp.Plugin.Twilio.Services
|
|||
reply = new AssistantMessage()
|
||||
{
|
||||
ConversationEnd = msg.Instruction?.ConversationEnd ?? false,
|
||||
HumanIntervationNeeded = string.Equals("human_intervention_needed", msg.FunctionName),
|
||||
Content = msg.Content,
|
||||
MessageId = msg.MessageId
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ public class TwilioService
|
|||
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
|
||||
SpeechTimeout = "auto", // timeout > 0 ? timeout.ToString() : "3",
|
||||
Timeout = timeout > 0 ? timeout : 3,
|
||||
ActionOnEmptyResult = actionOnEmptyResult
|
||||
ActionOnEmptyResult = actionOnEmptyResult,
|
||||
Hints = "Yes, No, Correct"
|
||||
};
|
||||
|
||||
if (!speechPaths.IsNullOrEmpty())
|
||||
|
|
@ -113,7 +114,7 @@ public class TwilioService
|
|||
},
|
||||
Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"),
|
||||
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
|
||||
SpeechTimeout = "auto", // timeout > 0 ? timeout.ToString() : "3",
|
||||
SpeechTimeout = timeout > 0 ? timeout.ToString() : "3",
|
||||
Timeout = timeout > 0 ? timeout : 3,
|
||||
ActionOnEmptyResult = actionOnEmptyResult
|
||||
};
|
||||
|
|
@ -132,6 +133,17 @@ public class TwilioService
|
|||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse DialCsrAgent(string speechPath)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
if (!string.IsNullOrEmpty(speechPath))
|
||||
{
|
||||
response.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
|
||||
}
|
||||
response.Dial(_settings.CsrAgentNumber);
|
||||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse HoldOn(int interval, string message = null)
|
||||
{
|
||||
var twilioSetting = _services.GetRequiredService<TwilioSetting>();
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ public class TwilioSetting
|
|||
public string ApiSecret { get; set; }
|
||||
public string CallbackHost { get; set; }
|
||||
public string AgentId { get; set; }
|
||||
public string CsrAgentNumber { get; set; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue