Untitled

mail@pastecode.io avatar
unknown
csharp
a month ago
6.1 kB
3
Indexable
Never
using System.Net.WebSockets;
using System.Text.Json;

using Apex.BFF.Application.Common.Interfaces;
using Apex.BFF.Infrastructure.Services.AzureAiTranslation;

using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using Microsoft.CognitiveServices.Speech.Translation;
using Microsoft.Extensions.Options;

namespace Apex.BFF.Infrastructure.Services.AITranslationService;

public class TranslationService(IOptions<TranslationServiceSettings> settings) : ITranslationService
{
    private readonly TranslationServiceSettings _serviceSettings = settings.Value;

    public async Task HandleWebSocketAsync(WebSocket webSocket, List<string>? targetLanguages)
    {
        try
        {
            var v2EndpointInString = $"wss://{_serviceSettings.Region}.stt.speech.microsoft.com/speech/universal/v2";

            var v2EndpointUrl = new Uri(v2EndpointInString);
            var config = SpeechTranslationConfig.FromEndpoint(v2EndpointUrl, _serviceSettings.ApiKey);

            var autoDetectSourceLanguageConfig =
                AutoDetectSourceLanguageConfig.FromLanguages(["en-US", "es-ES"]);

            config.AddTargetLanguage("es");
            config.AddTargetLanguage("en");

             using var audioInput = AudioConfig.FromStreamInput(new WebSocketAudioInput(webSocket));

            using var recognizer = new TranslationRecognizer(config, autoDetectSourceLanguageConfig);

            recognizer.Recognized += async (s, e) =>
            {
                var lidResult =
                    e.Result.Properties.GetProperty(PropertyId.SpeechServiceConnection_AutoDetectSourceLanguageResult);

                if (e.Result.Reason == ResultReason.TranslatedSpeech)
                {
                    await HandleTranslationsAsync(lidResult.Substring(0, 2), e.Result.Translations, webSocket);
                }
            };


            recognizer.Canceled += (s, e) =>
            {
                Console.WriteLine($"Recognition canceled: {e.Reason}");
                if (e.Reason == CancellationReason.Error)
                {
                    Console.WriteLine($"Error details: {e.ErrorDetails}");
                }
            };

            recognizer.SessionStarted += (s, e) => Console.WriteLine("Session started");
            recognizer.SessionStopped += (s, e) => Console.WriteLine("Session stopped");

            recognizer.Recognized += (s, e) => Console.WriteLine(e.Result.Reason == ResultReason.TranslatedSpeech
                ? $"Recognized: {e.Result.Text}"
                : $"Recognized event reason: {e.Result.Reason}");

            await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
            var buffer = new byte[1024 * 4];

            while (webSocket.State == WebSocketState.Open)
            {
                var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                        CancellationToken.None);
                    Console.WriteLine("WebSocket closed.");
                }
            }

            await recognizer.StopContinuousRecognitionAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"WebSocket receive error: {ex.Message}");
            throw;
        }
    }

    private async Task<byte[]> SynthesizeAudioAsync(string text)
    {
        var config = SpeechConfig.FromSubscription(_serviceSettings.ApiKey, _serviceSettings.Region);

        // Create a MemoryStream to capture the audio data
        var pullAudioStream = new PullAudioOutputStream();
        var audioConfig = AudioConfig.FromStreamOutput(pullAudioStream);

        using var synthesizer = new SpeechSynthesizer(config, audioConfig);
        using var result = await synthesizer.SpeakTextAsync(text);

        if (result.Reason == ResultReason.SynthesizingAudioCompleted)
        {
            return result.AudioData;
        }
        else
        {
            throw new Exception($"Speech synthesis failed: {result.Reason}");
        }
    }

    private async Task HandleTranslationsAsync(string? sourceLanguage, IReadOnlyDictionary<string, string> translations,
        WebSocket webSocket)
    {
        var tasks = translations.Select(async element =>
        {
            Console.WriteLine($"TRANSLATING into '{element.Key}': {element.Value}");
            if (element.Key != sourceLanguage)
            {
                var translatedAudio = await SynthesizeAudioAsync(element.Value);
                var message = new
                {
                    TranslateLanguage = element.Key,
                    TranslatedText = element.Value,
                    TranslatedAudio = translatedAudio
                };
                var messageBytes = JsonSerializer.SerializeToUtf8Bytes(message);
                await webSocket.SendAsync(new ArraySegment<byte>(messageBytes), WebSocketMessageType.Text, true,
                    CancellationToken.None);
            }
        });

        await Task.WhenAll(tasks);
    }
}

public class WebSocketAudioInput(WebSocket webSocket) : PullAudioInputStreamCallback
{
    private readonly byte[] _buffer = new byte[1024 * 4];

    public override int Read(byte[] dataBuffer, uint size)
    {
        try
        {
            var result = webSocket.ReceiveAsync(new ArraySegment<byte>(_buffer), CancellationToken.None).Result;
            if (result.MessageType == WebSocketMessageType.Close)
            {
                Console.WriteLine("WebSocket closed during read.");
                return 0;
            }

            var bytesToCopy = Math.Min(result.Count, (int)size);
            Array.Copy(_buffer, dataBuffer, bytesToCopy);


            Console.WriteLine($"Read {bytesToCopy} bytes from WebSocket.");
            return bytesToCopy;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"WebSocket read error: {ex.Message}");
            return 0;
        }
    }
}
Leave a Comment