diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Utilities/LlmUtility.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Utilities/LlmUtility.cs new file mode 100644 index 00000000..0303f6e2 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Utilities/LlmUtility.cs @@ -0,0 +1,14 @@ +namespace BotSharp.Abstraction.MLTasks.Utilities; + +public static class LlmUtility +{ + public static string? VerifyModelParameter(string? curVal, string? defaultVal, IEnumerable? options = null) + { + if (options.IsNullOrEmpty()) + { + return curVal.IfNullOrEmptyAs(defaultVal); + } + + return options.Contains(curVal) ? curVal : defaultVal; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Session/BotSharpRealtimeSession.cs b/src/Infrastructure/BotSharp.Core/Session/BotSharpRealtimeSession.cs index 8dc5b08d..da91e215 100644 --- a/src/Infrastructure/BotSharp.Core/Session/BotSharpRealtimeSession.cs +++ b/src/Infrastructure/BotSharp.Core/Session/BotSharpRealtimeSession.cs @@ -74,7 +74,7 @@ public class BotSharpRealtimeSession : IDisposable 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() diff --git a/src/Infrastructure/BotSharp.Core/Session/LlmRealtimeSession.cs b/src/Infrastructure/BotSharp.Core/Session/LlmRealtimeSession.cs index 9e1df1cd..8aa5fa31 100644 --- a/src/Infrastructure/BotSharp.Core/Session/LlmRealtimeSession.cs +++ b/src/Infrastructure/BotSharp.Core/Session/LlmRealtimeSession.cs @@ -111,7 +111,7 @@ public class LlmRealtimeSession : IDisposable 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); } } diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatStreamMiddleware.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatStreamMiddleware.cs index 0d8aa0b3..44a6195a 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatStreamMiddleware.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatStreamMiddleware.cs @@ -10,7 +10,6 @@ public class ChatStreamMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; - private BotSharpRealtimeSession _session; public ChatStreamMiddleware( RequestDelegate next, @@ -40,7 +39,6 @@ public class ChatStreamMiddleware } catch (Exception ex) { - _session?.Dispose(); _logger.LogError(ex, $"Error when connecting Chat stream. ({ex.Message})"); } return; @@ -52,8 +50,7 @@ public class ChatStreamMiddleware private async Task HandleWebSocket(IServiceProvider services, string agentId, string conversationId, WebSocket webSocket) { - _session?.Dispose(); - _session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions + using var session = new BotSharpRealtimeSession(services, webSocket, new ChatSessionOptions { Provider = "BotSharp Chat Stream", BufferSize = 1024 * 32, @@ -72,7 +69,7 @@ public class ChatStreamMiddleware convService.SetConversationId(conversationId, []); 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; if (string.IsNullOrEmpty(receivedText)) @@ -87,7 +84,7 @@ public class ChatStreamMiddleware _logger.LogCritical($"Start chat stream connection for conversation ({conversationId})"); #endif var request = InitRequest(data, conversationId); - await ConnectToModel(hub, webSocket, request?.States); + await ConnectToModel(hub, session, request?.States); } else if (eventType == "media") { @@ -107,17 +104,16 @@ public class ChatStreamMiddleware } convService.SaveStates(); - await _session.DisconnectAsync(); - _session.Dispose(); + await session.DisconnectAsync(); } - private async Task ConnectToModel(IRealtimeHub hub, WebSocket webSocket, List? states = null) + private async Task ConnectToModel(IRealtimeHub hub, BotSharpRealtimeSession session, List? states = null) { await hub.ConnectToModel(responseToUser: async data => { - if (_session != null) + if (session != null) { - await _session.SendEventAsync(data); + await session.SendEventAsync(data); } }, initStates: states); } diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Audio/AudioTranscriptionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Audio/AudioTranscriptionProvider.cs index 462d1fb6..006a41b8 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Audio/AudioTranscriptionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Audio/AudioTranscriptionProvider.cs @@ -47,8 +47,8 @@ public class AudioTranscriptionProvider : IAudioTranscription temperature = $"{settings.Temperature}"; } - responseFormat = settings?.ResponseFormat != null ? VerifyTranscriptionParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; - granularity = settings?.Granularity != null ? VerifyTranscriptionParameter(granularity, settings.Granularity.Default, settings.Granularity.Options) : null; + responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; + granularity = settings?.Granularity != null ? LlmUtility.VerifyModelParameter(granularity, settings.Granularity.Default, settings.Granularity.Options) : null; var options = new AudioTranscriptionOptions { @@ -131,14 +131,4 @@ public class AudioTranscriptionProvider : IAudioTranscription return temperature; } - - private string? VerifyTranscriptionParameter(string? curVal, string? defaultVal, IEnumerable? options = null) - { - if (options.IsNullOrEmpty()) - { - return curVal.IfNullOrEmptyAs(defaultVal); - } - - return options.Contains(curVal) ? curVal : defaultVal; - } } diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs index 28e44a8e..732cc7a9 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Edit.cs @@ -61,9 +61,9 @@ public partial class ImageCompletionProvider var settings = settingsService.GetSetting(Provider, _model)?.Image?.Edit; - size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; - responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; - background = settings?.Background != null ? VerifyImageParameter(background, settings.Background.Default, settings.Background.Options) : null; + size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null; + responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; + background = settings?.Background != null ? LlmUtility.VerifyModelParameter(background, settings.Background.Default, settings.Background.Options) : null; var options = new ImageEditOptions(); if (!string.IsNullOrEmpty(size)) diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Generation.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Generation.cs index 722f50d9..c1ad30d1 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Generation.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Generation.cs @@ -42,11 +42,11 @@ public partial class ImageCompletionProvider var settings = settingsService.GetSetting(Provider, _model)?.Image?.Generation; - size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; - quality = settings?.Quality != null ? VerifyImageParameter(quality, settings.Quality.Default, settings.Quality.Options) : null; - style = settings?.Style != null ? VerifyImageParameter(style, settings.Style.Default, settings.Style.Options) : null; - responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; - background = settings?.Background != null ? VerifyImageParameter(background, settings.Background.Default, settings.Background.Options) : null; + size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null; + quality = settings?.Quality != null ? LlmUtility.VerifyModelParameter(quality, settings.Quality.Default, settings.Quality.Options) : null; + style = settings?.Style != null ? LlmUtility.VerifyModelParameter(style, settings.Style.Default, settings.Style.Options) : null; + responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; + background = settings?.Background != null ? LlmUtility.VerifyModelParameter(background, settings.Background.Default, settings.Background.Options) : null; var options = new ImageGenerationOptions(); if (!string.IsNullOrEmpty(size)) diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Variation.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Variation.cs index 2f4efb18..22d8f2a5 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Variation.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.Variation.cs @@ -35,8 +35,8 @@ public partial class ImageCompletionProvider var settings = settingsService.GetSetting(Provider, _model)?.Image?.Variation; - size = settings?.Size != null ? VerifyImageParameter(size, settings.Size.Default, settings.Size.Options) : null; - responseFormat = settings?.ResponseFormat != null ? VerifyImageParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; + size = settings?.Size != null ? LlmUtility.VerifyModelParameter(size, settings.Size.Default, settings.Size.Options) : null; + responseFormat = settings?.ResponseFormat != null ? LlmUtility.VerifyModelParameter(responseFormat, settings.ResponseFormat.Default, settings.ResponseFormat.Options) : null; var options = new ImageVariationOptions(); if (!string.IsNullOrEmpty(size)) diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.cs index 883c22ab..919054b1 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Image/ImageCompletionProvider.cs @@ -201,15 +201,5 @@ public partial class ImageCompletionProvider : IImageCompletion } return retCount; } - - private string? VerifyImageParameter(string? curVal, string? defaultVal, IEnumerable? options = null) - { - if (options.IsNullOrEmpty()) - { - return curVal.IfNullOrEmptyAs(defaultVal); - } - - return options.Contains(curVal) ? curVal : defaultVal; - } #endregion } diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Using.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Using.cs index b8c75d29..b2bafc7b 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Using.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Using.cs @@ -26,6 +26,7 @@ global using BotSharp.Abstraction.Conversations.Enums; global using BotSharp.Abstraction.Files.Utilities; global using BotSharp.Abstraction.Functions.Models; global using BotSharp.Abstraction.MLTasks.Settings; +global using BotSharp.Abstraction.MLTasks.Utilities; global using BotSharp.Abstraction.Options; global using BotSharp.Abstraction.Realtime; global using BotSharp.Abstraction.Realtime.Models;