Fix conversation states before loading agent for init-outbound-call
This commit is contained in:
parent
69f0138593
commit
aba857c925
|
|
@ -52,28 +52,22 @@ public class TwilioInboundController : TwilioController
|
|||
instruction.SpeechPaths.Add(request.InitAudioFile);
|
||||
}
|
||||
|
||||
// Load agent profile
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var agent = await agentService.LoadAgent(request.AgentId);
|
||||
|
||||
await HookEmitter.Emit<ITwilioSessionHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnSessionCreating(request, instruction);
|
||||
});
|
||||
|
||||
request.ConversationId = await InitConversation(request, agent);
|
||||
var (agent, conversationId) = await InitConversation(request);
|
||||
request.ConversationId = conversationId.Id;
|
||||
instruction.AgentId = request.AgentId;
|
||||
instruction.ConversationId = request.ConversationId;
|
||||
|
||||
if (request.AnsweredBy == "machine_start" &&
|
||||
request.Direction == "outbound-api")
|
||||
if (twilio.MachineDetected(request))
|
||||
{
|
||||
response = new VoiceResponse();
|
||||
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnVoicemailStarting(request);
|
||||
});
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async hook => await hook.OnVoicemailStarting(request));
|
||||
|
||||
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
|
||||
response.Play(new Uri(url));
|
||||
|
|
@ -141,7 +135,7 @@ public class TwilioInboundController : TwilioController
|
|||
return result;
|
||||
}
|
||||
|
||||
private async Task<string> InitConversation(ConversationalVoiceRequest request, Agent agent)
|
||||
private async Task<(Agent, Conversation)> InitConversation(ConversationalVoiceRequest request)
|
||||
{
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var conversation = await convService.GetConversation(request.ConversationId);
|
||||
|
|
@ -167,20 +161,25 @@ public class TwilioInboundController : TwilioController
|
|||
new("twilio_call_sid", request.CallSid),
|
||||
};
|
||||
|
||||
// Enable lazy routing mode to optimize realtime experience
|
||||
if (agent.Profiles.Contains("realtime") && agent.Type == AgentType.Routing)
|
||||
{
|
||||
states.Add(new(StateConst.ROUTING_MODE, "lazy"));
|
||||
}
|
||||
|
||||
if (request.InitAudioFile != null)
|
||||
{
|
||||
states.Add(new("init_audio_file", request.InitAudioFile));
|
||||
}
|
||||
|
||||
convService.SetConversationId(conversation.Id, states);
|
||||
|
||||
// Load agent profile
|
||||
var agentService = _services.GetRequiredService<IAgentService>();
|
||||
var agent = await agentService.LoadAgent(request.AgentId);
|
||||
|
||||
// Enable lazy routing mode to optimize realtime experience
|
||||
if (agent.Profiles.Contains("realtime") && agent.Type == AgentType.Routing)
|
||||
{
|
||||
states.Add(new(StateConst.ROUTING_MODE, "lazy"));
|
||||
}
|
||||
|
||||
convService.SaveStates();
|
||||
|
||||
return conversation.Id;
|
||||
return (agent, conversation);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,15 +29,12 @@ public class TwilioOutboundController : TwilioController
|
|||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
|
||||
VoiceResponse response = default!;
|
||||
if (request.AnsweredBy == "machine_start" &&
|
||||
request.Direction == "outbound-api")
|
||||
if (twilio.MachineDetected(request))
|
||||
{
|
||||
response = new VoiceResponse();
|
||||
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnVoicemailStarting(request);
|
||||
});
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async hook => await hook.OnVoicemailStarting(request));
|
||||
|
||||
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
|
||||
response.Play(new Uri(url));
|
||||
|
|
|
|||
|
|
@ -332,38 +332,41 @@ public class TwilioVoiceController : TwilioController
|
|||
[HttpPost("twilio/voice/status")]
|
||||
public async Task<ActionResult> PhoneCallStatus(ConversationalVoiceRequest request)
|
||||
{
|
||||
var twilio = _services.GetRequiredService<TwilioService>();
|
||||
if (request.CallStatus == "completed")
|
||||
{
|
||||
if (request.AnsweredBy == "machine_start" &&
|
||||
request.Direction == "outbound-api")
|
||||
if (twilio.MachineDetected(request))
|
||||
{
|
||||
// voicemail
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, async hook =>
|
||||
{
|
||||
await hook.OnVoicemailLeft(request);
|
||||
});
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async hook => await hook.OnVoicemailLeft(request));
|
||||
}
|
||||
else
|
||||
{
|
||||
// phone call completed
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnUserDisconnected(request));
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async x => await x.OnUserDisconnected(request));
|
||||
}
|
||||
}
|
||||
else if (request.CallStatus == "busy")
|
||||
{
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnCallBusyStatus(request));
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async x => await x.OnCallBusyStatus(request));
|
||||
}
|
||||
else if (request.CallStatus == "no-answer")
|
||||
{
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnCallNoAnswerStatus(request));
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async x => await x.OnCallNoAnswerStatus(request));
|
||||
}
|
||||
else if (request.CallStatus == "canceled")
|
||||
{
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnCallCanceledStatus(request));
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async x => await x.OnCallCanceledStatus(request));
|
||||
}
|
||||
else if (request.CallStatus == "failed")
|
||||
{
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, x => x.OnCallFailedStatus(request));
|
||||
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
|
||||
async x => await x.OnCallFailedStatus(request));
|
||||
}
|
||||
|
||||
return Ok();
|
||||
|
|
|
|||
|
|
@ -309,6 +309,19 @@ public class TwilioService
|
|||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.twilio.com/docs/voice/answering-machine-detection
|
||||
/// </summary>
|
||||
/// <param name="answeredBy"></param>
|
||||
/// <returns></returns>
|
||||
public bool MachineDetected(ConversationalVoiceRequest request)
|
||||
{
|
||||
var answeredBy = request.AnsweredBy ?? "unknown";
|
||||
var isOutboundCall = request.Direction == "outbound-api";
|
||||
var isMachine = answeredBy.StartsWith("machine_") || answeredBy == "fax";
|
||||
return isOutboundCall && isMachine;
|
||||
}
|
||||
|
||||
public string GetSpeechPath(string conversationId, string speechPath)
|
||||
{
|
||||
if (speechPath.StartsWith("twilio/"))
|
||||
|
|
|
|||
Loading…
Reference in a new issue