Merge branch 'master' of https://github.com/SciSharp/BotSharp into features/add-agent-function-visibility
This commit is contained in:
commit
0341a0f7a9
|
|
@ -56,8 +56,9 @@ public class ChatStreamMiddleware
|
|||
_session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions
|
||||
{
|
||||
Provider = "BotSharp Chat Stream",
|
||||
BufferSize = 1024 * 16,
|
||||
JsonOptions = BotSharpOptions.defaultJsonOptions
|
||||
BufferSize = 1024 * 32,
|
||||
JsonOptions = BotSharpOptions.defaultJsonOptions,
|
||||
Logger = _logger
|
||||
});
|
||||
|
||||
var hub = services.GetRequiredService<IRealtimeHub>();
|
||||
|
|
@ -79,10 +80,13 @@ public class ChatStreamMiddleware
|
|||
continue;
|
||||
}
|
||||
|
||||
var (eventType, data) = MapEvents(conn, receivedText);
|
||||
var (eventType, data) = MapEvents(conn, receivedText, conversationId);
|
||||
if (eventType == "start")
|
||||
{
|
||||
var request = InitRequest(data);
|
||||
#if DEBUG
|
||||
_logger.LogCritical($"Start chat stream connection for conversation ({conversationId})");
|
||||
#endif
|
||||
var request = InitRequest(data, conversationId);
|
||||
await ConnectToModel(hub, webSocket, request?.States);
|
||||
}
|
||||
else if (eventType == "media")
|
||||
|
|
@ -94,6 +98,9 @@ public class ChatStreamMiddleware
|
|||
}
|
||||
else if (eventType == "disconnect")
|
||||
{
|
||||
#if DEBUG
|
||||
_logger.LogCritical($"Disconnecting chat stream connection for conversation ({conversationId})");
|
||||
#endif
|
||||
await hub.Completer.Disconnect();
|
||||
break;
|
||||
}
|
||||
|
|
@ -115,11 +122,20 @@ public class ChatStreamMiddleware
|
|||
}, initStates: states);
|
||||
}
|
||||
|
||||
private (string, string) MapEvents(RealtimeHubConnection conn, string receivedText)
|
||||
private (string, string) MapEvents(RealtimeHubConnection conn, string receivedText, string conversationId)
|
||||
{
|
||||
var response = JsonSerializer.Deserialize<ChatStreamEventResponse>(receivedText);
|
||||
var data = response?.Body?.Payload ?? string.Empty;
|
||||
ChatStreamEventResponse? response = new();
|
||||
|
||||
try
|
||||
{
|
||||
response = JsonSerializer.Deserialize<ChatStreamEventResponse>(receivedText);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error when deserializing chat stream event response for conversation ({conversationId}) (response: {receivedText?.SubstringMax(30)})");
|
||||
}
|
||||
|
||||
var data = response?.Body?.Payload ?? string.Empty;
|
||||
switch (response.Event)
|
||||
{
|
||||
case "start":
|
||||
|
|
@ -157,14 +173,15 @@ public class ChatStreamMiddleware
|
|||
});
|
||||
}
|
||||
|
||||
private ChatStreamRequest? InitRequest(string data)
|
||||
private ChatStreamRequest? InitRequest(string data, string conversationId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<ChatStreamRequest>(data, BotSharpOptions.defaultJsonOptions);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error when deserializing initial request data for conversation ({conversationId}).");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
using BotSharp.Abstraction.Hooks;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Abstraction.Options;
|
||||
using BotSharp.Abstraction.Realtime;
|
||||
using BotSharp.Abstraction.Realtime.Models;
|
||||
using BotSharp.Abstraction.Realtime.Models.Session;
|
||||
using BotSharp.Abstraction.Routing;
|
||||
using BotSharp.Abstraction.Utilities;
|
||||
using BotSharp.Core.Session;
|
||||
using BotSharp.Plugin.Twilio.Interfaces;
|
||||
using BotSharp.Plugin.Twilio.Models.Stream;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -20,8 +23,11 @@ public class TwilioStreamMiddleware
|
|||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<TwilioStreamMiddleware> _logger;
|
||||
private BotSharpRealtimeSession _session;
|
||||
|
||||
public TwilioStreamMiddleware(RequestDelegate next, ILogger<TwilioStreamMiddleware> logger)
|
||||
public TwilioStreamMiddleware(
|
||||
RequestDelegate next,
|
||||
ILogger<TwilioStreamMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
|
|
@ -46,6 +52,7 @@ public class TwilioStreamMiddleware
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_session?.Dispose();
|
||||
_logger.LogError(ex, $"Error in WebSocket communication: {ex.Message} for conversation {conversationId}");
|
||||
}
|
||||
return;
|
||||
|
|
@ -57,7 +64,15 @@ public class TwilioStreamMiddleware
|
|||
|
||||
private async Task HandleWebSocket(IServiceProvider services, string agentId, string conversationId, WebSocket webSocket)
|
||||
{
|
||||
var settings = services.GetRequiredService<RealtimeModelSettings>();
|
||||
_session?.Dispose();
|
||||
_session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions
|
||||
{
|
||||
Provider = "BotSharp Twilio Stream",
|
||||
BufferSize = 1024 * 32,
|
||||
JsonOptions = BotSharpOptions.defaultJsonOptions,
|
||||
Logger = _logger
|
||||
});
|
||||
|
||||
var hub = services.GetRequiredService<IRealtimeHub>();
|
||||
var conn = hub.SetHubConnection(conversationId);
|
||||
conn.CurrentAgentId = agentId;
|
||||
|
|
@ -65,25 +80,21 @@ public class TwilioStreamMiddleware
|
|||
// load conversation and state
|
||||
var convService = services.GetRequiredService<IConversationService>();
|
||||
convService.SetConversationId(conversationId, []);
|
||||
|
||||
var hooks = services.GetHooks<ITwilioSessionHook>(agentId);
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnStreamingStarted(conn);
|
||||
}
|
||||
|
||||
convService.States.Save();
|
||||
|
||||
var routing = services.GetRequiredService<IRoutingService>();
|
||||
routing.Context.Push(agentId);
|
||||
|
||||
var buffer = new byte[1024 * 32];
|
||||
WebSocketReceiveResult result;
|
||||
|
||||
do
|
||||
await foreach (ChatSessionUpdate update in _session.ReceiveUpdatesAsync(CancellationToken.None))
|
||||
{
|
||||
Array.Clear(buffer, 0, buffer.Length);
|
||||
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
string receivedText = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
|
||||
var receivedText = update?.RawResponse;
|
||||
if (string.IsNullOrEmpty(receivedText))
|
||||
{
|
||||
continue;
|
||||
|
|
@ -128,10 +139,13 @@ public class TwilioStreamMiddleware
|
|||
#endif
|
||||
await hub.Completer.Disconnect();
|
||||
await HandleUserDisconnected();
|
||||
break;
|
||||
}
|
||||
} while (!result.CloseStatus.HasValue);
|
||||
}
|
||||
|
||||
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||
convService.SaveStates();
|
||||
await _session.DisconnectAsync();
|
||||
_session.Dispose();
|
||||
}
|
||||
|
||||
private async Task ConnectToModel(IRealtimeHub hub, WebSocket webSocket)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,15 @@
|
|||
"phone_number": {
|
||||
"type": "string",
|
||||
"description": "Phone number transfer to."
|
||||
},
|
||||
"transfer_required_by_user": {
|
||||
"type": "boolean",
|
||||
"description": "Only set to true if the user initially and directly asks for a representative, otherwise false."
|
||||
}
|
||||
},
|
||||
"required": [ "transition_message", "phone_number" ]
|
||||
"required": [
|
||||
"transition_message",
|
||||
"phone_number"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue