diff --git a/docs/channels/components.md b/docs/channels/components.md new file mode 100644 index 00000000..3754a1c3 --- /dev/null +++ b/docs/channels/components.md @@ -0,0 +1,154 @@ +# Messaging Components + +Conversations are a lot more than simple text messages when you are building a AI chatbot. In addition to text, the `BotSharp`` allows you to send rich-media, like audio, video, and images, and provides a set of structured messaging options in the form of message templates, quick replies, buttons and more. The UI rendering program can render components according to the returned data format. + + +## Text Messages +```json +{ + "recipient":{ + "id":"{{conversation_id}}" + }, + "messaging_type": "RESPONSE", + "message":{ + "text":"Hello, world!" + } +} +``` +## Quick Replies + +`content_type`: Text, Phone Number and Email +```json +{ + "recipient":{ + "id":"{{conversation_id}}" + }, + "messaging_type": "RESPONSE", + "message":{ + "text": "Pick a color:", + "quick_replies":[ + { + "content_type":"text", + "title":"Red", + "payload":"", + "image_url":"http://example.com/img/red.png" + },{ + "content_type":"text", + "title":"Green", + "payload":"", + "image_url":"http://example.com/img/green.png" + } + ] + } +} +``` +## Sender Actions + +Setting expectations is crucial when creating a chatbot. Sender actions, a key tool, allow you to control typing and read receipt indicators. For instance, you can use them to show when a message has been seen or when a response is being typed, keeping users informed during interactions. + +`sender_action`: mark_seen, typing_on and typing_off +```json +{ + "recipient":{ + "id":"{{conversation_id}}" + }, + "sender_action":"typing_on" +} +``` +## Message Templates + +Message templates are structured message formats used for various purposes to present complex information in a tidy manner during conversations, preventing messy text. These templates also include buttons to enhance interactivity. It gives a way for you to offer a richer in-conversation experience than standard text messages by integrating buttons, images, lists, and more alongside text a single message. Templates can be use for many purposes, such as displaying product information, asking the message recipient to choose from a pre-determined set of options, and showing search results. + +```json +{ + "recipient":{ + "id":"{{conversation_id}}" + }, + "message":{ + "attachment":{ + "type":"template", + "payload":{ + "template_type":"TEMPLATE-TYPE", + "elements":[ + { + "title":"TEMPLATE-TITLE", + ... + } + ] + } + } + } +} +``` +### Button template + +The button template sends a text message with up to three attached buttons. This template is useful for offering the message recipient options to choose from, such as pre-determined responses to a question, or actions to take. + +`type`: web_url, postback, phone_number, account_link (log in), account_unlink (log out) + +```json +{ + "template_type":"button", + "text":"What do you want to do next?", + "buttons":[ + { + "type":"web_url", + "url":"https://www.github.com", + "title":"Visit Github" + }, + { + "type":"postback", + "title":"Visit Github", + "payload": "" + }, + { + "type":"phone_number", + "title":"", + "payload":"" + }, + { + "type": "account_link", + "url": "" + }, + { + "type": "account_unlink" + } + ] +} +``` + +### Generic template + +The generic template is a simple structured message that includes a title, subtitle, image, and up to three buttons. You may also specify a `default_action` object that sets a URL that will be opened in the chat webview when the template is tapped. + +```json +{ + "template_type":"generic", + "elements":[ + { + "title":"Welcome!", + "image_url":"https://raw.githubusercontent.com/fbsamples/original-coast-clothing/main/public/styles/male-work.jpg", + "subtitle":"We have the right hat for everyone.", + "default_action": { + "type": "web_url", + "url": "https://www.originalcoastclothing.com/", + "webview_height_ratio": "tall" + }, + "buttons":[ + { + "type":"web_url", + "url":"https://www.originalcoastclothing.com/", + "title":"View Website" + } + ] + } + ] +} +``` + +### Form template + +Form template is used to collect information from the user side, and the UI allows users to fill in a structured form. + +### Customer Feedback Template + diff --git a/docs/index.rst b/docs/index.rst index 663d5c78..8b3d08f6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -66,6 +66,7 @@ The main documentation for the site is organized into the following sections: :caption: Interactive Channels channels/intro + channels/components channels/messenger channels/wechat diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs index 715bfde5..808f7821 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs @@ -5,6 +5,8 @@ namespace BotSharp.Abstraction.Agents; public abstract class AgentHookBase : IAgentHook { + public virtual string SelfId => throw new NotImplementedException("Please set SelfId as agent id!"); + protected Agent _agent; public Agent Agent => _agent; diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs index f7b7379b..99cdadca 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs @@ -4,6 +4,10 @@ namespace BotSharp.Abstraction.Agents; public interface IAgentHook { + /// + /// Agent Id + /// + string SelfId { get; } Agent Agent { get; } void SetAget(Agent agent); diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index ba1ea69d..18ddee55 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -31,4 +31,8 @@ + + + + diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs index 975a17d6..d4e69e2a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionParametersDef.cs @@ -5,7 +5,7 @@ namespace BotSharp.Abstraction.Functions.Models; public class FunctionParametersDef { [JsonPropertyName("type")] - public string Type { get; set; } = "object"; + public string Type { get; set; } = "string"; /// /// ParameterPropertyDef diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs index 5aa7667a..88835216 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs @@ -13,7 +13,7 @@ public class RoutingRule /// /// Field type: string, number, object /// - public string Type { get; set; } + public string Type { get; set; } = "string"; public bool Required { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index f5f54a7e..91c82886 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -15,6 +15,11 @@ public partial class AgentService // Before agent is loaded. foreach (var hook in hooks) { + if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id) + { + continue; + } + hook.OnAgentLoading(ref id); } @@ -30,6 +35,11 @@ public partial class AgentService // After agent is loaded foreach (var hook in hooks) { + if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id) + { + continue; + } + hook.SetAget(agent); if (!string.IsNullOrEmpty(agent.Instruction)) diff --git a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs index 812c7684..6232c887 100644 --- a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs +++ b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs @@ -31,13 +31,13 @@ public class EvaluationConversationHook : ConversationHookBase public override Task OnHumanInterventionNeeded(RoleDialogModel message) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger event \"{message.FunctionName}\""); + _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); return base.OnHumanInterventionNeeded(message); } public override Task OnConversationEnding(RoleDialogModel message) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger event \"{message.FunctionName}\""); + _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); return base.OnConversationEnding(message); } } diff --git a/src/Infrastructure/BotSharp.Core/Evaluations/ExecutionLogger.cs b/src/Infrastructure/BotSharp.Core/Evaluations/ExecutionLogger.cs index a7e7b1f5..9a222554 100644 --- a/src/Infrastructure/BotSharp.Core/Evaluations/ExecutionLogger.cs +++ b/src/Infrastructure/BotSharp.Core/Evaluations/ExecutionLogger.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Evaluations; using BotSharp.Abstraction.Repositories; +using System.Text.RegularExpressions; namespace BotSharp.Core.Evaluations; @@ -17,6 +18,8 @@ public class ExecutionLogger : IExecutionLogger public void Append(string conversationId, string content) { + content = content.Replace("\r\n", " ").Replace("\n", " "); + content = Regex.Replace(content, @"\s+", " "); var db = _services.GetRequiredService(); db.AddExectionLogs(conversationId, new List { content }); } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs index cf802720..2a860267 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs @@ -1,13 +1,18 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Settings; namespace BotSharp.Core.Routing.Hooks; public class RoutingAgentHook : AgentHookBase { - public RoutingAgentHook(IServiceProvider services, AgentSettings settings) + private readonly RoutingSettings _routingSetting; + public override string SelfId => _routingSetting.RouterId; + + public RoutingAgentHook(IServiceProvider services, AgentSettings settings, RoutingSettings routingSetting) : base(services, settings) { + _routingSetting = routingSetting; } public override bool OnInstructionLoaded(string template, Dictionary dict) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs index c4ebb7f3..2893b7ff 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.MLTasks.Settings; using BotSharp.Abstraction.Templating; namespace BotSharp.Core.Routing; @@ -19,7 +20,8 @@ public partial class RoutingService var agentService = _services.GetRequiredService(); var agent = await agentService.LoadAgent(agentId); - var chatCompletion = CompletionProvider.GetChatCompletion(_services); + var settings = _services.GetRequiredService(); + var chatCompletion = CompletionProvider.GetChatCompletion(_services, provider: settings.Provider, model: settings.Model); RoleDialogModel response = chatCompletion.GetChatCompletions(agent, Dialogs); if (response.Role == AgentRole.Function)