Merge pull request #1000 from hchen2020/master
Add InterruptResponse in RealtimeModelSettings
This commit is contained in:
commit
2ddfb5289f
|
|
@ -23,7 +23,7 @@ public interface IRealTimeCompletion
|
|||
Task SendEventToModel(object message);
|
||||
Task Disconnect();
|
||||
|
||||
Task<string> UpdateSession(RealtimeHubConnection conn, bool interruptResponse = true);
|
||||
Task<string> UpdateSession(RealtimeHubConnection conn);
|
||||
Task InsertConversationItem(RoleDialogModel message);
|
||||
Task RemoveConversationItem(string itemId);
|
||||
Task TriggerModelInference(string? instructions = null);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Realtime.Models;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace BotSharp.Abstraction.Realtime;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ public class RealtimeHubConnection
|
|||
public long LatestMediaTimestamp { get; set; }
|
||||
public long? ResponseStartTimestamp { get; set; }
|
||||
public string KeypadInputBuffer { get; set; } = string.Empty;
|
||||
public ConcurrentQueue<string> MarkQueue { get; set; } = new();
|
||||
public string CurrentAgentId { get; set; } = null!;
|
||||
public string ConversationId { get; set; } = null!;
|
||||
public Func<string, string> OnModelMessageReceived { get; set; } = null!;
|
||||
|
|
@ -18,7 +17,6 @@ public class RealtimeHubConnection
|
|||
|
||||
public void ResetResponseState()
|
||||
{
|
||||
MarkQueue.Clear();
|
||||
LastAssistantItemId = null;
|
||||
ResponseStartTimestamp = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ namespace BotSharp.Abstraction.Realtime.Models;
|
|||
|
||||
public class RealtimeModelSettings
|
||||
{
|
||||
public bool InterruptResponse { get; set; } = false;
|
||||
public string InputAudioFormat { get; set; } = "g711_ulaw";
|
||||
public string OutputAudioFormat { get; set; } = "g711_ulaw";
|
||||
public string Voice { get; set; } = "alloy";
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class RealtimeHub : IRealtimeHub
|
|||
routing.Context.SetMessageId(_conn.ConversationId, dialogs.Last().MessageId);
|
||||
|
||||
var states = _services.GetRequiredService<IConversationStateService>();
|
||||
var realtimeModelSettings = _services.GetRequiredService<RealtimeModelSettings>();
|
||||
|
||||
await _completer.Connect(_conn,
|
||||
onModelReady: async () =>
|
||||
|
|
@ -99,9 +100,7 @@ public class RealtimeHub : IRealtimeHub
|
|||
await HookEmitter.Emit<IRoutingHook>(_services, async hook => await hook.OnRoutingInstructionReceived(instruction, message));
|
||||
}
|
||||
|
||||
var delay = Task.Delay(1000);
|
||||
routing.InvokeFunction(message.FunctionName, message);
|
||||
await delay;
|
||||
await routing.InvokeFunction(message.FunctionName, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -140,11 +139,14 @@ public class RealtimeHub : IRealtimeHub
|
|||
},
|
||||
onUserInterrupted: async () =>
|
||||
{
|
||||
// Reset states
|
||||
_conn.ResetResponseState();
|
||||
if (realtimeModelSettings.InterruptResponse)
|
||||
{
|
||||
// Reset states
|
||||
_conn.ResetResponseState();
|
||||
|
||||
var data = _conn.OnModelUserInterrupted();
|
||||
await responseToUser(data);
|
||||
var data = _conn.OnModelUserInterrupted();
|
||||
await responseToUser(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using GenerativeAI.Core;
|
|||
using GenerativeAI.Live;
|
||||
using GenerativeAI.Live.Extensions;
|
||||
using GenerativeAI.Types;
|
||||
using System;
|
||||
|
||||
namespace BotSharp.Plugin.GoogleAi.Providers.Realtime;
|
||||
|
||||
|
|
@ -235,7 +234,7 @@ public class GoogleRealTimeProvider : IRealTimeCompletion
|
|||
//todo Send Audio Chunks to Model, Botsharp RealTime Implementation seems to be incomplete
|
||||
}
|
||||
|
||||
public async Task<string> UpdateSession(RealtimeHubConnection conn, bool interruptResponse = true)
|
||||
public async Task<string> UpdateSession(RealtimeHubConnection conn)
|
||||
{
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var conv = await convService.GetConversation(conn.ConversationId);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ public class RealtimeSessionTurnDetection
|
|||
[JsonPropertyName("threshold")]
|
||||
public float Threshold { get; set; } = 0.5f;*/
|
||||
|
||||
/// <summary>
|
||||
/// server_vad, semantic_vad
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = "semantic_vad";
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
|||
else if (response.Type == "input_audio_buffer.speech_started")
|
||||
{
|
||||
// Handle user interuption
|
||||
if (conn.MarkQueue.Count > 0 && conn.ResponseStartTimestamp != null)
|
||||
if (conn.ResponseStartTimestamp != null)
|
||||
{
|
||||
var elapsedTime = conn.LatestMediaTimestamp - conn.ResponseStartTimestamp;
|
||||
|
||||
|
|
@ -284,7 +284,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
|||
await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
|
||||
public async Task<string> UpdateSession(RealtimeHubConnection conn, bool interruptResponse = true)
|
||||
public async Task<string> UpdateSession(RealtimeHubConnection conn)
|
||||
{
|
||||
var convService = _services.GetRequiredService<IConversationService>();
|
||||
var conv = await convService.GetConversation(conn.ConversationId);
|
||||
|
|
@ -335,7 +335,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
|
|||
MaxResponseOutputTokens = realtimeModelSettings.MaxResponseOutputTokens,
|
||||
TurnDetection = new RealtimeSessionTurnDetection
|
||||
{
|
||||
InterruptResponse = interruptResponse/*,
|
||||
InterruptResponse = realtimeModelSettings.InterruptResponse/*,
|
||||
Threshold = realtimeModelSettings.TurnDetection.Threshold,
|
||||
PrefixPadding = realtimeModelSettings.TurnDetection.PrefixPadding,
|
||||
SilenceDuration = realtimeModelSettings.TurnDetection.SilenceDuration*/
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ public class TwilioStreamMiddleware
|
|||
if (eventType == "user_connected")
|
||||
{
|
||||
// Connect to model
|
||||
await hub.ConnectToModel(async data =>
|
||||
{
|
||||
await SendEventToUser(webSocket, data);
|
||||
});
|
||||
await ConnectToModel(hub, webSocket);
|
||||
}
|
||||
else if (eventType == "user_data_received")
|
||||
{
|
||||
|
|
@ -112,6 +109,14 @@ public class TwilioStreamMiddleware
|
|||
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||
}
|
||||
|
||||
private async Task ConnectToModel(IRealtimeHub hub, WebSocket webSocket)
|
||||
{
|
||||
await hub.ConnectToModel(async data =>
|
||||
{
|
||||
await SendEventToUser(webSocket, data);
|
||||
});
|
||||
}
|
||||
|
||||
private (string, string) MapEvents(RealtimeHubConnection conn, string receivedText)
|
||||
{
|
||||
var response = JsonSerializer.Deserialize<StreamEventResponse>(receivedText);
|
||||
|
|
@ -136,10 +141,6 @@ public class TwilioStreamMiddleware
|
|||
case "stop":
|
||||
eventType = "user_disconnected";
|
||||
break;
|
||||
case "mark":
|
||||
eventType = "mark";
|
||||
if (conn.MarkQueue.Count > 0) conn.MarkQueue.TryDequeue(out var _);
|
||||
break;
|
||||
case "dtmf":
|
||||
var dtmfResponse = JsonSerializer.Deserialize<StreamEventDtmfResponse>(receivedText);
|
||||
if (dtmfResponse.Body.Digit == "#")
|
||||
|
|
@ -210,7 +211,6 @@ public class TwilioStreamMiddleware
|
|||
};
|
||||
var message = JsonSerializer.Serialize(markEvent);
|
||||
await SendEventToUser(userWebSocket, message);
|
||||
conn.MarkQueue.Enqueue("responsePart");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue