Skip to content

Commit 2f2ef32

Browse files
authored
Merge pull request #203 from hchen2020/master
Add Twilio plugin.
2 parents cbd76c4 + bc8fa59 commit 2f2ef32

File tree

9 files changed

+227
-6
lines changed

9 files changed

+227
-6
lines changed

BotSharp.sln

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.MongoStorag
6363
EndProject
6464
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.GoogleAI", "src\Plugins\BotSharp.Plugin.GoogleAI\BotSharp.Plugin.GoogleAI.csproj", "{8BC29F8A-78D6-422C-B522-10687ADC38ED}"
6565
EndProject
66+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.Twilio", "src\Plugins\BotSharp.Plugin.Twilio\BotSharp.Plugin.Twilio.csproj", "{E627F1E3-BE03-443A-83A2-86A855A278EB}"
67+
EndProject
6668
Global
6769
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6870
Debug|Any CPU = Debug|Any CPU
@@ -223,6 +225,14 @@ Global
223225
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|Any CPU.Build.0 = Release|Any CPU
224226
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.ActiveCfg = Release|Any CPU
225227
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.Build.0 = Release|Any CPU
228+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
229+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
230+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.ActiveCfg = Debug|Any CPU
231+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Debug|x64.Build.0 = Debug|Any CPU
232+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
233+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|Any CPU.Build.0 = Release|Any CPU
234+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.ActiveCfg = Release|Any CPU
235+
{E627F1E3-BE03-443A-83A2-86A855A278EB}.Release|x64.Build.0 = Release|Any CPU
226236
EndGlobalSection
227237
GlobalSection(SolutionProperties) = preSolution
228238
HideSolutionNode = FALSE
@@ -254,6 +264,7 @@ Global
254264
{5CD330E1-9E5A-4112-8346-6E31CA98EF78} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
255265
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C} = {5CD330E1-9E5A-4112-8346-6E31CA98EF78}
256266
{8BC29F8A-78D6-422C-B522-10687ADC38ED} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
267+
{E627F1E3-BE03-443A-83A2-86A855A278EB} = {64264688-0F5C-4AB0-8F2B-B59B717CCE00}
257268
EndGlobalSection
258269
GlobalSection(ExtensibilityGlobals) = postSolution
259270
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}

README.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,39 @@ It's written in C# running on .Net Core that is full cross-platform framework, t
3939
```
4040
2. Run UI project, reference to [Chatbot UI](src/Plugins/BotSharp.Plugin.ChatbotUI/Chatbot-UI.md).
4141

42-
### Extension Libraries
42+
### Plugins
4343

44-
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.
44+
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:
4545

46-
* Chatbot UI connector.
47-
* A channel module of BotSharp for Facebook Messenger.
48-
* A channel module of BotSharp for Tencent Wechat.
49-
* A channel module of BotSharp for Telegram.
46+
#### Data Storages
47+
- BotSharp.Plugin.MongoStorage
48+
49+
#### LLMs
50+
- BotSharp.Plugin.AzureOpenAI
51+
- BotSharp.Plugin.GoogleAI
52+
- BotSharp.Plugin.MetaAI
53+
- BotSharp.Plugin.HuggingFace
54+
- BotSharp.Plugin.LLamaSharp
55+
56+
#### Messaging / Channel
57+
- BotSharp.OpenAPI
58+
- BotSharp.Plugin.MetaMessenger
59+
- BotSharp.Plugin.Twilio
60+
- BotSharp.Plugin.WeChat
61+
62+
#### RAGS
63+
- BotSharp.Plugin.KnowledgeBase
64+
- BotSharp.Plugin.Qdrant
65+
66+
#### Visions
67+
- BotSharp.Plugin.PaddleSharp
68+
69+
#### Tools
70+
- BotSharp.Plugin.RoutingSpeeder
71+
- BotSharp.Plugin.PizzaBot
72+
73+
#### UIs
74+
- BotSharp.Plugin.ChatbotUI
5075

5176
### Documents
5277

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<LangVersion>$(LangVersion)</LangVersion>
6+
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
7+
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Twilio.AspNet.Common" Version="8.0.2" />
12+
<PackageReference Include="Twilio.AspNet.Core" Version="8.0.2" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using BotSharp.Abstraction.Conversations;
2+
using BotSharp.Plugin.Twilio.Settings;
3+
using Microsoft.AspNetCore.Authorization;
4+
using Microsoft.AspNetCore.Mvc;
5+
using System.Collections.Generic;
6+
using System;
7+
using Twilio.AspNet.Common;
8+
using Twilio.AspNet.Core;
9+
using Twilio.TwiML;
10+
using Twilio.TwiML.Voice;
11+
using System.Threading.Tasks;
12+
using Microsoft.Extensions.DependencyInjection;
13+
using BotSharp.Abstraction.Routing.Settings;
14+
using Twilio.Http;
15+
using Twilio.TwiML.Messaging;
16+
using BotSharp.Abstraction.Agents.Enums;
17+
using BotSharp.Abstraction.Conversations.Models;
18+
19+
namespace BotSharp.Plugin.Twilio.Controllers;
20+
21+
[AllowAnonymous]
22+
public class TwilioVoiceController : TwilioController
23+
{
24+
private readonly TwilioSetting _settings;
25+
private readonly IServiceProvider _services;
26+
27+
public TwilioVoiceController(TwilioSetting settings, IServiceProvider services)
28+
{
29+
_settings = settings;
30+
_services = services;
31+
}
32+
33+
[HttpPost("/twilio/voice/welcome")]
34+
public async Task<TwiMLResult> StartConversation(VoiceRequest request)
35+
{
36+
string sessionId = $"TwilioVoice_{request.CallSid}";
37+
var response = ReturnInstructions("Hello, how may I help you?");
38+
return TwiML(response);
39+
}
40+
41+
[HttpPost("/twilio/voice/{agentId}")]
42+
public async Task<TwiMLResult> ReceivedVoiceMessage([FromRoute] string agentId, VoiceRequest input)
43+
{
44+
string sessionId = $"TwilioVoice_{input.CallSid}";
45+
46+
var conv = _services.GetRequiredService<IConversationService>();
47+
conv.SetConversationId(sessionId, new List<string>
48+
{
49+
"channel=phone",
50+
$"calling_phone={input.DialCallSid}"
51+
});
52+
53+
VoiceResponse response = default;
54+
55+
var result = await conv.SendMessage(agentId, new RoleDialogModel(AgentRole.User, input.SpeechResult), async msg =>
56+
{
57+
response = HangUp(msg.Content);
58+
}, async functionExecuting =>
59+
{
60+
}, async functionExecuted =>
61+
{
62+
});
63+
64+
return TwiML(response);
65+
}
66+
67+
private VoiceResponse ReturnInstructions(string message)
68+
{
69+
var routingSetting = _services.GetRequiredService<RoutingSettings>();
70+
71+
var response = new VoiceResponse();
72+
var gather = new Gather()
73+
{
74+
Input = new List<Gather.InputEnum>()
75+
{
76+
Gather.InputEnum.Speech
77+
},
78+
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.RouterId}")
79+
};
80+
gather.Say(message);
81+
response.Append(gather);
82+
return response;
83+
}
84+
85+
private VoiceResponse HangUp(string message)
86+
{
87+
var response = new VoiceResponse();
88+
if (!string.IsNullOrEmpty(message))
89+
{
90+
response.Say(message);
91+
}
92+
response.Hangup();
93+
return response;
94+
}
95+
96+
private VoiceResponse HoldOn(int interval, string message = null)
97+
{
98+
var routingSetting = _services.GetRequiredService<RoutingSettings>();
99+
100+
var response = new VoiceResponse();
101+
var gather = new Gather()
102+
{
103+
Input = new List<Gather.InputEnum>() { Gather.InputEnum.Speech },
104+
Action = new Uri($"{_settings.CallbackHost}/twilio/voice/{routingSetting.RouterId}"),
105+
ActionOnEmptyResult = true
106+
};
107+
if (!string.IsNullOrEmpty(message))
108+
{
109+
gather.Say(message);
110+
}
111+
gather.Pause(interval);
112+
response.Append(gather);
113+
return response;
114+
}
115+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace BotSharp.Plugin.Twilio.Settings;
2+
3+
public class TwilioSetting
4+
{
5+
public string PhoneNumber { get; set; }
6+
public string AccountSID { get; set; }
7+
public string AuthToken { get; set; }
8+
public string CallbackHost { get; set; }
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using BotSharp.Abstraction.Plugins;
2+
using BotSharp.Plugin.Twilio.Settings;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace BotSharp.Plugin.Twilio;
7+
8+
public class TwilioPlugin : IBotSharpPlugin
9+
{
10+
public void RegisterDI(IServiceCollection services, IConfiguration config)
11+
{
12+
var setting = new TwilioSetting();
13+
config.Bind("Twilio", setting);
14+
services.AddSingleton(setting);
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
global using System;
2+
global using System.Collections.Generic;
3+
global using System.Text;
4+
global using System.Threading.Tasks;
5+
global using System.Linq;
6+
global using System.Text.Json;
7+
global using Microsoft.Extensions.DependencyInjection;
8+
global using Microsoft.Extensions.Configuration;
9+
global using Microsoft.Extensions.Logging;
10+
global using BotSharp.Abstraction.Functions;
11+
global using BotSharp.Abstraction.Functions.Models;
12+
global using BotSharp.Abstraction.Agents.Enums;
13+
global using BotSharp.Abstraction.Models;
14+
global using BotSharp.Abstraction.Agents;
15+
global using BotSharp.Abstraction.Conversations;
16+
global using BotSharp.Abstraction.Plugins;
17+
global using BotSharp.Abstraction.Conversations.Models;

src/WebStarter/WebStarter.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
<ItemGroup>
6565
<ProjectReference Include="..\..\tests\BotSharp.Plugin.PizzaBot\BotSharp.Plugin.PizzaBot.csproj" />
66+
<ProjectReference Include="..\Plugins\BotSharp.Plugin.Twilio\BotSharp.Plugin.Twilio.csproj" />
6667
</ItemGroup>
6768

6869
</Project>

src/WebStarter/appsettings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@
8989
"PageAccessToken": ""
9090
},
9191

92+
"Twilio": {
93+
"PhoneNumber": "+1",
94+
"AccountSID": "",
95+
"AuthToken": "",
96+
"CallbackHost": "https://"
97+
},
98+
9299
"Database": {
93100
"Default": "FileRepository",
94101
"TablePrefix": "BotSharp",
@@ -132,6 +139,7 @@
132139
"BotSharp.Plugin.AzureOpenAI",
133140
"BotSharp.Plugin.GoogleAI",
134141
"BotSharp.Plugin.MetaAI",
142+
// "BotSharp.Plugin.Twilio",
135143
"BotSharp.Plugin.HuggingFace",
136144
"BotSharp.Plugin.LLamaSharp",
137145
"BotSharp.Plugin.KnowledgeBase",

0 commit comments

Comments
 (0)