diff --git a/BotSharp.sln b/BotSharp.sln index d0a61d4d2..29e7cb8e2 100644 --- a/BotSharp.sln +++ b/BotSharp.sln @@ -63,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.MongoStorag EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.GoogleAI", "src\Plugins\BotSharp.Plugin.GoogleAI\BotSharp.Plugin.GoogleAI.csproj", "{8BC29F8A-78D6-422C-B522-10687ADC38ED}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.Twilio", "src\Plugins\BotSharp.Plugin.Twilio\BotSharp.Plugin.Twilio.csproj", "{E627F1E3-BE03-443A-83A2-86A855A278EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -223,6 +225,14 @@ Global {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|Any CPU.Build.0 = Release|Any CPU {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.ActiveCfg = Release|Any CPU {8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.Build.0 = Release|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.ActiveCfg = Debug|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.Build.0 = Debug|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.Build.0 = Release|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.ActiveCfg = Release|Any CPU + {E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -254,6 +264,7 @@ Global {5CD330E1-9E5A-4112-8346-6E31CA98EF78} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C} {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C} = {5CD330E1-9E5A-4112-8346-6E31CA98EF78} {8BC29F8A-78D6-422C-B522-10687ADC38ED} = {D5293208-2BEF-42FC-A64C-5954F61720BA} + {E627F1E3-BE03-443A-83A2-86A855A278EB} = {64264688-0F5C-4AB0-8F2B-B59B717CCE00} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19} diff --git a/README.md b/README.md index 7c0006212..af398158f 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,39 @@ It's written in C# running on .Net Core that is full cross-platform framework, t ``` 2. Run UI project, reference to [Chatbot UI](src/Plugins/BotSharp.Plugin.ChatbotUI/Chatbot-UI.md). -### Extension Libraries +### Plugins -BotSharp uses component design, the kernel is kept to a minimum, and business functions are implemented by external components. The modular design also allows contributors to better participate. +BotSharp uses component design, the kernel is kept to a minimum, and business functions are implemented by external components. The modular design also allows contributors to better participate. Below are the bulit-in plugins: -* Chatbot UI connector. -* A channel module of BotSharp for Facebook Messenger. -* A channel module of BotSharp for Tencent Wechat. -* A channel module of BotSharp for Telegram. +#### Data Storages +- BotSharp.Plugin.MongoStorage + +#### LLMs +- BotSharp.Plugin.AzureOpenAI +- BotSharp.Plugin.GoogleAI +- BotSharp.Plugin.MetaAI +- BotSharp.Plugin.HuggingFace +- BotSharp.Plugin.LLamaSharp + +#### Messaging / Channel +- BotSharp.OpenAPI +- BotSharp.Plugin.MetaMessenger +- BotSharp.Plugin.Twilio +- BotSharp.Plugin.WeChat + +#### RAGS +- BotSharp.Plugin.KnowledgeBase +- BotSharp.Plugin.Qdrant + +#### Visions +- BotSharp.Plugin.PaddleSharp + +#### Tools +- BotSharp.Plugin.RoutingSpeeder +- BotSharp.Plugin.PizzaBot + +#### UIs +- BotSharp.Plugin.ChatbotUI ### Documents diff --git a/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj b/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj new file mode 100644 index 000000000..99c35ca75 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Twilio/BotSharp.Plugin.Twilio.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + $(LangVersion) + $(BotSharpVersion) + $(GeneratePackageOnBuild) + + + + + + + + + + + + diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs new file mode 100644 index 000000000..7913c0567 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs @@ -0,0 +1,115 @@ +using BotSharp.Abstraction.Conversations; +using BotSharp.Plugin.Twilio.Settings; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System; +using Twilio.AspNet.Common; +using Twilio.AspNet.Core; +using Twilio.TwiML; +using Twilio.TwiML.Voice; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using BotSharp.Abstraction.Routing.Settings; +using Twilio.Http; +using Twilio.TwiML.Messaging; +using BotSharp.Abstraction.Agents.Enums; +using BotSharp.Abstraction.Conversations.Models; + +namespace BotSharp.Plugin.Twilio.Controllers; + +[AllowAnonymous] +public class TwilioVoiceController : TwilioController +{ + private readonly TwilioSetting _settings; + private readonly IServiceProvider _services; + + public TwilioVoiceController(TwilioSetting settings, IServiceProvider services) + { + _settings = settings; + _services = services; + } + + [HttpPost("/twilio/voice/welcome")] + public async Task StartConversation(VoiceRequest request) + { + string sessionId = $"TwilioVoice_{request.CallSid}"; + var response = ReturnInstructions("Hello, how may I help you?"); + return TwiML(response); + } + + [HttpPost("/twilio/voice/{agentId}")] + public async Task ReceivedVoiceMessage([FromRoute] string agentId, VoiceRequest input) + { + string sessionId = $"TwilioVoice_{input.CallSid}"; + + var conv = _services.GetRequiredService(); + conv.SetConversationId(sessionId, new List + { + "channel=phone", + $"calling_phone={input.DialCallSid}" + }); + + VoiceResponse response = default; + + var result = await conv.SendMessage(agentId, new RoleDialogModel(AgentRole.User, input.SpeechResult), async msg => + { + response = HangUp(msg.Content); + }, async functionExecuting => + { + }, async functionExecuted => + { + }); + + return TwiML(response); + } + + private VoiceResponse ReturnInstructions(string message) + { + var routingSetting = _services.GetRequiredService(); + + var response = new VoiceResponse(); + var gather = new Gather() + { + Input = new List() + { + Gather.InputEnum.Speech + }, + Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.RouterId}") + }; + gather.Say(message); + response.Append(gather); + return response; + } + + private VoiceResponse HangUp(string message) + { + var response = new VoiceResponse(); + if (!string.IsNullOrEmpty(message)) + { + response.Say(message); + } + response.Hangup(); + return response; + } + + private VoiceResponse HoldOn(int interval, string message = null) + { + var routingSetting = _services.GetRequiredService(); + + var response = new VoiceResponse(); + var gather = new Gather() + { + Input = new List() { Gather.InputEnum.Speech }, + Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.RouterId}"), + ActionOnEmptyResult = true + }; + if (!string.IsNullOrEmpty(message)) + { + gather.Say(message); + } + gather.Pause(interval); + response.Append(gather); + return response; + } +} diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs new file mode 100644 index 000000000..a1048b8cd --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Twilio/Settings/TwilioSetting.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Plugin.Twilio.Settings; + +public class TwilioSetting +{ + public string PhoneNumber { get; set; } + public string AccountSID { get; set; } + public string AuthToken { get; set; } + public string CallbackHost { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs new file mode 100644 index 000000000..ff8884b22 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs @@ -0,0 +1,16 @@ +using BotSharp.Abstraction.Plugins; +using BotSharp.Plugin.Twilio.Settings; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace BotSharp.Plugin.Twilio; + +public class TwilioPlugin : IBotSharpPlugin +{ + public void RegisterDI(IServiceCollection services, IConfiguration config) + { + var setting = new TwilioSetting(); + config.Bind("Twilio", setting); + services.AddSingleton(setting); + } +} diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Using.cs b/src/Plugins/BotSharp.Plugin.Twilio/Using.cs new file mode 100644 index 000000000..5026d4913 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.Twilio/Using.cs @@ -0,0 +1,17 @@ +global using System; +global using System.Collections.Generic; +global using System.Text; +global using System.Threading.Tasks; +global using System.Linq; +global using System.Text.Json; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.Logging; +global using BotSharp.Abstraction.Functions; +global using BotSharp.Abstraction.Functions.Models; +global using BotSharp.Abstraction.Agents.Enums; +global using BotSharp.Abstraction.Models; +global using BotSharp.Abstraction.Agents; +global using BotSharp.Abstraction.Conversations; +global using BotSharp.Abstraction.Plugins; +global using BotSharp.Abstraction.Conversations.Models; \ No newline at end of file diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index 3cb6b16bc..8c14beff8 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -63,6 +63,7 @@ + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index ed51f673b..157755eaa 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -89,6 +89,13 @@ "PageAccessToken": "" }, + "Twilio": { + "PhoneNumber": "+1", + "AccountSID": "", + "AuthToken": "", + "CallbackHost": "https://" + }, + "Database": { "Default": "FileRepository", "TablePrefix": "BotSharp", @@ -132,6 +139,7 @@ "BotSharp.Plugin.AzureOpenAI", "BotSharp.Plugin.GoogleAI", "BotSharp.Plugin.MetaAI", + // "BotSharp.Plugin.Twilio", "BotSharp.Plugin.HuggingFace", "BotSharp.Plugin.LLamaSharp", "BotSharp.Plugin.KnowledgeBase",