From 95d3dcefe69a4d1edc29300bd655d464f5592c50 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 18 Jun 2025 04:23:18 -0700 Subject: [PATCH 1/5] Update OpenAIEmbedding.cs --- src/Custom/Embeddings/OpenAIEmbedding.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Custom/Embeddings/OpenAIEmbedding.cs b/src/Custom/Embeddings/OpenAIEmbedding.cs index ac644c843..ae304ab4e 100644 --- a/src/Custom/Embeddings/OpenAIEmbedding.cs +++ b/src/Custom/Embeddings/OpenAIEmbedding.cs @@ -121,6 +121,7 @@ private static ReadOnlyMemory ConvertToVectorOfFloats(BinaryData binaryDa OperationStatus status = Base64.DecodeFromUtf8(base64, bytes.AsSpan(), out int bytesConsumed, out int bytesWritten); if (status != OperationStatus.Done || bytesWritten % sizeof(float) != 0) { + ArrayPool.Shared.Return(bytes); ThrowInvalidData(); } From a5325a73c3c206eed1660cbdd5fcedc3ea0526a3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 18 Jun 2025 04:27:01 -0700 Subject: [PATCH 2/5] Update AsyncWebsocketMessageEnumerator.cs --- .../Internal/AsyncWebsocketMessageEnumerator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs index 3df40ef6f..906823ff0 100644 --- a/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs +++ b/src/Custom/RealtimeConversation/Internal/AsyncWebsocketMessageEnumerator.cs @@ -26,6 +26,7 @@ public AsyncWebsocketMessageResultEnumerator(WebSocket webSocket, CancellationTo public ValueTask DisposeAsync() { + ArrayPool.Shared.Return(_receiveBuffer); _webSocket?.Dispose(); return new ValueTask(Task.CompletedTask); } @@ -50,4 +51,4 @@ public async ValueTask MoveNextAsync() Current = ClientResult.FromResponse(websocketPipelineResponse); return true; } -} \ No newline at end of file +} From a864ffafba2f8a956a62d0a64d58a5b8f640095f Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 18 Jun 2025 04:29:14 -0700 Subject: [PATCH 3/5] Update RealtimeConversationSession.cs --- .../RealtimeConversation/RealtimeConversationSession.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Custom/RealtimeConversation/RealtimeConversationSession.cs b/src/Custom/RealtimeConversation/RealtimeConversationSession.cs index 31a4ef50a..f27bc600c 100644 --- a/src/Custom/RealtimeConversation/RealtimeConversationSession.cs +++ b/src/Custom/RealtimeConversation/RealtimeConversationSession.cs @@ -55,9 +55,9 @@ public virtual async Task SendInputAudioAsync(Stream audio, CancellationToken ca } _isSendingAudioStream = true; } + byte[] buffer = ArrayPool.Shared.Rent(1024 * 16); try { - byte[] buffer = ArrayPool.Shared.Rent(1024 * 16); while (true) { int bytesRead = await audio.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); @@ -75,6 +75,7 @@ public virtual async Task SendInputAudioAsync(Stream audio, CancellationToken ca } finally { + ArrayPool.Shared.Return(buffer); using (await _audioSendSemaphore.AutoReleaseWaitAsync(cancellationToken).ConfigureAwait(false)) { _isSendingAudioStream = false; @@ -93,9 +94,9 @@ public virtual void SendInputAudio(Stream audio, CancellationToken cancellationT } _isSendingAudioStream = true; } + byte[] buffer = ArrayPool.Shared.Rent(1024 * 16); try { - byte[] buffer = ArrayPool.Shared.Rent(1024 * 16); while (true) { int bytesRead = audio.Read(buffer, 0, buffer.Length); @@ -113,6 +114,7 @@ public virtual void SendInputAudio(Stream audio, CancellationToken cancellationT } finally { + ArrayPool.Shared.Return(buffer); using (_audioSendSemaphore.AutoReleaseWait(cancellationToken)) { _isSendingAudioStream = false; @@ -349,4 +351,4 @@ public void Dispose() { WebSocket?.Dispose(); } -} \ No newline at end of file +} From 22c09995be7586710d10f3debe86a3c71a8bde99 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 18 Jun 2025 04:34:33 -0700 Subject: [PATCH 4/5] Update ConversationTests.cs Not used --- tests/RealtimeConversation/ConversationTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/RealtimeConversation/ConversationTests.cs b/tests/RealtimeConversation/ConversationTests.cs index 9c855d009..66141cf44 100644 --- a/tests/RealtimeConversation/ConversationTests.cs +++ b/tests/RealtimeConversation/ConversationTests.cs @@ -341,7 +341,6 @@ public async Task AudioWithToolsWorks(TestAudioSendType audioSendType) { byte[] allAudioBytes = await File.ReadAllBytesAsync(inputAudioFilePath, CancellationToken); const int audioSendBufferLength = 8 * 1024; - byte[] audioSendBuffer = ArrayPool.Shared.Rent(audioSendBufferLength); for (int readPos = 0; readPos < allAudioBytes.Length; readPos += audioSendBufferLength) { int nextSegmentLength = Math.Min(audioSendBufferLength, allAudioBytes.Length - readPos); From 16281ae81797ac06441fcf5f624068bae3d306c5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 22 Jun 2025 21:27:32 +0200 Subject: [PATCH 5/5] Move to finally --- src/Custom/Embeddings/OpenAIEmbedding.cs | 43 +++++++++++++----------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/Custom/Embeddings/OpenAIEmbedding.cs b/src/Custom/Embeddings/OpenAIEmbedding.cs index ae304ab4e..cbb581e29 100644 --- a/src/Custom/Embeddings/OpenAIEmbedding.cs +++ b/src/Custom/Embeddings/OpenAIEmbedding.cs @@ -118,33 +118,36 @@ private static ReadOnlyMemory ConvertToVectorOfFloats(BinaryData binaryDa // Decode base64 string to bytes. byte[] bytes = ArrayPool.Shared.Rent(Base64.GetMaxDecodedFromUtf8Length(base64.Length)); - OperationStatus status = Base64.DecodeFromUtf8(base64, bytes.AsSpan(), out int bytesConsumed, out int bytesWritten); - if (status != OperationStatus.Done || bytesWritten % sizeof(float) != 0) - { - ArrayPool.Shared.Return(bytes); - ThrowInvalidData(); - } - - // Interpret bytes as floats - float[] vector = new float[bytesWritten / sizeof(float)]; - bytes.AsSpan(0, bytesWritten).CopyTo(MemoryMarshal.AsBytes(vector.AsSpan())); - if (!BitConverter.IsLittleEndian) - { - Span ints = MemoryMarshal.Cast(vector.AsSpan()); + try + { + OperationStatus status = Base64.DecodeFromUtf8(base64, bytes.AsSpan(), out int bytesConsumed, out int bytesWritten); + if (status != OperationStatus.Done || bytesWritten % sizeof(float) != 0) + { + ThrowInvalidData(); + } + + // Interpret bytes as floats + float[] vector = new float[bytesWritten / sizeof(float)]; + bytes.AsSpan(0, bytesWritten).CopyTo(MemoryMarshal.AsBytes(vector.AsSpan())); + if (!BitConverter.IsLittleEndian) + { + Span ints = MemoryMarshal.Cast(vector.AsSpan()); #if NET8_0_OR_GREATER - BinaryPrimitives.ReverseEndianness(ints, ints); + BinaryPrimitives.ReverseEndianness(ints, ints); #else for (int i = 0; i < ints.Length; i++) { ints[i] = BinaryPrimitives.ReverseEndianness(ints[i]); } #endif + } + return new ReadOnlyMemory(vector); + } + finally + { + ArrayPool.Shared.Return(bytes); } - - ArrayPool.Shared.Return(bytes); - return new ReadOnlyMemory(vector); - - static void ThrowInvalidData() => + } + static void ThrowInvalidData() => throw new FormatException("The input is not a valid Base64 string of encoded floats."); - } }