improve the workflow

This commit is contained in:
Bo Yin 2024-08-29 14:36:07 -05:00
parent 84ae25878c
commit e6f03fcdf4
4 changed files with 59 additions and 7 deletions

View file

@ -36,13 +36,13 @@ public class TwilioVoiceController : TwilioController
string conversationId = $"TwilioVoice_{request.CallSid}";
var twilio = _services.GetRequiredService<TwilioService>();
var url = $"twilio/voice/{conversationId}/receive/0?states={states}";
var response = twilio.ReturnInstructions(new List<string> { "twilio/welcome.mp3" }, url, true);
var response = twilio.ReturnNoninterruptedInstructions(new List<string> { "twilio/welcome.mp3" }, url, true);
return TwiML(response);
}
[ValidateRequest]
[HttpPost("twilio/voice/{conversationId}/receive/{seqNum}")]
public async Task<TwiMLResult> ReceiveCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum, [FromQuery] string states, VoiceRequest request)
public async Task<TwiMLResult> ReceiveCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum, [FromQuery] string states, [FromQuery] int attempts, VoiceRequest request)
{
var twilio = _services.GetRequiredService<TwilioService>();
var messageQueue = _services.GetRequiredService<TwilioMessageQueue>();
@ -81,7 +81,21 @@ public class TwilioVoiceController : TwilioController
}
else
{
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
if (attempts >= 3)
{
var speechPaths = new List<string>();
if (seqNum == 0)
{
speechPaths.Add("twilio/welcome.mp3");
}
else
{
var lastRepy = await sessionManager.GetAssistantReplyAsync(conversationId, seqNum - 1);
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{lastRepy.SpeechFileName}");
}
response = twilio.ReturnInstructions(speechPaths, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}", true);
}
response = twilio.ReturnInstructions(null, $"twilio/voice/{conversationId}/receive/{seqNum}?states={states}&attempts={++attempts}", true);
}
return TwiML(response);
@ -90,7 +104,7 @@ public class TwilioVoiceController : TwilioController
[ValidateRequest]
[HttpPost("twilio/voice/{conversationId}/reply/{seqNum}")]
public async Task<TwiMLResult> ReplyCallerMessage([FromRoute] string conversationId, [FromRoute] int seqNum,
[FromQuery] string states, [FromQuery] string play, VoiceRequest request)
[FromQuery] string states, VoiceRequest request)
{
var nextSeqNum = seqNum + 1;
var sessionManager = _services.GetRequiredService<ITwilioSessionManager>();
@ -107,6 +121,7 @@ public class TwilioVoiceController : TwilioController
if (indication != null)
{
var speechPaths = new List<string>();
int segIndex = 0;
foreach (var text in indication.Split('|'))
{
var seg = text.Trim();
@ -119,12 +134,14 @@ public class TwilioVoiceController : TwilioController
var textToSpeechService = CompletionProvider.GetTextToSpeech(_services, "openai", "tts-1");
var fileService = _services.GetRequiredService<IFileStorageService>();
var data = await textToSpeechService.GenerateSpeechFromTextAsync(seg);
var fileName = $"indication_{seqNum}.mp3";
var fileName = $"indication_{seqNum}_{segIndex}.mp3";
await fileService.SaveSpeechFileAsync(conversationId, fileName, data);
speechPaths.Add($"twilio/voice/speeches/{conversationId}/{fileName}");
segIndex++;
}
}
response = twilio.ReturnInstructions(speechPaths, $"twilio/voice/{conversationId}/reply/{seqNum}?states={states}", true);
await sessionManager.RemoveReplyIndicationAsync(conversationId, seqNum);
}
else
{

View file

@ -11,5 +11,6 @@ namespace BotSharp.Plugin.Twilio.Services
Task<List<string>> RetrieveStagedCallerMessagesAsync(string conversationId, int seqNum);
Task SetReplyIndicationAsync(string conversationId, int seqNum, string indication);
Task<string> GetReplyIndicationAsync(string conversationId, int seqNum);
Task RemoveReplyIndicationAsync(string conversationId, int seqNum);
}
}

View file

@ -76,8 +76,8 @@ public class TwilioService
},
Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"),
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
SpeechTimeout = timeout > 0 ? timeout.ToString() : "3",
Timeout = timeout > 0 ? timeout : 3,
SpeechTimeout = timeout > 0 ? timeout.ToString() : "2",
Timeout = timeout > 0 ? timeout : 2,
ActionOnEmptyResult = actionOnEmptyResult
};
if (speechPaths != null && speechPaths.Any())
@ -91,6 +91,33 @@ public class TwilioService
return response;
}
public VoiceResponse ReturnNoninterruptedInstructions(List<string> speechPaths, string callbackPath, bool actionOnEmptyResult, int timeout = 2)
{
var response = new VoiceResponse();
if (speechPaths != null && speechPaths.Any())
{
foreach (var speechPath in speechPaths)
{
response.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
}
}
var gather = new Gather()
{
Input = new List<Gather.InputEnum>()
{
Gather.InputEnum.Speech,
Gather.InputEnum.Dtmf
},
Action = new Uri($"{_settings.CallbackHost}/{callbackPath}"),
SpeechModel = Gather.SpeechModelEnum.PhoneCall,
SpeechTimeout = timeout > 0 ? timeout.ToString() : "2",
Timeout = timeout > 0 ? timeout : 2,
ActionOnEmptyResult = actionOnEmptyResult
};
response.Append(gather);
return response;
}
public VoiceResponse HangUp(string speechPath)
{
var response = new VoiceResponse();

View file

@ -59,5 +59,12 @@ namespace BotSharp.Plugin.Twilio.Services
var key = $"{conversationId}:Indication:{seqNum}";
return await db.StringGetAsync(key);
}
public async Task RemoveReplyIndicationAsync(string conversationId, int seqNum)
{
var db = _redis.GetDatabase();
var key = $"{conversationId}:Indication:{seqNum}";
await db.KeyDeleteAsync(key);
}
}
}