Merge pull request #1172 from iceljc/master

fix chat stream and websocket close
This commit is contained in:
iceljc 2025-09-23 17:21:37 -05:00 committed by GitHub
commit 6581b2ecbc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 36 additions and 45 deletions

View file

@ -0,0 +1,14 @@
namespace BotSharp.Abstraction.MLTasks.Utilities;
public static class LlmUtility
{
public static string? VerifyModelParameter(string? curVal, string? defaultVal, IEnumerable<string>? options = null)
{
if (options.IsNullOrEmpty())
{
return curVal.IfNullOrEmptyAs(defaultVal);
}
return options.Contains(curVal) ? curVal : defaultVal;
}
}

View file

@ -74,7 +74,7 @@ public class BotSharpRealtimeSession : IDisposable
return; return;
} }
await _websocket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None); await _websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, $"Normal Closure from {nameof(BotSharpRealtimeSession)}-{_sessionOptions?.Provider}", CancellationToken.None);
} }
public void Dispose() public void Dispose()

View file

@ -111,7 +111,7 @@ public class LlmRealtimeSession : IDisposable
if (_webSocket.State == WebSocketState.Open) if (_webSocket.State == WebSocketState.Open)
{ {
await _webSocket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None); await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, $"Normal Closure from {nameof(LlmRealtimeSession)}-{_sessionOptions?.Provider}", CancellationToken.None);
} }
} }

View file

@ -10,7 +10,6 @@ public class ChatStreamMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly ILogger<ChatStreamMiddleware> _logger; private readonly ILogger<ChatStreamMiddleware> _logger;
private BotSharpRealtimeSession _session;
public ChatStreamMiddleware( public ChatStreamMiddleware(
RequestDelegate next, RequestDelegate next,
@ -40,7 +39,6 @@ public class ChatStreamMiddleware
} }
catch (Exception ex) catch (Exception ex)
{ {
_session?.Dispose();
_logger.LogError(ex, $"Error when connecting Chat stream. ({ex.Message})"); _logger.LogError(ex, $"Error when connecting Chat stream. ({ex.Message})");
} }
return; return;
@ -52,8 +50,7 @@ public class ChatStreamMiddleware
private async Task HandleWebSocket(IServiceProvider services, string agentId, string conversationId, WebSocket webSocket) private async Task HandleWebSocket(IServiceProvider services, string agentId, string conversationId, WebSocket webSocket)
{ {
_session?.Dispose(); using var session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions
_session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions
{ {
Provider = "BotSharp Chat Stream", Provider = "BotSharp Chat Stream",
BufferSize = 1024 * 32, BufferSize = 1024 * 32,
@ -72,7 +69,7 @@ public class ChatStreamMiddleware
convService.SetConversationId(conversationId, []); convService.SetConversationId(conversationId, []);
await convService.GetConversationRecordOrCreateNew(agentId); await convService.GetConversationRecordOrCreateNew(agentId);
await foreach (ChatSessionUpdate update in _session.ReceiveUpdatesAsync(CancellationToken.None)) await foreach (ChatSessionUpdate update in session.ReceiveUpdatesAsync(CancellationToken.None))
{ {
var receivedText = update?.RawResponse; var receivedText = update?.RawResponse;
if (string.IsNullOrEmpty(receivedText)) if (string.IsNullOrEmpty(receivedText))
@ -87,7 +84,7 @@ public class ChatStreamMiddleware
_logger.LogCritical($"Start chat stream connection for conversation ({conversationId})"); _logger.LogCritical($"Start chat stream connection for conversation ({conversationId})");
#endif #endif
var request = InitRequest(data, conversationId); var request = InitRequest(data, conversationId);
await ConnectToModel(hub, webSocket, request?.States); await ConnectToModel(hub, session, request?.States);
} }
else if (eventType == "media") else if (eventType == "media")
{ {
@ -107,17 +104,16 @@ public class ChatStreamMiddleware
} }
convService.SaveStates(); convService.SaveStates();
await _session.DisconnectAsync(); await session.DisconnectAsync();
_session.Dispose();
} }
private async Task ConnectToModel(IRealtimeHub hub, WebSocket webSocket, List<MessageState>? states = null) private async Task ConnectToModel(IRealtimeHub hub, BotSharpRealtimeSession session, List<MessageState>? states = null)
{ {
await hub.ConnectToModel(responseToUser: async data => await hub.ConnectToModel(responseToUser: async data =>
{ {
if (_session != null) if (session != null)
{ {
await _session.SendEventAsync(data); await session.SendEventAsync(data);
} }
}, initStates: states); }, initStates: states);
} }

View file

@ -47,8 +47,8 @@ public class AudioTranscriptionProvider : IAudioTranscription
temperature = $"{settings.Temperature}"; temperature = $"{settings.Temperature}";
} }
responseFormat = settings?.ResponseFormat != null ? VerifyTranscriptionParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null;
granularity = settings?.Granularity != null ? VerifyTranscriptionParameter(granularity, settings.Granularity.Default, settings.Granularity.Options) : null; granularity = settings?.Granularity != null ? LlmUtility.VerifyModelParameter(granularity, settings.Granularity.Default, settings.Granularity.Options) : null;
var options = new AudioTranscriptionOptions var options = new AudioTranscriptionOptions
{ {
@ -131,14 +131,4 @@ public class AudioTranscriptionProvider : IAudioTranscription
return temperature; return temperature;
} }
private string? VerifyTranscriptionParameter(string? curVal, string? defaultVal, IEnumerable<string>? options = null)
{
if (options.IsNullOrEmpty())
{
return curVal.IfNullOrEmptyAs(defaultVal);
}
return options.Contains(curVal) ? curVal : defaultVal;
}
} }

View file

@ -61,9 +61,9 @@ public partial class ImageCompletionProvider
var settings = settingsService.GetSetting(Provider, _model)?.Image?.Edit; var settings = settingsService.GetSetting(Provider, _model)?.Image?.Edit;
size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null;
responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null;
background = settings?.Background != null ? VerifyImageParameter(background, settings.Background.Default, settings.Background.Options) : null; background = settings?.Background != null ? LlmUtility.VerifyModelParameter(background, settings.Background.Default, settings.Background.Options) : null;
var options = new ImageEditOptions(); var options = new ImageEditOptions();
if (!string.IsNullOrEmpty(size)) if (!string.IsNullOrEmpty(size))

View file

@ -42,11 +42,11 @@ public partial class ImageCompletionProvider
var settings = settingsService.GetSetting(Provider, _model)?.Image?.Generation; var settings = settingsService.GetSetting(Provider, _model)?.Image?.Generation;
size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null;
quality = settings?.Quality != null ? VerifyImageParameter(quality, settings.Quality.Default, settings.Quality.Options) : null; quality = settings?.Quality != null ? LlmUtility.VerifyModelParameter(quality, settings.Quality.Default, settings.Quality.Options) : null;
style = settings?.Style != null ? VerifyImageParameter(style, settings.Style.Default, settings.Style.Options) : null; style = settings?.Style != null ? LlmUtility.VerifyModelParameter(style, settings.Style.Default, settings.Style.Options) : null;
responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null;
background = settings?.Background != null ? VerifyImageParameter(background, settings.Background.Default, settings.Background.Options) : null; background = settings?.Background != null ? LlmUtility.VerifyModelParameter(background, settings.Background.Default, settings.Background.Options) : null;
var options = new ImageGenerationOptions(); var options = new ImageGenerationOptions();
if (!string.IsNullOrEmpty(size)) if (!string.IsNullOrEmpty(size))

View file

@ -35,8 +35,8 @@ public partial class ImageCompletionProvider
var settings = settingsService.GetSetting(Provider, _model)?.Image?.Variation; var settings = settingsService.GetSetting(Provider, _model)?.Image?.Variation;
size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null;
responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null;
var options = new ImageVariationOptions(); var options = new ImageVariationOptions();
if (!string.IsNullOrEmpty(size)) if (!string.IsNullOrEmpty(size))

View file

@ -201,15 +201,5 @@ public partial class ImageCompletionProvider : IImageCompletion
} }
return retCount; return retCount;
} }
private string? VerifyImageParameter(string? curVal, string? defaultVal, IEnumerable<string>? options = null)
{
if (options.IsNullOrEmpty())
{
return curVal.IfNullOrEmptyAs(defaultVal);
}
return options.Contains(curVal) ? curVal : defaultVal;
}
#endregion #endregion
} }

View file

@ -26,6 +26,7 @@ global using BotSharp.Abstraction.Conversations.Enums;
global using BotSharp.Abstraction.Files.Utilities; global using BotSharp.Abstraction.Files.Utilities;
global using BotSharp.Abstraction.Functions.Models; global using BotSharp.Abstraction.Functions.Models;
global using BotSharp.Abstraction.MLTasks.Settings; global using BotSharp.Abstraction.MLTasks.Settings;
global using BotSharp.Abstraction.MLTasks.Utilities;
global using BotSharp.Abstraction.Options; global using BotSharp.Abstraction.Options;
global using BotSharp.Abstraction.Realtime; global using BotSharp.Abstraction.Realtime;
global using BotSharp.Abstraction.Realtime.Models; global using BotSharp.Abstraction.Realtime.Models;