使用WebSocket协议进行调用

本文介绍如何通过WebSocket协议,使用CosyVoice大模型进行语音合成。当您不希望引入百炼SDK,或者当目前提供的SDK无法满足您的要求时,您可以参照本文档,自行开发代码访问百炼语音服务。

WebSocket是一种在单个TCP连接上进行全双工通信的协议。它让客户端和服务端之间的数据交换变得更加简单,客户端和服务端只需通过一次握手就可建立永久性连接,并进行双向数据传输。

通过WebSocket协议使用CosyVoice大模型进行语音合成有以下几个简要步骤:

  1. 拿到WebSocket服务URL地址

  2. 鉴权并建立连接

  3. 进行数据交互

  4. 断开连接

本文将对上述步骤中涉及到的一些概念(WebSocket交互流程、指令、事件)和信息(WebSocketURL、鉴权细节)等分别进行详细的介绍。

前提条件

已开通服务并获得api-key:获取API Key

WebSocket交互流程

客户端和服务端的交互流程,按照时间顺序可分为三个阶段,关于指令(例如:【run-task】)和事件(例如:【task-started】)的详细介绍,请分别参见客户端指令服务端事件

  1. 建立连接阶段(一次握手):客户端与服务端建立连接。客户端发送【run-task】指令,服务端返回响应事件【task-started】以确认建立连接成功,正式开启TTS语音合成服务。

  2. 循环调用阶段:客户端循环发送【continue-task】指令,向服务端发送待合成的文本流;同时,服务端返回合成好的音频数据。

  3. 断开连接阶段:文本发送完毕后,客户端发送【finish-task】指令,服务端待所有合成好的音频数据发送完毕后返回响应事件【task-finished】,然后客户端断开连接。

image

WebSocket服务URL

wss://dashscope.aliyuncs.com/api-ws/v1/inference

鉴权

只支持在建立连接阶段,通过Headers中携带API Key进行鉴权。配置好鉴权信息后您可以确认下是否能和WebSocket服务建立连接。

{
    "Authorization": "bearer <your-dashscope-api-key>", // 将<your-dashscope-api-key>替换成您自己的API-KEY
    "user-agent": "your-platform-info", //可选
    "X-DashScope-WorkSpace": workspace, // 可选
    "X-DashScope-DataInspection":"enable"
}

客户端指令

指令用于控制语音合成任务的起止,标识任务边界。客户端以JSON格式的Text Frame方式向服务端发送请求。

指令由headerpayload两部分组成:

  • header:包含指令的基础信息。所有指令的header格式统一。

    header参数:

    参数

    类型

    是否必选

    说明

    header

    请求头

    -

    -

    header.action

    String

    指令类型,可以选填:

    • "run-task"

    • "continue-task"

    • "finish-task"

    用法参见下文。

    header.task_id

    String

    当次任务ID,随机生成32位唯一ID。

    header.streaming

    String

    固定字符串:"duplex"。

    说明

    task_id是用于区分不同任务唯一性的字段,为32通用唯一识别码(UUID),由32个随机生成的字母和数字构成。您可以使用带横线'-'分隔的UUID,也可以使用不包含横线的UUID。

    有横线类型:"2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx"

    无横线类型:"2bf83b9abaeb4fda8d9axxxxxxxxxxxx"

    绝大部分编程语言都内置有生成UUIDAPI,以python为例:

    import uuid
    
    
    def generateTaskId(self):
        # 生成随机UUID
        return uuid.uuid4().hex
    

    header请求头示例如下

    {
        "header": {
            "action": "run-task",
            "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // 随机uuid
            "streaming": "duplex"
        }
    }

  • payload:包含基础信息外的其他信息如模型名、发音人等。不同指令的payload格式各不相同。

各指令如下:

run-task指令:开启语音合成任务

该指令用于开启语音合成任务。

run-task指令的payload参数:

参数

类型

是否必选

说明

payload.task_group

String

固定字符串:"audio"。

payload.task

String

固定字符串:"tts"。

payload.function

String

固定字符串:"SpeechSynthesizer"。

payload.model

String

模型名称:"cosyvoice-v1"。

payload.input

Object

固定格式:{}。

payload.parameters

text_type

String

固定字符串:“PlainText”。

voice

String

发音人。

format

String

音频编码格式,支持"pcm"、"wav"和"mp3"。

sample_rate

Integer

音频采样率,支持下述采样率:

8000, 16000, 22050, 24000, 44100, 48000。

volume

Integer

音量,取值范围:0~100。默认值:50。

rate

Float

合成音频的语速,取值范围:0.5~2。

  • 0.5:表示默认语速的0.5倍速。

  • 1:表示默认语速。默认语速是指模型默认输出的合成语速,语速会依据每一个发音人略有不同,约每秒钟4个字。

  • 2:表示默认语速的2倍速。

默认值:1.0。

pitch

Float

合成音频的语调,取值范围:0.5~2。

默认值:1.0。

run-task指令示例如下:

{
    "header": {
        "action": "run-task",
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // 随机uuid
        "streaming": "duplex"
    },
    "payload": {
        "task_group": "audio",
        "task": "tts",
        "function": "SpeechSynthesizer",
        "model": "cosyvoice-v1",
        "parameters": {
            "text_type": "PlainText",
            "voice": "longxiaochun",            // 音色
            "format": "mp3",		        // 音频格式
            "sample_rate": 22050,	        // 采样率
            "volume": 50,			// 音量
            "rate": 1,				// 语速
            "pitch": 1				// 音调
        },
        "input": {}
    }
}

continue-task指令:发送待合成文本

该指令用于发送待合成的文本片段。文本可以在一次任务中分成片段按顺序多次通过该指令进行发送。

continue-task指令的payload参数:

参数

类型

是否必选

说明

payload.task_group

String

固定字符串:"audio"。

payload.task

String

固定字符串:"tts"。

payload.function

String

固定字符串:"SpeechSynthesizer"。

payload.model

String

模型名称:"cosyvoice-v1"。

input.text

String

需要合成的文本片段。

continue-task指令示例如下:

{
    "header": {
        "action": "continue-task",
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // 随机uuid
        "streaming": "duplex"
    },
    "payload": {
        "task_group": "audio",
        "task": "tts",
        "function": "SpeechSynthesizer",
        "model": "cosyvoice-v1",
        "input": {
            "text": "待合成的文本"
        }
    }
}

finish-task指令:结束语音合成任务

该指令用于结束语音合成任务。

finish-task指令的payload参数:

参数

类型

是否必选

说明

payload.input

Object

固定格式:{}。

finish-task指令示例如下

{
    "header": {
        "action": "finish-task",
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx", // 随机uuid
        "streaming": "duplex"
    },
    "payload": {
        "input": {}
    }
}

服务端事件

事件指的是服务端返回给客户端的处理进度事件,代表不同的处理阶段,客户端可获取不同处理阶段的事件实现不同的业务逻辑。以JSON格式返回。

事件由headerpayload两部分组成:

  • header:包含事件的基础信息。除task-failed事件外,所有事件的header格式统一。

    header参数:

    参数

    类型

    说明

    header

    请求头

    -

    header.event

    String

    事件类型

    • task-started

    • result-generated

    • task-finished

    • task-failed

    详细说明参见下文。

    header.task_id

    String

    客户端生成的task_id。

    header请求头示例如下:

    {
        "header": {
            "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
            "event": "task-started",
            "attributes": {}
        }
    }
  • payload:包含基础信息外的其他信息。不同事件的payload格式可能不同。

各事件如下:

task-started事件:语音合成任务已开启

客户端发送start-task指令成功之后,服务端会返回task-started事件,客户端收到task-started事件之后才可以开始发送文本指令(continue-task)和结束任务指令(finish-task)。

task-started事件的payload没有内容。

task-started事件示例如下:

{
    "header": {
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
        "event": "task-started",
        "attributes": {}
    },
    "payload": {}
}

result-generated事件(现阶段忽略)

CosyVoice服务中,result-generated事件为协议预留接口,现阶段在集成时可以忽略该事件。

task-finished事件:语音合成任务已结束

客户端发送finish-task指令后,服务端在所有合成好的音频数据发送完毕后返回响应事件task-finished,然后客户端断开连接。

task-finished事件的payload参数:

参数

类型

说明

payload.usage.characters

Integer

本次请求中计费的有效字符数。

task-finished事件示例如下:

{
    "header": {
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
        "event": "task-finished",
        "attributes": {
            "x-ds-batch-queue-length": "0",
            "request_uuid": "0a9dba9e-d3a6-45a4-be6d-xxxxxxxxxxxx",
            "x-ds-batch-enqueue-time": "1727436802878"
        }
    },
    "payload": {
        "output": {
            "sentence": {
                "words": []
            }
        },
        "usage": {
            "characters": 13
        }
    }
}

task-failed事件:任务失败

如果合成任务失败会下发task-failed事件。客户端收到该事件后结束连接并处理报错。

task-failed事件的header参数:

参数

类型

说明

header.error_code

String

报错类型描述。

header.error_message

String

具体报错原因。

task-failed事件示例如下:

{
    "header": {
        "task_id": "2bf83b9a-baeb-4fda-8d9a-xxxxxxxxxxxx",
        "event": "task-failed",
        "error_code": "InvalidParameter",
        "error_message": "[tts:]Engine return error code: 418",
        "attributes": {}
    },
    "payload": {}
}

下发音频流

CosyVoice语音合成中,音频会通过binary通道按照数据流的方式分帧下发。下发的所有音频为一个完整的音频文件,可以通过支持流式播放的播放器实时播放。

支持流式播放的播放器:ffmpeg、pyaudio (Python)、AudioFormat (Java)、MediaSource (Javascript)等。
重要
  • 客户端从第一次通过continue-task指令发送文本开始,到收到task-finished事件之间会收到音频流。

  • 在流式语音合成中,是将一个完整的音频文件分多次返回。在播放流式音频时,需要使用支持流式播放的音频播放器,而不是将每一帧当作一个独立的音频播放,这样无法成功解码。

  • 在保存音频时,请使用追加模式写入同一个文件。

  • 在使用wav/mp3格式合成音频时,由于文件按照流式合成,因此只在第一帧中包含当前任务的文件头信息。