diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Speech.cs b/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Speech.cs index b81d37f3..9788631e 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Speech.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Speech.cs @@ -2,7 +2,7 @@ using System.IO; namespace BotSharp.Core.Files.Services { - public partial class BotSharpFileService + public partial class LocalFileStorageService { public async Task SaveSpeechFileAsync(string conversationId, string fileName, BinaryData data) { diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs index 43c4dc51..6e163ce8 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs @@ -86,24 +86,24 @@ public class TwilioVoiceController : TwilioController } - [HttpPost("anonymous/start")] + [HttpPost("start")] public TwiMLResult InitiateConversation(VoiceRequest request) { if (request?.CallSid == null) throw new ArgumentNullException(nameof(VoiceRequest.CallSid)); string sessionId = $"TwilioVoice_{request.CallSid}"; var twilio = _services.GetRequiredService(); - var url = $"twiliovoice/anonymous/{sessionId}/send/0"; - var response = twilio.DummyInstructions("Hello, how may I help you?", url, false); + var url = $"twiliovoice/{sessionId}/send/0"; + var response = twilio.ReturnInstructions("twilio/welcome.mp3", url, false); return TwiML(response); } - [HttpPost("anonymous/{sessionId}/send/{seqNum}")] + [HttpPost("{sessionId}/send/{seqNum}")] public async Task SendCallerMessage([FromRoute] string sessionId, [FromRoute] int seqNum, VoiceRequest request) { var twilio = _services.GetRequiredService(); var messageQueue = _services.GetRequiredService(); var sessionManager = _services.GetRequiredService(); - var url = $"twiliovoice/anonymous/{sessionId}/reply/{seqNum}"; + var url = $"twiliovoice/{sessionId}/reply/{seqNum}"; var messages = await sessionManager.RetrieveStagedCallerMessagesAsync(sessionId, seqNum); if (!string.IsNullOrWhiteSpace(request.SpeechResult)) { @@ -121,16 +121,16 @@ public class TwilioVoiceController : TwilioController From = request.From }; await messageQueue.EnqueueAsync(callerMessage); - response = twilio.DummyInstructions("Please hold on and wait a moment.", url, true); + response = twilio.ReturnInstructions("twilio/holdon.mp3", url, true); } else { - response = twilio.HangUp("Thanks for calling. Good bye."); + response = twilio.HangUp("twilio/holdon.mp3"); } return TwiML(response); } - [HttpPost("anonymous/{sessionId}/reply/{seqNum}")] + [HttpPost("{sessionId}/reply/{seqNum}")] public async Task ReplyCallerMessage([FromRoute] string sessionId, [FromRoute] int seqNum, VoiceRequest request) { var nextSeqNum = seqNum + 1; @@ -144,38 +144,28 @@ public class TwilioVoiceController : TwilioController VoiceResponse response; if (string.IsNullOrEmpty(reply)) { - response = twilio.ReturnInstructions(null, $"twiliovoice/anonymous/{sessionId}/reply/{seqNum}", true); + response = twilio.ReturnInstructions(null, $"twiliovoice/{sessionId}/reply/{seqNum}", true); } else { var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1"); - var fileService = _services.GetRequiredService(); + var fileService = _services.GetRequiredService(); var data = await textToSpeechService.GenerateSpeechFromTextAsync(reply); var fileName = $"{seqNum}.mp3"; await fileService.SaveSpeechFileAsync(sessionId, fileName, data); - response = twilio.ReturnInstructions($"twiliovoice/anonymous/speeches/{sessionId}/{fileName}", $"twiliovoice/anonymous/{sessionId}/send/{nextSeqNum}", true); + response = twilio.ReturnInstructions($"twiliovoice/speeches/{sessionId}/{fileName}", $"twiliovoice/{sessionId}/send/{nextSeqNum}", true); } return TwiML(response); } - [HttpGet("anonymous/speeches/{conversationId}/{fileName}")] + [HttpGet("speeches/{conversationId}/{fileName}")] public async Task RetrieveSpeechFile([FromRoute] string conversationId, [FromRoute] string fileName) { - var fileService = _services.GetRequiredService(); + var fileService = _services.GetRequiredService(); var data = await fileService.RetrieveSpeechFileAsync(conversationId, fileName); - var result = new FileContentResult(data.ToArray(), "application/octet-stream"); + var result = new FileContentResult(data.ToArray(), "audio/mpeg"); result.FileDownloadName = fileName; return result; } - - [HttpGet("anonymous/text-to-speech")] - public async Task TextToSpeech([FromQuery] string text) - { - var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1"); - var data = await textToSpeechService.GenerateSpeechFromTextAsync(text); - var fileService = _services.GetRequiredService(); - await fileService.SaveSpeechFileAsync("123", "sample.mp3", data); - return Ok(); - } } diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs b/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs index be270a41..e0f4463a 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Models/CallerMessage.cs @@ -9,7 +9,7 @@ namespace BotSharp.Plugin.Twilio.Models public override string ToString() { - return $"({SessionId}-{SeqNumber}) {Content}"; + return $"{SessionId}-{SeqNumber}"; } } } diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueue.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueue.cs index 456e43c1..455e314c 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueue.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueue.cs @@ -25,6 +25,7 @@ namespace BotSharp.Plugin.Twilio.Services internal void Stop() { + Console.WriteLine($"[{DateTime.UtcNow}] Complete queue"); _queue.Writer.TryComplete(); } } diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs index 5e01f2a9..dab06c4b 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs @@ -1,7 +1,6 @@ using BotSharp.Abstraction.Routing; using BotSharp.Plugin.Twilio.Models; using Microsoft.Extensions.Hosting; -using System.Security.Cryptography; using System.Threading; using Task = System.Threading.Tasks.Task; @@ -31,12 +30,12 @@ namespace BotSharp.Plugin.Twilio.Services { try { - Console.WriteLine("Processing {message}.", message); + Console.WriteLine($"Start processing {message}."); await ProcessUserMessageAsync(message); } catch (Exception ex) { - Console.WriteLine("Processing {message} failed due to {ex}.", message, ex.Message); + Console.WriteLine($"Processing {message} failed due to {ex.Message}."); } finally { @@ -57,18 +56,17 @@ namespace BotSharp.Plugin.Twilio.Services using var scope = _serviceProvider.CreateScope(); var sp = scope.ServiceProvider; string reply = null; - //await Task.Delay(2000); - //reply = $"response for sequence number {message.SeqNumber}"; var inputMsg = new RoleDialogModel(AgentRole.User, message.Content); var conv = sp.GetRequiredService(); var routing = sp.GetRequiredService(); + var config = sp.GetRequiredService(); routing.Context.SetMessageId(message.SessionId, inputMsg.MessageId); conv.SetConversationId(message.SessionId, new List { new MessageState("channel", ConversationChannel.Phone), new MessageState("calling_phone", message.From) }); - var result = await conv.SendMessage("2cd4b805-7078-4405-87e9-2ec9aadf8a11", + var result = await conv.SendMessage(config.AgentId, inputMsg, replyMessage: null, async msg => @@ -82,7 +80,7 @@ namespace BotSharp.Plugin.Twilio.Services ); if (string.IsNullOrWhiteSpace(reply)) { - reply = "Bye."; + reply = "Sorry, something was wrong."; } var sessionManager = sp.GetRequiredService(); await sessionManager.SetAssistantReplyAsync(message.SessionId, message.SeqNumber, reply); diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs index 2428b90b..09405817 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs @@ -1,4 +1,3 @@ -using BotSharp.Plugin.Twilio.Settings; using Twilio.Jwt.AccessToken; using Token = Twilio.Jwt.AccessToken.Token; @@ -74,6 +73,7 @@ public class TwilioService Gather.InputEnum.Speech }, Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"), + SpeechTimeout = "3", ActionOnEmptyResult = actionOnEmptyResult }; if (!string.IsNullOrEmpty(speechPath)) @@ -84,32 +84,12 @@ public class TwilioService return response; } - public VoiceResponse DummyInstructions(string message, string callbackPath, bool actionOnEmptyResult) + public VoiceResponse HangUp(string speechPath) { var response = new VoiceResponse(); - var gather = new Gather() + if (!string.IsNullOrEmpty(speechPath)) { - Input = new List() - { - Gather.InputEnum.Speech - }, - Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"), - ActionOnEmptyResult = actionOnEmptyResult - }; - if (!string.IsNullOrEmpty(message)) - { - gather.Say(message); - } - response.Append(gather); - return response; - } - - public VoiceResponse HangUp(string message) - { - var response = new VoiceResponse(); - if (!string.IsNullOrEmpty(message)) - { - response.Say(message); + response.Play(new Uri($"{_settings.CallbackHost}/{speechPath}")); } response.Hangup(); return response; diff --git a/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs index 0a93b6a9..38d278a6 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/TwilioPlugin.cs @@ -19,7 +19,7 @@ public class TwilioPlugin : IBotSharpPlugin }); services.AddScoped(); - var conn = ConnectionMultiplexer.Connect("10.2.3.227"); + var conn = ConnectionMultiplexer.Connect(config["Twilio:RedisConnectionString"]); var sessionManager = new TwilioSessionManager(conn); services.AddSingleton(sessionManager); services.AddSingleton();