commit
bef26ad542
|
|
@ -0,0 +1,9 @@
|
|||
namespace BotSharp.Abstraction.Infrastructures.Enums;
|
||||
|
||||
public class LanguageType
|
||||
{
|
||||
public const string UNKNOWN = "Unknown";
|
||||
public const string ENGLISH = "English";
|
||||
public const string SPANISH = "Spanish";
|
||||
public const string CHINESE = "Chinese";
|
||||
}
|
||||
|
|
@ -29,5 +29,6 @@ public class ElementButton
|
|||
|
||||
[JsonPropertyName("post_action_disclaimer")]
|
||||
[JsonProperty("post_action_disclaimer")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? PostActionDisclaimer { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public class GenericTemplateMessage<T> : IRichMessage, ITemplateMessage
|
|||
|
||||
[JsonPropertyName("text")]
|
||||
[JsonProperty("text")]
|
||||
[Translate]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("template_type")]
|
||||
|
|
@ -36,6 +37,7 @@ public class GenericTemplateMessage<T> : IRichMessage, ITemplateMessage
|
|||
|
||||
public class GenericElement
|
||||
{
|
||||
[Translate]
|
||||
public string Title { get; set; }
|
||||
public string Subtitle { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,12 @@ public class RoutingArgs
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string UserGoal { get; set; }
|
||||
|
||||
[JsonPropertyName("user_message_in_english")]
|
||||
public string UserMessageInEnglish { get; set; }
|
||||
|
||||
[JsonPropertyName("language")]
|
||||
public string Language { get; set; } = LanguageType.UNKNOWN;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var route = string.IsNullOrEmpty(AgentName) ? "" : $"<Route to {AgentName.ToUpper()} because {NextActionReason}>";
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@ namespace BotSharp.Abstraction.Translation;
|
|||
|
||||
public interface ITranslationService
|
||||
{
|
||||
T Translate<T>(T data, string language = "Spanish", bool clone = true) where T : class;
|
||||
Task<T> Translate<T>(Agent router, string messageId, T data, string language = "Spanish", bool clone = true) where T : class;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.plan.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.task.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid" />
|
||||
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\translation_prompt.liquid" />
|
||||
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\agent.json" />
|
||||
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\instruction.liquid" />
|
||||
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\templates\instruction.executor.liquid" />
|
||||
|
|
@ -118,6 +119,9 @@
|
|||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\.welcome.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\translation_prompt.liquid">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\agent.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -71,15 +71,6 @@ public partial class ConversationService
|
|||
}
|
||||
}
|
||||
|
||||
// Persist to storage
|
||||
if (!message.StopCompletion)
|
||||
{
|
||||
_storage.Append(_conversationId, message);
|
||||
|
||||
// Add to thread
|
||||
dialogs.Add(RoleDialogModel.From(message));
|
||||
}
|
||||
|
||||
if (!stopCompletion)
|
||||
{
|
||||
// Routing with reasoning
|
||||
|
|
|
|||
|
|
@ -10,10 +10,21 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
|
||||
public List<ParameterPropertyDef> Parameters => new List<ParameterPropertyDef>
|
||||
{
|
||||
new ParameterPropertyDef("reason", "why response to user directly without go to other agents"),
|
||||
new ParameterPropertyDef("response", "response content to user in courteous words. If the user wants to end the conversation, you must set conversation_end to true and response politely."),
|
||||
new ParameterPropertyDef("conversation_end", "whether to end this conversation", type: "boolean"),
|
||||
new ParameterPropertyDef("task_completed ", "whether the user's task request has been completed.", type: "boolean")
|
||||
new ParameterPropertyDef("reason",
|
||||
"why response to user directly without go to other agents"),
|
||||
new ParameterPropertyDef("response",
|
||||
"response content to user in courteous words with language English. If the user wants to end the conversation, you must set conversation_end to true and response politely."),
|
||||
new ParameterPropertyDef("conversation_end",
|
||||
"whether to end this conversation",
|
||||
type: "boolean"),
|
||||
new ParameterPropertyDef("task_completed ",
|
||||
"whether the user's task request has been completed.",
|
||||
type: "boolean"),
|
||||
new ParameterPropertyDef("user_message_in_english",
|
||||
"Translate user message from non-English to English"),
|
||||
new ParameterPropertyDef("language",
|
||||
"Language name of the message user sent, the name may be English, Spanish or Chinese.",
|
||||
required: true),
|
||||
};
|
||||
|
||||
public ResponseToUserRoutingHandler(IServiceProvider services, ILogger<ResponseToUserRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
|
|||
type: "object"),
|
||||
new ParameterPropertyDef("is_new_task",
|
||||
"whether the user is requesting a new task that is different from the previous topic.",
|
||||
type: "boolean")
|
||||
type: "boolean"),
|
||||
new ParameterPropertyDef("user_message_in_english",
|
||||
"Translate user message from non-English to English"),
|
||||
new ParameterPropertyDef("language",
|
||||
"Language name of the message user sent, the name may be English, Spanish or Chinese.",
|
||||
required: true),
|
||||
};
|
||||
|
||||
public RouteToAgentRoutingHandler(IServiceProvider services, ILogger<RouteToAgentRoutingHandler> logger, RoutingSettings settings)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Infrastructures.Enums;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using BotSharp.Abstraction.Routing.Planning;
|
||||
using BotSharp.Abstraction.Routing.Settings;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using BotSharp.Core.Routing.Planning;
|
||||
using Fluid.Ast;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using ThirdParty.Json.LitJson;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace BotSharp.Core.Routing;
|
||||
|
||||
|
|
@ -39,15 +51,10 @@ public partial class RoutingService : IRoutingService
|
|||
var handler = handlers.FirstOrDefault(x => x.Name == "route_to_agent");
|
||||
|
||||
var conv = _services.GetRequiredService<IConversationService>();
|
||||
var dialogs = new List<RoleDialogModel>();
|
||||
if (conv.States.GetState("hide_context", "false") == "true")
|
||||
{
|
||||
dialogs.Add(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
dialogs = conv.GetDialogHistory();
|
||||
}
|
||||
var storage = _services.GetRequiredService<IConversationStorage>();
|
||||
storage.Append(conv.ConversationId, message);
|
||||
|
||||
var dialogs = conv.GetDialogHistory();
|
||||
handler.SetDialogs(dialogs);
|
||||
|
||||
var inst = new FunctionCallFromLlm
|
||||
|
|
@ -71,11 +78,14 @@ public partial class RoutingService : IRoutingService
|
|||
|
||||
public async Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs)
|
||||
{
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
_router = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
RoleDialogModel response = default;
|
||||
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var storage = _services.GetRequiredService<IConversationStorage>();
|
||||
|
||||
_router = await agentService.LoadAgent(message.CurrentAgentId);
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var executor = _services.GetRequiredService<IExecutor>();
|
||||
|
||||
|
|
@ -83,17 +93,23 @@ public partial class RoutingService : IRoutingService
|
|||
|
||||
_context.Push(_router.Id);
|
||||
|
||||
int loopCount = 0;
|
||||
while (loopCount < planner.MaxLoopCount && !_context.IsEmpty)
|
||||
dialogs.Add(message);
|
||||
|
||||
// Get first instruction
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
|
||||
// Handle multi-language for input
|
||||
|
||||
if (inst.Language != LanguageType.UNKNOWN && inst.Language != LanguageType.ENGLISH)
|
||||
{
|
||||
loopCount++;
|
||||
|
||||
var conversation = await GetConversationContent(dialogs);
|
||||
_router.TemplateDict["conversation"] = conversation;
|
||||
|
||||
// Get instruction from Planner
|
||||
var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
message.Content = inst.UserMessageInEnglish;
|
||||
}
|
||||
storage.Append(convService.ConversationId, message);
|
||||
|
||||
int loopCount = 1;
|
||||
while (true)
|
||||
{
|
||||
await HookEmitter.Emit<IRoutingHook>(_services, async hook =>
|
||||
await hook.OnRoutingInstructionReceived(inst, message)
|
||||
);
|
||||
|
|
@ -121,6 +137,29 @@ public partial class RoutingService : IRoutingService
|
|||
}
|
||||
|
||||
await planner.AgentExecuted(_router, inst, response, dialogs);
|
||||
|
||||
if (loopCount >= planner.MaxLoopCount || _context.IsEmpty)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get next instruction from Planner
|
||||
_router.TemplateDict["conversation"] = await GetConversationContent(dialogs);
|
||||
inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs);
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
// Handle multi-language for output
|
||||
if (inst.Language != LanguageType.UNKNOWN && inst.Language != LanguageType.ENGLISH)
|
||||
{
|
||||
if (response.RichContent != null)
|
||||
{
|
||||
var translator = _services.GetRequiredService<ITranslationService>();
|
||||
response.RichContent.Message = await translator.Translate(_router,
|
||||
message.MessageId,
|
||||
response.RichContent.Message,
|
||||
language: inst.Language);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using Amazon.Runtime.Internal.Transform;
|
||||
using BotSharp.Abstraction.Options;
|
||||
using BotSharp.Abstraction.Templating;
|
||||
using BotSharp.Abstraction.Translation.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using System.Reflection;
|
||||
|
|
@ -10,6 +12,8 @@ public class TranslationService : ITranslationService
|
|||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<TranslationService> _logger;
|
||||
private readonly BotSharpOptions _options;
|
||||
private Agent _router;
|
||||
private string _messageId;
|
||||
|
||||
public TranslationService(IServiceProvider services,
|
||||
ILogger<TranslationService> logger,
|
||||
|
|
@ -20,8 +24,10 @@ public class TranslationService : ITranslationService
|
|||
_options = options;
|
||||
}
|
||||
|
||||
public T Translate<T>(T data, string language = "Spanish", bool clone = true) where T : class
|
||||
public async Task<T> Translate<T>(Agent router, string messageId, T data, string language = "Spanish", bool clone = true) where T : class
|
||||
{
|
||||
_router = router;
|
||||
_messageId = messageId;
|
||||
var cloned = data;
|
||||
if (clone)
|
||||
{
|
||||
|
|
@ -30,7 +36,7 @@ public class TranslationService : ITranslationService
|
|||
|
||||
var unique = new HashSet<string>();
|
||||
Collect(cloned, ref unique);
|
||||
var map = InnerTranslate(unique, language);
|
||||
var map = await InnerTranslate(unique, language);
|
||||
cloned = Assign(cloned, map);
|
||||
return cloned;
|
||||
}
|
||||
|
|
@ -250,14 +256,44 @@ public class TranslationService : ITranslationService
|
|||
/// <param name="list"></param>
|
||||
/// <param name="language"></param>
|
||||
/// <returns></returns>
|
||||
private Dictionary<string, string> InnerTranslate(HashSet<string> list, string language)
|
||||
private async Task<Dictionary<string, string>> InnerTranslate(HashSet<string> list, string language)
|
||||
{
|
||||
var map = new Dictionary<string, string>();
|
||||
if (list == null || !list.Any()) return map;
|
||||
// chat completion
|
||||
var completion = CompletionProvider.GetChatCompletion(_services,
|
||||
provider: _router?.LlmConfig?.Provider,
|
||||
model: _router?.LlmConfig?.Model);
|
||||
|
||||
foreach (var item in list)
|
||||
var texts = list.ToArray();
|
||||
var translator = new Agent
|
||||
{
|
||||
map.Add(item, "hello world");
|
||||
Id = Guid.Empty.ToString(),
|
||||
Name = "Translator",
|
||||
TemplateDict = new Dictionary<string, object>
|
||||
{
|
||||
{ "text_list", JsonConvert.SerializeObject(texts) },
|
||||
{ "language", language }
|
||||
}
|
||||
};
|
||||
|
||||
var template = _router.Templates.First(x => x.Name == "translation_prompt").Content;
|
||||
var render = _services.GetRequiredService<ITemplateRender>();
|
||||
var prompt = render.Render(template, translator.TemplateDict);
|
||||
|
||||
var translationDialogs = new List<RoleDialogModel>
|
||||
{
|
||||
new RoleDialogModel(AgentRole.User, prompt)
|
||||
{
|
||||
FunctionName = "translation_prompt",
|
||||
MessageId = _messageId
|
||||
}
|
||||
};
|
||||
var translationResponse = await completion.GetChatCompletions(translator, translationDialogs);
|
||||
var translatedTexts = translationResponse.Content.JsonArrayContent<string>();
|
||||
var map = new Dictionary<string, string>();
|
||||
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
map.Add(texts[i], translatedTexts[i]);
|
||||
}
|
||||
|
||||
return map;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
You're {{router.name}} ({{router.description}}). Follow these steps to handle user request:
|
||||
You're {{router.name}} ({{router.description}}).
|
||||
You can understand messages sent by users in different languages.
|
||||
Follow these steps to handle user request:
|
||||
1. Read the [CONVERSATION] content.
|
||||
2. Select a appropriate function from [FUNCTIONS].
|
||||
3. Determine which agent is suitable to handle this conversation.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{{ text_list }}
|
||||
|
||||
=====
|
||||
Translate the sentences in the list into {{ language }}, output the translated text list.
|
||||
|
||||
Loading…
Reference in a new issue