prevent initial response interruption

This commit is contained in:
Haiping Chen 2025-03-05 16:57:58 -06:00
parent 9c50824369
commit 89fc99f4e1
5 changed files with 19 additions and 13 deletions

View file

@ -24,7 +24,7 @@ public interface IRealTimeCompletion
Task Disconnect();
Task<RealtimeSession> CreateSession(Agent agent, List<RoleDialogModel> conversations);
Task UpdateSession(RealtimeHubConnection conn);
Task UpdateSession(RealtimeHubConnection conn, bool turnDetection = true);
Task InsertConversationItem(RoleDialogModel message);
Task RemoveConversationItem(string itemId);
Task TriggerModelInference(string? instructions = null);

View file

@ -99,8 +99,8 @@ public class RealtimeHub : IRealtimeHub
await completer.Connect(conn,
onModelReady: async () =>
{
// Control initial session
await completer.UpdateSession(conn);
// Control initial session, prevent initial response interruption
await completer.UpdateSession(conn, turnDetection: false);
// Add dialog history
foreach (var item in dialogs)
@ -110,12 +110,16 @@ public class RealtimeHub : IRealtimeHub
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
{
await completer.TriggerModelInference("Reply based on the conversation context.");
}
// Start turn detection
await Task.Delay(1000 * 8);
await completer.UpdateSession(conn, turnDetection: true);
},
onModelAudioDeltaReceived: async audioDeltaData =>
{

View file

@ -47,7 +47,7 @@ public class RealtimeSessionBody
public FunctionDef[] Tools { get; set; } = [];
[JsonPropertyName("turn_detection")]
public RealtimeSessionTurnDetection TurnDetection { get; set; } = new();
public RealtimeSessionTurnDetection? TurnDetection { get; set; } = new();
}
public class RealtimeSessionTurnDetection

View file

@ -59,10 +59,9 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
if (_webSocket.State == WebSocketState.Open)
{
onModelReady();
// Receive a message
_ = ReceiveMessage(conn,
onModelReady,
onModelAudioDeltaReceived,
onModelAudioResponseDone,
onAudioTranscriptDone,
@ -122,7 +121,8 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
});
}
private async Task ReceiveMessage(RealtimeHubConnection conn,
private async Task ReceiveMessage(RealtimeHubConnection conn,
Action onModelReady,
Action<string> onModelAudioDeltaReceived,
Action onModelAudioResponseDone,
Action<string> onAudioTranscriptDone,
@ -156,6 +156,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
else if (response.Type == "session.created")
{
_logger.LogInformation($"{response.Type}: {receivedText}");
onModelReady();
}
else if (response.Type == "session.updated")
{
@ -295,7 +296,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
return session;
}
public async Task UpdateSession(RealtimeHubConnection conn)
public async Task UpdateSession(RealtimeHubConnection conn, bool turnDetection = true)
{
var convService = _services.GetRequiredService<IConversationService>();
var conv = await convService.GetConversation(conn.ConversationId);
@ -346,6 +347,11 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
}
};
if (!turnDetection)
{
sessionUpdate.session.TurnDetection = null;
}
await HookEmitter.Emit<IContentGeneratingHook>(_services, async hook =>
{
await hook.OnSessionUpdated(agent, instruction, functions);

View file

@ -1,13 +1,9 @@
using BotSharp.Abstraction.Realtime;
using BotSharp.Abstraction.Realtime.Models;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models.Stream;
using Microsoft.AspNetCore.Http;
using System.Net.WebSockets;
using System.Text.Json;
using System.Collections.Concurrent;
using System.Text;
using Task = System.Threading.Tasks.Task;
namespace BotSharp.Plugin.Twilio.Services.Stream;