unity web连接阿里云语音合成大模型 通过Newtonsoft.Json解析,最后返回的MP3格式文件存储到项目文件夹下

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.WebSockets;
using System.Threading.Tasks;
using System.Threading;
using UnityEngine;

public class Program : MonoBehaviour
{
    public string ApiKey = "your_api_key";

    // WebSocket服务器地址
    private const string WebSocketUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference/";
    // 输出文件路径
    private const string OutputFilePath = "output.mp3";

    // WebSocket客户端
    private ClientWebSocket _webSocket = new ClientWebSocket();
    // 取消令牌源
    private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    // 任务ID
    private string _taskId;
    // 任务是否已启动
    private TaskCompletionSource<bool> _taskStartedTcs = new TaskCompletionSource<bool>();

    void Start()
    {
        // 启动异步任务
        StartCoroutine(RunWebSocketTask());
    }

    private IEnumerator RunWebSocketTask()
    {
        // 将Main方法的逻辑移到这里
        Task task = RunAsync();
        yield return new WaitUntil(() => task.IsCompleted);
    }

    private async Task RunAsync()
    {
        try
        {
            // 清空输出文件
            ClearOutputFile(OutputFilePath);

            // 连接WebSocket服务
            await ConnectToWebSocketAsync(WebSocketUrl);

            // 启动接收消息的任务
            Task receiveTask = ReceiveMessagesAsync();

            // 发送run-task指令
            _taskId = GenerateTaskId();
            await SendRunTaskCommandAsync(_taskId);

            // 等待task-started事件
            await _taskStartedTcs.Task;

            // 持续发送continue-task指令
            string[] texts = {
                "床前明月光",
                "疑是地上霜",
                "举头望明月",
                "低头思故乡"
            };
            foreach (string text in texts)
            {
                await SendContinueTaskCommandAsync(text);
            }

            // 发送finish-task指令
            await SendFinishTaskCommandAsync(_taskId);

            // 等待接收任务完成
            await receiveTask;

            Debug.Log("任务完成,连接已关闭。");
        }
        catch (OperationCanceledException)
        {
            Debug.Log("任务被取消。");
        }
        catch (Exception ex)
        {
            Debug.Log($"发生错误:{ex.Message}");
        }
        finally
        {
            _cancellationTokenSource.Cancel();
            _webSocket.Dispose();
        }
    }

    private void ClearOutputFile(string filePath)
    {
        if (File.Exists(filePath))
        {
            File.WriteAllText(filePath, string.Empty);
            Debug.Log("输出文件已清空。");
        }
        else
        {
            Debug.Log("输出文件不存在,无需清空。");
        }
    }

    private async Task ConnectToWebSocketAsync(string url)
    {
        var uri = new Uri(url);
        if (_webSocket.State == WebSocketState.Connecting || _webSocket.State == WebSocketState.Open)
        {
            return;
        }

        // 设置WebSocket连接的头部信息
        _webSocket.Options.SetRequestHeader("Authorization", $"bearer {ApiKey}");
        _webSocket.Options.SetRequestHeader("X-DashScope-DataInspection", "enable");

        try
        {
            await _webSocket.ConnectAsync(uri, _cancellationTokenSource.Token);
            Debug.Log("已成功连接到WebSocket服务。");
        }
        catch (OperationCanceledException)
        {
            Debug.Log("WebSocket连接被取消。");
        }
        catch (Exception ex)
        {
            Debug.Log($"WebSocket连接失败: {ex.Message}");
            throw;
        }
    }

    private async Task SendRunTaskCommandAsync(string taskId)
    {
        var command = CreateCommand("run-task", taskId, "duplex", new
        {
            task_group = "audio",
            task = "tts",
            function = "SpeechSynthesizer",
            model = "cosyvoice-v1",
            parameters = new
            {
                text_type = "PlainText",
                voice = "longxiaochun",
                format = "mp3",
                sample_rate = 22050,
                volume = 50,
                rate = 1,
                pitch = 1
            },
            input = new { }
        });

        await SendJsonMessageAsync(command);
        Debug.Log("已发送run-task指令。");
    }

    private async Task SendContinueTaskCommandAsync(string text)
    {
        if (_taskId == null)
        {
            throw new InvalidOperationException("任务ID未初始化。");
        }

        var command = CreateCommand("continue-task", _taskId, "duplex", new
        {
            input = new
            {
                text
            }
        });

        await SendJsonMessageAsync(command);
        Debug.Log("已发送continue-task指令。");
    }

    private async Task SendFinishTaskCommandAsync(string taskId)
    {
        var command = CreateCommand("finish-task", taskId, "duplex", new
        {
            input = new { }
        });

        await SendJsonMessageAsync(command);
        Debug.Log("已发送finish-task指令。");
    }

    private async Task SendJsonMessageAsync(string message)
    {
        var buffer = Encoding.UTF8.GetBytes(message);
        try
        {
            await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("消息发送被取消。");
        }
    }

    private async Task ReceiveMessagesAsync()
    {
        while (_webSocket.State == WebSocketState.Open)
        {
            var response = await ReceiveMessageAsync();
            if (response != null)
            {
                string eventStr = response["header"]["event"].ToString();
                switch (eventStr)
                {
                    case "task-started":
                        Debug.Log("任务已启动。");
                        _taskStartedTcs.TrySetResult(true);
                        break;
                    case "task-finished":
                        Debug.Log("任务已完成。");
                        _cancellationTokenSource.Cancel();
                        break;
                    case "task-failed":
                        Debug.Log("任务失败。");
                        _cancellationTokenSource.Cancel();
                        break;
                    default:
                        // result-generated可在此处理
                        break;
                }
            }
        }
    }

    private async Task<JObject> ReceiveMessageAsync()
    {
        var buffer = new byte[1024 * 4];
        var segment = new ArraySegment<byte>(buffer);

        try
        {
            WebSocketReceiveResult result = await _webSocket.ReceiveAsync(segment, _cancellationTokenSource.Token);

            if (result.MessageType == WebSocketMessageType.Close)
            {
                await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", _cancellationTokenSource.Token);
                return null;
            }

            if (result.MessageType == WebSocketMessageType.Binary)
            {
                // 处理二进制数据
                Debug.Log("接收到二进制数据...");

                // 将二进制数据保存到文件
                using (var fileStream = new FileStream(OutputFilePath, FileMode.Append))
                {
                    fileStream.Write(buffer, 0, result.Count);
                }

                return null;
            }

            string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
            return JObject.Parse(message);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("消息接收被取消。");
            return null;
        }
    }

    private static string GenerateTaskId()
    {
        return Guid.NewGuid().ToString("N").Substring(0, 32);
    }

    private static string CreateCommand(string action, string taskId, string streaming, object payload)
    {
        var command = new
        {
            header = new
            {
                action,
                task_id = taskId,
                streaming
            },
            payload
        };

        return JsonConvert.SerializeObject(command);
    }
}

更多推荐