diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs index 2a1f18fa..8b0769a7 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRouting.cs @@ -2,5 +2,6 @@ namespace BotSharp.Abstraction.Agents; public interface IAgentRouting { + Task LoadRouter(); Task LoadCurrentAgent(); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs new file mode 100644 index 00000000..4046cda4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Abstraction.Agents.Models; + +public class AgentRoutingArgs +{ + [JsonPropertyName("agent_id")] + public string AgentId { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index 740547a3..6f56d00b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -20,12 +20,14 @@ public interface IConversationService /// /// /// This delegate is useful when you want to report progress on UI + /// This delegate is useful when you want to report progress on UI /// Task SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func onMessageReceived, - Func onFunctionExecuting); + Func onFunctionExecuting, + Func onFunctionExecuted); List GetDialogHistory(string conversationId, int lastCount = 20); Task CleanHistory(string agentId); diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index 3335617e..bc460159 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -20,10 +20,16 @@ public class RoleDialogModel public string? FunctionArgs { get; set; } /// - /// Function execution result + /// Function execution result, this result will be seen by LLM. /// public string? ExecutionResult { get; set; } + /// + /// Function execution structured data, this data won't pass to LLM. + /// It's ideal to render in rich content in UI. + /// + public object ExecutionData { get; set; } + public bool IsConversationEnd { get; set; } public bool NeedReloadAgent { get; set; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Settings/ConversationSetting.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Settings/ConversationSetting.cs index 48e81061..80897657 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Settings/ConversationSetting.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Settings/ConversationSetting.cs @@ -5,4 +5,5 @@ public class ConversationSetting public string DataDir { get; set; } public string ChatCompletion { get; set; } public bool EnableKnowledgeBase { get; set; } + public bool ShowVerboseLog { get; set; } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs index 1c28bad3..f14ed93c 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Agents; using BotSharp.Abstraction.Agents.Models; namespace BotSharp.Core.Agents.Services; @@ -17,11 +18,18 @@ public class AgentRouter : IAgentRouting _settings = settings; } + public async Task LoadRouter() + { + var agentService = _services.GetRequiredService(); + var agent = await agentService.LoadAgent(_settings.RouterId); + return agent; + } + public async Task LoadCurrentAgent() { // Load current agent from state var state = _services.GetRequiredService(); - var currentAgentId = state.GetState("agentId"); + var currentAgentId = state.GetState("agent_id"); if (string.IsNullOrEmpty(currentAgentId)) { currentAgentId = _settings.RouterId; @@ -30,7 +38,7 @@ public class AgentRouter : IAgentRouting var agent = await agentService.LoadAgent(currentAgentId); // Set agent and trigger state changed - state.SetState("agentId", currentAgentId); + state.SetState("agent_id", currentAgentId); return agent; } diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index ceb5a348..6b871db4 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -73,7 +73,6 @@ - diff --git a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs index 4607086a..ae315146 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs @@ -38,6 +38,7 @@ public static class BotSharpServiceCollectionExtensions services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs index 1180c7e6..71698ebd 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs @@ -15,7 +15,8 @@ public partial class ConversationService Agent agent, List wholeDialogs, Func onMessageReceived, - Func onFunctionExecuting) + Func onFunctionExecuting, + Func onFunctionExecuted) { currentRecursiveDepth++; if (currentRecursiveDepth > maxRecursiveDepth) @@ -23,7 +24,8 @@ public partial class ConversationService _logger.LogError($"Exceed max current recursive depth."); await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, "System has exception, please try later.") { - CurrentAgentId = agent.Id + CurrentAgentId = agent.Id, + Channel = wholeDialogs.Last().Channel }, onMessageReceived); return false; } @@ -38,14 +40,15 @@ public partial class ConversationService { var preAgentId = agent.Id; - await HandleFunctionMessage(fn, onFunctionExecuting); + await HandleFunctionMessage(fn, onFunctionExecuting, onFunctionExecuted); // Function executed has exception if (fn.ExecutionResult == null) { await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, fn.Content) { - CurrentAgentId = fn.CurrentAgentId + CurrentAgentId = fn.CurrentAgentId, + Channel = fn.Channel }, onMessageReceived); return; } @@ -58,10 +61,6 @@ public partial class ConversationService var agentSettings = _services.GetRequiredService(); var agentService = _services.GetRequiredService(); agent = await agentService.LoadAgent(fn.CurrentAgentId); - - // Set state to make next conversation will go to this agent directly - // var state = _services.GetRequiredService(); - // state.SetState("agentId", fn.CurrentAgentId); } // Add to dialog history @@ -70,7 +69,13 @@ public partial class ConversationService // After function is executed, pass the result to LLM to get a natural response wholeDialogs.Add(fn); - await GetChatCompletionsAsyncRecursively(chatCompletion, conversationId, agent, wholeDialogs, onMessageReceived, onFunctionExecuting); + await GetChatCompletionsAsyncRecursively(chatCompletion, + conversationId, + agent, + wholeDialogs, + onMessageReceived, + onFunctionExecuting, + onFunctionExecuted); }); return result; @@ -89,7 +94,9 @@ public partial class ConversationService await onMessageReceived(msg); } - private async Task HandleFunctionMessage(RoleDialogModel msg, Func onFunctionExecuting) + private async Task HandleFunctionMessage(RoleDialogModel msg, + Func onFunctionExecuting, + Func onFunctionExecuted) { // Save states SaveStateByArgs(msg.FunctionArgs); @@ -97,5 +104,6 @@ public partial class ConversationService // Call functions await onFunctionExecuting(msg); await CallFunctions(msg); + await onFunctionExecuted(msg); } } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index b4ab98f5..521f3054 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -8,7 +8,8 @@ public partial class ConversationService public async Task SendMessage(string agentId, string conversationId, RoleDialogModel lastDialog, Func onMessageReceived, - Func onFunctionExecuting) + Func onFunctionExecuting, + Func onFunctionExecuted) { var converation = await GetConversation(conversationId); @@ -27,16 +28,19 @@ public partial class ConversationService var stateService = _services.GetRequiredService(); stateService.SetConversation(conversationId); stateService.Load(); + stateService.SetState("channel", lastDialog.Channel); var router = _services.GetRequiredService(); - var agent = await router.LoadCurrentAgent(); + var agent = await router.LoadRouter(); _logger.LogInformation($"[{agent.Name}] {lastDialog.Role}: {lastDialog.Content}"); lastDialog.CurrentAgentId = agent.Id; - _storage.Append(conversationId, agent.Id, lastDialog); - + var wholeDialogs = GetDialogHistory(conversationId); + wholeDialogs.Add(lastDialog); + + _storage.Append(conversationId, agent.Id, lastDialog); // Get relevant domain knowledge /*if (_settings.EnableKnowledgeBase) @@ -67,7 +71,8 @@ public partial class ConversationService agent, wholeDialogs, onMessageReceived, - onFunctionExecuting); + onFunctionExecuting, + onFunctionExecuted); return result; } diff --git a/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs new file mode 100644 index 00000000..c8cd625d --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs @@ -0,0 +1,36 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Functions; +using BotSharp.Abstraction.Functions.Models; + +namespace BotSharp.Core.Functions; + +public class RouteToAgentFn : IFunctionCallback +{ + public string Name => "route_to_agent"; + private readonly IServiceProvider _services; + + public RouteToAgentFn(IServiceProvider services) + { + _services = services; + } + + public async Task Execute(RoleDialogModel message) + { + var args = JsonSerializer.Deserialize(message.FunctionArgs); + + if (string.IsNullOrEmpty(args.AgentId)) + { + var result = new FunctionExecutionValidationResult("false", "agent_id can't be parsed."); + message.ExecutionResult = JsonSerializer.Serialize(result); + } + else + { + var result = new FunctionExecutionValidationResult("true"); + message.ExecutionResult = JsonSerializer.Serialize(result); + message.CurrentAgentId = args.AgentId; + } + + return true; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs index 516b906f..60bc3d3d 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/PluginLoader.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Configuration; using System.Drawing; using System.IO; using System.Reflection; -using Console = Colorful.Console; namespace BotSharp.Core.Plugins; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index dab95e50..026a7874 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -1,8 +1,6 @@ using BotSharp.Abstraction.ApiAdapters; using BotSharp.Abstraction.Conversations.Models; using BotSharp.OpenAPI.ViewModels.Conversations; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; namespace BotSharp.OpenAPI.Controllers; @@ -50,11 +48,23 @@ public class ConversationController : ControllerBase, IApiAdapter var stackMsg = new List(); await conv.SendMessage(agentId, conversationId, - new RoleDialogModel("user", input.Text), + new RoleDialogModel("user", input.Text) + { + Channel = "webapi" + }, async msg => - stackMsg.Add(msg), - async fn - => await Task.CompletedTask); + { + stackMsg.Add(msg); + }, + async fnExecuting => + { + + }, + async fnExecuted => + { + response.Function = fnExecuted.FunctionName; + response.Data = fnExecuted.ExecutionData; + }); response.Text = string.Join("\r\n", stackMsg.Select(x => x.Content)); return response; diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs index b6a6e1e4..5f7241c0 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/MessageResponseModel.cs @@ -3,4 +3,6 @@ namespace BotSharp.OpenAPI.ViewModels.Conversations; public class MessageResponseModel { public string Text { get; set; } + public string Function { get; set; } + public object Data { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index 111a5412..0e8438d8 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -3,9 +3,11 @@ using Azure.AI.OpenAI; using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Conversations.Settings; using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.MLTasks; using BotSharp.Plugin.AzureOpenAI.Settings; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -18,12 +20,16 @@ namespace BotSharp.Plugin.AzureOpenAI.Providers; public class ChatCompletionProvider : IChatCompletion { private readonly AzureOpenAiSettings _settings; + private readonly IServiceProvider _services; private readonly ILogger _logger; - public ChatCompletionProvider(AzureOpenAiSettings settings, ILogger logger) + public ChatCompletionProvider(AzureOpenAiSettings settings, + ILogger logger, + IServiceProvider services) { _settings = settings; _logger = logger; + _services = services; } private OpenAIClient GetClient() @@ -98,7 +104,8 @@ public class ChatCompletionProvider : IChatCompletion { CurrentAgentId = agent.Id, FunctionName = message.FunctionCall.Name, - FunctionArgs = message.FunctionCall.Arguments + FunctionArgs = message.FunctionCall.Arguments, + Channel = conversations.Last().Channel }; // Execute functions @@ -110,7 +117,8 @@ public class ChatCompletionProvider : IChatCompletion var msg = new RoleDialogModel(AgentRole.Assistant, message.Content) { - CurrentAgentId= agent.Id + CurrentAgentId= agent.Id, + Channel = conversations.Last().Channel }; // Text response received @@ -215,7 +223,18 @@ public class ChatCompletionProvider : IChatCompletion chatCompletionsOptions.Temperature = 0.5f; chatCompletionsOptions.NucleusSamplingFactor = 0.5f; - _logger.LogInformation(string.Join("\n", chatCompletionsOptions.Messages.Select(x => $"{x.Role}: {x.Content}"))); + var convSetting = _services.GetRequiredService(); + if (convSetting.ShowVerboseLog) + { + var verbose = string.Join("\n", chatCompletionsOptions.Messages.Select(x => + { + return x.Role == ChatRole.Function ? + $"{x.Role}: {x.Name} {x.Content}" : + $"{x.Role}: {x.Content}"; + })); + _logger.LogInformation(verbose); + } + return chatCompletionsOptions; } } diff --git a/src/Plugins/BotSharp.Plugin.ChatbotUI/ChatbotUiController.cs b/src/Plugins/BotSharp.Plugin.ChatbotUI/ChatbotUiController.cs index 84c8e309..89bd7a95 100644 --- a/src/Plugins/BotSharp.Plugin.ChatbotUI/ChatbotUiController.cs +++ b/src/Plugins/BotSharp.Plugin.ChatbotUI/ChatbotUiController.cs @@ -64,7 +64,10 @@ public class ChatbotUiController : ControllerBase, IApiAdapter var conversation = input.Messages .Where(x => x.Role == AgentRole.User) - .Select(x => new RoleDialogModel(x.Role, x.Content)) + .Select(x => new RoleDialogModel(x.Role, x.Content) + { + Channel = "webchat" + }) .Last(); var conversationService = _services.GetRequiredService(); @@ -75,6 +78,8 @@ public class ChatbotUiController : ControllerBase, IApiAdapter async msg => await OnChunkReceived(outputStream, msg), async fn + => await Task.CompletedTask, + async fn => await Task.CompletedTask); await OnEventCompleted(outputStream); diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs index 2e45f60b..47e87dc3 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs @@ -15,7 +15,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Refit; -using BotSharp.Abstraction.Agents.Enums; +using Microsoft.Extensions.Logging; namespace BotSharp.Plugin.MetaMessenger.Controllers; @@ -27,10 +27,12 @@ namespace BotSharp.Plugin.MetaMessenger.Controllers; public class WebhookController : ControllerBase { private readonly IServiceProvider _services; + private readonly ILogger _logger; - public WebhookController(IServiceProvider services) + public WebhookController(IServiceProvider services, ILogger logger) { _services = services; + _logger = logger; } [HttpGet("/messenger/webhook/{agentId}")] @@ -67,7 +69,7 @@ public class WebhookController : ControllerBase { var conv = _services.GetRequiredService(); - string content = ""; + var reply = new QuickReplyMessage(); var senderId = req.Entry[0].Messaging[0].Sender.Id; var input = req.Entry[0].Messaging[0].Message.Text; @@ -78,11 +80,13 @@ public class WebhookController : ControllerBase PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }; + var recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt); + // Marking seen await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest { AccessToken = setting.PageAccessToken, - Recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt), + Recipient = recipient, SenderAction = SenderActionEnum.MarkSeen }); @@ -90,7 +94,7 @@ public class WebhookController : ControllerBase await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest { AccessToken = setting.PageAccessToken, - Recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt), + Recipient = recipient, SenderAction = SenderActionEnum.TypingOn }); @@ -100,12 +104,8 @@ public class WebhookController : ControllerBase Channel = "messenger" }, async msg => { - if (msg.Role == AgentRole.Function) - { - - } - content = msg.Content; - }, async fn => + reply.Text = msg.Content; + }, async functionExecuting => { /*await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest { @@ -113,28 +113,39 @@ public class WebhookController : ControllerBase Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt), Message = JsonSerializer.Serialize(new { Text = "I'm pulling the relevent information, please wait a second ..." }, jsonOpt) });*/ - - await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest + }, async functionExecuted => + { + // Render structured data + if (functionExecuted.ExecutionData != null) { - AccessToken = setting.PageAccessToken, - Recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt), - SenderAction = SenderActionEnum.TypingOn - }); + // validate data format + var json = JsonSerializer.Serialize(functionExecuted.ExecutionData, jsonOpt); + + try + { + var parsed = JsonSerializer.Deserialize(json, jsonOpt); + reply.QuickReplies = parsed; + } + catch(Exception ex) + { + _logger.LogError(ex, ex.Message); + } + } }); // Response to user await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest { AccessToken = setting.PageAccessToken, - Recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt), - Message = JsonSerializer.Serialize(new { Text = content }, jsonOpt) + Recipient = recipient, + Message = JsonSerializer.Serialize(reply, jsonOpt) }); // Typing off await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest { AccessToken = setting.PageAccessToken, - Recipient = JsonSerializer.Serialize(new { Id = senderId }, jsonOpt), + Recipient = recipient, SenderAction = SenderActionEnum.TypingOff }); } diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/Interfaces/IResponseMessage.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/Interfaces/IResponseMessage.cs new file mode 100644 index 00000000..c03e5ea9 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/Interfaces/IResponseMessage.cs @@ -0,0 +1,5 @@ +namespace BotSharp.Plugin.MetaMessenger.Interfaces; + +public interface IResponseMessage +{ +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachementPayload.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachementPayload.cs new file mode 100644 index 00000000..f78fd762 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachementPayload.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +public class AttachementPayload +{ + [JsonPropertyName("template_type")] + public string TemplateType { get; set; } + public string Text { get; set; } + public ButtonItem[] Buttons { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachmentBody.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachmentBody.cs new file mode 100644 index 00000000..90c5de53 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/AttachmentBody.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +public class AttachmentBody +{ + public string Type { get; set; } = "template"; + public AttachementPayload Payload { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/ButtonItem.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/ButtonItem.cs new file mode 100644 index 00000000..143e966b --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/ButtonItem.cs @@ -0,0 +1,8 @@ +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +public class ButtonItem +{ + public string Type { get; set; } + public string Title { get; set; } + public string Url { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs new file mode 100644 index 00000000..e0db6925 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs @@ -0,0 +1,17 @@ +using BotSharp.Plugin.MetaMessenger.Interfaces; +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +/// +/// Quick Replies +/// https://developers.facebook.com/docs/messenger-platform/send-messages/quick-replies +/// +public class QuickReplyMessage : IResponseMessage +{ + [JsonPropertyName("text")] + public string Text { get; set; } + + [JsonPropertyName("quick_replies")] + public QuickReplyMessageItem[] QuickReplies { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessageItem.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessageItem.cs new file mode 100644 index 00000000..a8782d69 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessageItem.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +public class QuickReplyMessageItem +{ + [JsonPropertyName("content_type")] + public string ContentType { get; set; } = "text"; + + [JsonPropertyName("title")] + public string Title { get; set; } + + [JsonPropertyName("payload")] + public string Payload { get; set; } + + [JsonPropertyName("image_url")] + public string ImageUrl { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/TemplateMessage.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/TemplateMessage.cs new file mode 100644 index 00000000..1981b258 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/TemplateMessage.cs @@ -0,0 +1,13 @@ +using BotSharp.Plugin.MetaMessenger.Interfaces; +using System.Text.Json.Serialization; + +namespace BotSharp.Plugin.MetaMessenger.MessagingModels; + +/// +/// https://developers.facebook.com/docs/messenger-platform/send-messages/templates +/// +public class TemplateMessage : IResponseMessage +{ + [JsonPropertyName("attachment")] + public AttachmentBody Attachment { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/WebhookModels/WebhookMessageBody.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/WebhookModels/WebhookMessageBody.cs index 3da17142..0c745c9e 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/WebhookModels/WebhookMessageBody.cs +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/WebhookModels/WebhookMessageBody.cs @@ -1,3 +1,4 @@ +using BotSharp.Plugin.MetaMessenger.MessagingModels; using System; using System.Collections.Generic; using System.Text; @@ -10,4 +11,6 @@ public class WebhookMessageBody [JsonPropertyName("mid")] public string Id { get;set; } public string Text { get;set; } + [JsonPropertyName("quick_reply")] + public QuickReplyMessageItem QuickReply { get;set; } } diff --git a/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs b/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs index 5823e813..ac0dab42 100644 --- a/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs +++ b/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs @@ -59,7 +59,10 @@ namespace BotSharp.Plugin.WeChat var result = await conversationService.SendMessage(AgentId, latestConversationId, new RoleDialogModel("user", message), async msg => { await ReplyTextMessageAsync(openid, msg.Content); - }, async fn => + }, async functionExecuting => + { + + }, async functionExecuted => { });