Hang up phone with audio
This commit is contained in:
parent
1c9f76947a
commit
72abb965de
|
|
@ -164,7 +164,7 @@ public class TwilioVoiceController : TwilioController
|
|||
OnlyOnce = true
|
||||
});
|
||||
|
||||
response = twilio.HangUp(null);
|
||||
response = twilio.HangUp(string.Empty);
|
||||
}
|
||||
// keep waiting for user response
|
||||
else
|
||||
|
|
@ -433,8 +433,18 @@ public class TwilioVoiceController : TwilioController
|
|||
[HttpPost("twilio/voice/hang-up")]
|
||||
public async Task<TwiMLResult> Hangup(ConversationalVoiceRequest request)
|
||||
{
|
||||
var instruction = new ConversationalVoiceResponse
|
||||
{
|
||||
ConversationId = request.ConversationId
|
||||
};
|
||||
|
||||
if (request.InitAudioFile != null)
|
||||
{
|
||||
instruction.SpeechPaths.Add(request.InitAudioFile);
|
||||
}
|
||||
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
var response = twilio.HangUp("twilio/bye.mp3");
|
||||
var response = twilio.HangUp(instruction);
|
||||
return TwiML(response);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using BotSharp.Abstraction.Files;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Core.Infrastructures;
|
||||
using BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.LlmContexts;
|
||||
using Twilio.Rest.Api.V2010.Account;
|
||||
|
||||
|
|
@ -27,6 +29,7 @@ public class HangupPhoneCallFn : IFunctionCallback
|
|||
{
|
||||
var args = JsonSerializer.Deserialize<HangupPhoneCallArgs>(message.FunctionArgs);
|
||||
|
||||
var fileStorage = _services.GetRequiredService<IFileStorageService>();
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
var conversationId = routing.Context.ConversationId;
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
|
|
@ -39,21 +42,28 @@ public class HangupPhoneCallFn : IFunctionCallback
|
|||
return false;
|
||||
}
|
||||
|
||||
if (args.AnythingElseToHelp)
|
||||
{
|
||||
message.Content = "Tell me how I can help.";
|
||||
}
|
||||
else
|
||||
{
|
||||
var call = CallResource.Update(
|
||||
url: new Uri($"{_twilioSetting.CallbackHost}/twilio/voice/hang-up?conversation-id={conversationId}"),
|
||||
pathSid: callSid
|
||||
);
|
||||
var processUrl = $"{_twilioSetting.CallbackHost}/twilio/voice/hang-up?conversation-id={conversationId}";
|
||||
|
||||
message.Content = "The call is ending.";
|
||||
message.StopCompletion = true;
|
||||
// Generate initial assistant audio
|
||||
string initAudioFile = null;
|
||||
if (!string.IsNullOrEmpty(args.ResponseContent))
|
||||
{
|
||||
var completion = CompletionProvider.GetAudioCompletion(_services, "openai", "tts-1");
|
||||
var data = await completion.GenerateAudioFromTextAsync(args.ResponseContent);
|
||||
initAudioFile = "ending.mp3";
|
||||
fileStorage.SaveSpeechFile(conversationId, initAudioFile, data);
|
||||
|
||||
processUrl += $"&init-audio-file={initAudioFile}";
|
||||
}
|
||||
|
||||
var call = CallResource.Update(
|
||||
url: new Uri(processUrl),
|
||||
pathSid: callSid
|
||||
);
|
||||
|
||||
message.Content = args.Reason;
|
||||
message.StopCompletion = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,44 +35,35 @@ public class TransferPhoneCallFn : IFunctionCallback
|
|||
|
||||
var fileStorage = _services.GetRequiredService<IFileStorageService>();
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
var conversationId = routing.Context.ConversationId;
|
||||
var processUrl = $"{_twilioSetting.CallbackHost}/twilio/voice/transfer-call?conversation-id={conversationId}&transfer-to={args.PhoneNumber}";
|
||||
|
||||
// Generate initial assistant audio
|
||||
string initAudioFile = null;
|
||||
if (!string.IsNullOrEmpty(args.TransitionMessage))
|
||||
{
|
||||
var completion = CompletionProvider.GetAudioCompletion(_services, "openai", "tts-1");
|
||||
var data = await completion.GenerateAudioFromTextAsync(args.TransitionMessage);
|
||||
initAudioFile = "transfer.mp3";
|
||||
fileStorage.SaveSpeechFile(conversationId, initAudioFile, data);
|
||||
|
||||
processUrl += $"&init-audio-file={initAudioFile}";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(initAudioFile))
|
||||
{
|
||||
processUrl += $"&init-audio-file={initAudioFile}";
|
||||
}
|
||||
|
||||
// Forward call
|
||||
var sid = states.GetState("twilio_call_sid");
|
||||
|
||||
if (string.IsNullOrEmpty(sid))
|
||||
{
|
||||
_logger.LogError("Twilio call sid is empty.");
|
||||
message.Content = "There is an error when transferring the phone call.";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var call = CallResource.Update(
|
||||
pathSid: sid,
|
||||
url: new Uri(processUrl));
|
||||
|
||||
message.Content = args.TransitionMessage;
|
||||
return true;
|
||||
var routing = _services.GetRequiredService<IRoutingService>();
|
||||
var conversationId = routing.Context.ConversationId;
|
||||
var processUrl = $"{_twilioSetting.CallbackHost}/twilio/voice/transfer-call?conversation-id={conversationId}&transfer-to={args.PhoneNumber}";
|
||||
|
||||
// Generate initial assistant audio
|
||||
if (!string.IsNullOrEmpty(args.TransitionMessage))
|
||||
{
|
||||
var completion = CompletionProvider.GetAudioCompletion(_services, "openai", "tts-1");
|
||||
var data = await completion.GenerateAudioFromTextAsync(args.TransitionMessage);
|
||||
var initAudioFile = "transfer.mp3";
|
||||
fileStorage.SaveSpeechFile(conversationId, initAudioFile, data);
|
||||
|
||||
processUrl += $"&init-audio-file={initAudioFile}";
|
||||
}
|
||||
|
||||
// Transfer call
|
||||
var call = CallResource.Update(
|
||||
pathSid: sid,
|
||||
url: new Uri(processUrl));
|
||||
|
||||
message.Content = args.TransitionMessage;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ namespace BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.LlmContexts;
|
|||
|
||||
public class HangupPhoneCallArgs
|
||||
{
|
||||
[JsonPropertyName("anything_else_to_help")]
|
||||
public bool AnythingElseToHelp { get; set; } = true;
|
||||
[JsonPropertyName("reason")]
|
||||
public string Reason { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("response_content")]
|
||||
public string ResponseContent { get; set; } = null!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,22 @@ public class TwilioService
|
|||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse HangUp(ConversationalVoiceResponse voiceResponse)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
var conversationId = voiceResponse.ConversationId;
|
||||
if (voiceResponse.SpeechPaths != null && voiceResponse.SpeechPaths.Any())
|
||||
{
|
||||
foreach (var speechPath in voiceResponse.SpeechPaths)
|
||||
{
|
||||
var uri = GetSpeechPath(conversationId, speechPath);
|
||||
response.Play(new Uri(uri));
|
||||
}
|
||||
}
|
||||
response.Hangup();
|
||||
return response;
|
||||
}
|
||||
|
||||
public VoiceResponse DialCsrAgent(string speechPath)
|
||||
{
|
||||
var response = new VoiceResponse();
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
"type": "string",
|
||||
"description": "The reason why user wants to end the phone call."
|
||||
},
|
||||
"anything_else_to_help": {
|
||||
"type": "boolean",
|
||||
"description": "Check if user has anything else to help."
|
||||
"response_content": {
|
||||
"type": "string",
|
||||
"description": "A statement said to the user when politely ending a conversation."
|
||||
}
|
||||
},
|
||||
"required": [ "reason", "anything_else_to_help" ]
|
||||
"required": [ "reason", "response_content" ]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue