Mak initial audio is not interruptable
This commit is contained in:
parent
ded711d164
commit
b4862837da
|
|
@ -21,28 +21,22 @@ public class RealtimeHub : IRealtimeHub
|
||||||
public async Task Listen(WebSocket userWebSocket,
|
public async Task Listen(WebSocket userWebSocket,
|
||||||
Func<string, RealtimeHubConnection> onUserMessageReceived)
|
Func<string, RealtimeHubConnection> onUserMessageReceived)
|
||||||
{
|
{
|
||||||
var buffer = new byte[1024 * 4];
|
var buffer = new byte[1024 * 16];
|
||||||
WebSocketReceiveResult result;
|
WebSocketReceiveResult result;
|
||||||
|
|
||||||
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
|
||||||
var model = llmProviderService.GetProviderModel("openai", "gpt-4",
|
|
||||||
realTime: true).Name;
|
|
||||||
|
|
||||||
var completer = _services.GetServices<IRealTimeCompletion>().First(x => x.Provider == "openai");
|
var completer = _services.GetServices<IRealTimeCompletion>().First(x => x.Provider == "openai");
|
||||||
completer.SetModelName(model);
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
result = await userWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
result = await userWebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
string receivedText = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
string receivedText = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||||
_logger.LogDebug($"Received from user: {receivedText}");
|
|
||||||
if (string.IsNullOrEmpty(receivedText))
|
if (string.IsNullOrEmpty(receivedText))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var conn = onUserMessageReceived(receivedText);
|
var conn = onUserMessageReceived(receivedText);
|
||||||
conn.Model = model;
|
|
||||||
|
|
||||||
if (conn.Event == "user_connected")
|
if (conn.Event == "user_connected")
|
||||||
{
|
{
|
||||||
|
|
@ -74,6 +68,17 @@ public class RealtimeHub : IRealtimeHub
|
||||||
var agent = await agentService.LoadAgent(conversation.AgentId);
|
var agent = await agentService.LoadAgent(conversation.AgentId);
|
||||||
conn.CurrentAgentId = agent.Id;
|
conn.CurrentAgentId = agent.Id;
|
||||||
|
|
||||||
|
// Set model
|
||||||
|
var model = agent.LlmConfig.Model;
|
||||||
|
if (!model.Contains("-realtime-"))
|
||||||
|
{
|
||||||
|
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
|
||||||
|
model = llmProviderService.GetProviderModel("openai", "gpt-4", realTime: true).Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
completer.SetModelName(model);
|
||||||
|
conn.Model = model;
|
||||||
|
|
||||||
var routing = _services.GetRequiredService<IRoutingService>();
|
var routing = _services.GetRequiredService<IRoutingService>();
|
||||||
routing.Context.Push(agent.Id);
|
routing.Context.Push(agent.Id);
|
||||||
|
|
||||||
|
|
@ -98,7 +103,7 @@ public class RealtimeHub : IRealtimeHub
|
||||||
|
|
||||||
if (dialogs.LastOrDefault()?.Role == AgentRole.Assistant)
|
if (dialogs.LastOrDefault()?.Role == AgentRole.Assistant)
|
||||||
{
|
{
|
||||||
await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
|
// await completer.TriggerModelInference($"Rephase your last response:\r\n{dialogs.LastOrDefault()?.Content}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,10 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
||||||
Action<RoleDialogModel> onInputAudioTranscriptionCompleted,
|
Action<RoleDialogModel> onInputAudioTranscriptionCompleted,
|
||||||
Action onUserInterrupted)
|
Action onUserInterrupted)
|
||||||
{
|
{
|
||||||
var buffer = new byte[1024 * 1024 * 1];
|
var buffer = new byte[1024 * 256];
|
||||||
WebSocketReceiveResult result;
|
WebSocketReceiveResult result;
|
||||||
string lastAssistantItem = "";
|
string? lastAssistantItem = null;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
result = await _webSocket.ReceiveAsync(
|
result = await _webSocket.ReceiveAsync(
|
||||||
|
|
@ -166,15 +167,17 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"{response.Type}: {receivedText}");
|
_logger.LogInformation($"{response.Type}: {receivedText}");
|
||||||
var data = JsonSerializer.Deserialize<ResponseAudioTranscript>(receivedText);
|
var data = JsonSerializer.Deserialize<ResponseAudioTranscript>(receivedText);
|
||||||
|
await Task.Delay(1000);
|
||||||
onAudioTranscriptDone(data.Transcript);
|
onAudioTranscriptDone(data.Transcript);
|
||||||
}
|
}
|
||||||
else if (response.Type == "response.audio.delta")
|
else if (response.Type == "response.audio.delta")
|
||||||
{
|
{
|
||||||
var audio = JsonSerializer.Deserialize<ResponseAudioDelta>(receivedText);
|
var audio = JsonSerializer.Deserialize<ResponseAudioDelta>(receivedText);
|
||||||
lastAssistantItem = audio?.ItemId ?? "";
|
lastAssistantItem = audio?.ItemId;
|
||||||
|
|
||||||
if (audio != null && audio.Delta != null)
|
if (audio != null && audio.Delta != null)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug($"{response.Type}: {receivedText}");
|
||||||
onModelAudioDeltaReceived(audio.Delta);
|
onModelAudioDeltaReceived(audio.Delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,16 +207,19 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
||||||
{
|
{
|
||||||
// var elapsedTime = latestMediaTimestamp - responseStartTimestampTwilio;
|
// var elapsedTime = latestMediaTimestamp - responseStartTimestampTwilio;
|
||||||
// handle use interuption
|
// handle use interuption
|
||||||
var truncateEvent = new
|
if (!string.IsNullOrEmpty(lastAssistantItem))
|
||||||
{
|
{
|
||||||
type = "conversation.item.truncate",
|
var truncateEvent = new
|
||||||
item_id = lastAssistantItem,
|
{
|
||||||
content_index = 0,
|
type = "conversation.item.truncate",
|
||||||
audio_end_ms = 100
|
item_id = lastAssistantItem,
|
||||||
};
|
content_index = 0,
|
||||||
|
audio_end_ms = 300
|
||||||
|
};
|
||||||
|
|
||||||
await SendEventToModel(truncateEvent);
|
await SendEventToModel(truncateEvent);
|
||||||
onUserInterrupted();
|
onUserInterrupted();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (!result.CloseStatus.HasValue);
|
} while (!result.CloseStatus.HasValue);
|
||||||
|
|
@ -612,7 +618,9 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
||||||
|
|
||||||
outputs.Add(new RoleDialogModel(output.Role, content.Transcript)
|
outputs.Add(new RoleDialogModel(output.Role, content.Transcript)
|
||||||
{
|
{
|
||||||
CurrentAgentId = conn.CurrentAgentId
|
CurrentAgentId = conn.CurrentAgentId,
|
||||||
|
MessageId = output.Id,
|
||||||
|
MessageType = MessageTypeName.Plain
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,14 @@ public class TwilioService
|
||||||
{
|
{
|
||||||
foreach (var speechPath in conversationalVoiceResponse.SpeechPaths)
|
foreach (var speechPath in conversationalVoiceResponse.SpeechPaths)
|
||||||
{
|
{
|
||||||
response.Play(new Uri($"{_settings.CallbackHost}/twilio/voice/speeches/{conversationId}/{speechPath}"));
|
if (speechPath.StartsWith("twilio/"))
|
||||||
|
{
|
||||||
|
response.Play(new Uri($"{_settings.CallbackHost}/{speechPath}"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.Play(new Uri($"{_settings.CallbackHost}/twilio/voice/speeches/{conversationId}/{speechPath}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var connect = new Connect();
|
var connect = new Connect();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue