Fish Audio 文档
API 文档文字转语音实时文字转语音

实时文字转语音 v2

通过公开的 Realtime TTS WebSocket v2 协议流式生成语音。

Realtime TTS v2 仅为现有客户端保留;新接入请使用上级 v3 页面。默认简单模式只需发送一次输入;需要显式顺序、幂等和断线恢复时再启用可靠模式。

接口与子协议

品牌接口地址
Fish Audiowss://realtime.fishaudio.org/v2/tts/live

连接必须声明 WebSocket 子协议 realtime.tts.msgpack.v2。客户端和服务端的应用层消息均为 MessagePack 二进制帧,不是 JSON 文本帧。

现有 /v1/tts/live 接入仍继续提供兼容服务,但 v1 已冻结。新接入应使用上级 v3 协议;本页仅用于维护 v2 客户端。

站点能力

站点供应商标准模型格式
Fish AudioFishAudiofishaudio-s21pro-flashmp3, wav, opus

公开 voice_id 必须支持所选 model。建连前可通过 GET /v2/tts/capabilities 获取当前站点支持的供应商、模型、格式、参数及 PCM 元数据。超出当前站点能力矩阵的组合会被明确拒绝。

鉴权

服务端应用应在 WebSocket 握手阶段传递 API 密钥:

Authorization: Bearer API_KEY
Sec-WebSocket-Protocol: realtime.tts.msgpack.v2

浏览器原生 WebSocket API 无法设置 Authorization 请求头。可信服务端可用 API Key 换取绑定 Origin 的一次性票据:

POST /v2/tts/browser-tickets
Authorization: Bearer API_KEY
Content-Type: application/json

{"origin":"https://your-app.example"}

浏览器再使用 v2 子协议连接,并把返回票据编码成首个 MessagePack 帧:

{ event: 'auth', token: 'rtv2_ticket_...' }

必须在鉴权超时前发送。票据只能使用一次、短期有效,并绑定站点、Host 与 Origin。不要把凭证放入 URL,服务端会拒绝 token 和 api_key 查询参数。正式浏览器产品不得把长期 API 密钥下发给浏览器。

快速接入:简单模式

连接 → authenticated → start → ready → input → audio(一个或多个)→ finish

省略 start.mode 即使用简单模式。服务端生成请求、事件、顺序和分段 ID。收到 ready 后发送一次 { event: 'input', text };默认 commit: true,生成完成后自动结束。客户端只需处理 ready、audio、error、finish,确认和用量事件可以忽略。

{ event: 'start', request: { voice_id: '公开音色 UUID', model: 'fishaudio-s21pro-flash', format: 'mp3' } }
{ event: 'input', text: '你好,这是 Realtime TTS v2。' }

需要分多帧提交文本时,可先发送多个 commit: false 的 input,最后发送一次 commit: true。一个 WebSocket 连接只承载一次生成请求。

客户端事件包括 auth、start、input、text、flush、stop、ping。简单模式通常只使用 start 和 input;text、flush、stop 属于可靠模式。

客户端事件入参

所有客户端事件都是 MessagePack Map。未知字段会被拒绝;字段名统一使用 snake_case,文本值必须是有效的 UTF-8 字符串。

事件适用模式必填字段可选字段与默认值约束与行为
auth选择模式前event、tokenevent_id仅在握手没有携带 Authorization 时使用;token 是一次性浏览器票据。
start简单、可靠event、requestmode: "simple"、event_id、request_id、retry_failed可靠模式必须提供 event_id 和 request_id;retry_failed: true 仅限可靠模式。
input简单event、textevent_id、commit: truetext 不得为空;整个缓冲请求最多 10,000 个字符。
text可靠event、event_id、sequence、text无sequence 是正整数且必须等于服务端期待的下一个值;每帧最多 2,000 个字符。
flush可靠event、event_id、segment_id无提交非空缓冲区;segment_id 是该分段唯一的 1–128 字符幂等键。
stop可靠event、event_id无等所有已接受分段完成后结束本次请求。
ping简单、可靠event;可靠模式还需 event_id简单模式可带 event_id,并可带 timestamp鉴权完成后可发送,服务端返回 pong。

event 必须等于第一列中的事件名。可靠模式从 start 开始的每个客户端事件都必须使用唯一 event_id。简单模式中的请求、事件、顺序和分段 ID 由服务端生成,客户端无需回传。

可靠模式

需要显式多分段控制和断线恢复时,发送 { event: 'start', mode: 'reliable', event_id, request_id, request }。可靠模式从 start 开始要求每个客户端事件携带唯一 event_id,每个 text 携带严格递增的 sequence,每个 flush 携带唯一 segment_id。

start → ready → text → input_ack → flush → segment_accepted
      → audio → usage → segment_completed → stop → finish

request_id 长度为 1–128 个字符,是账号、站点和域名范围内的幂等键。重复提交相同请求返回 request_status,不会再次调用供应商或重复扣费。

start.request 入参

字段必填类型与约束
parameter_profile否省略时保持旧 v2;设为 product_v1 启用统一产品参数
voice_id是音色目录返回的公开音色 UUID
model是公共模型 ID;当前默认模型为 fishaudio-s21pro-flash
format否GET /v2/tts/capabilities 返回的格式
speed否0.5 到 2 的数字
volume否旧 v2 为 0 到 10;product_v1 为 -20 到 20
stability否product_v1 稳定性;数值越高越稳定
similarity否product_v1 音色相似度
pitch否product_v1 音高;仅模型支持时生效
language否1–32 个字符的语言提示
chunk_length否50 到 1000 的整数
latency否仅在所选供应商和模型的能力列表中存在时可用
emotion否仅在所选供应商和模型的能力列表中存在时可用
instructions否仅在所选供应商和模型的能力列表中存在时可用
optimize_instructions否仅在所选供应商和模型的能力列表中存在时可用
text_normalization否product_v1 文本归一化开关;仅模型支持时生效

默认 profile 保持旧 v2 的严格行为。使用 parameter_profile: "product_v1" 时,服务端会把支持的参数限制到模型范围,忽略模型不支持的参数,并通过 ready.effective_request 返回最终生效值。

示例:

{
  event: 'start',
  request: {
    voice_id: '00000000-0000-0000-0000-000000000000',
    model: 'fishaudio-s21pro-flash',
    parameter_profile: 'product_v1',
    format: 'mp3',
    speed: 1,
    volume: 0,
    stability: 1,
    similarity: 1,
    text_normalization: true,
    language: 'zh',
    chunk_length: 200,
    latency: 'normal'
  }
}

服务端事件

每个服务端事件都包含唯一 event_id、链路 trace_id 和 Unix 毫秒 timestamp。直接响应客户端事件时还包含 in_reply_to。

事件主要字段
authenticatedsession_id、site、protocol_version、quota
readymode、request_id、session_id、provider、model、voice_id、format、PCM 元数据
input_ackrequest_id、已接收的 sequence 和字符数、当前缓冲字符数、剩余容量
segment_acceptedrequest_id、segment_id、分段字符数和预留计费单位
audiorequest_id、session_id、segment_id、递增的 sequence、二进制 audio、format、PCM 元数据
usagerequest_id、segment_id、segment_units、session_units、quota_remaining、audio_bytes
segment_completedrequest_id、segment_id、分段计费单位、音频字节数
request_status重复请求的 state、retryable、units、result_available;不会重新生成
warningrequest_id?、code、message
errorrequest_id?、session_id?、稳定的 code、message、retryable、terminal、stage?、path?
finishrequest_id、session_id、reason、units;终态原因为 completed、error、timeout 或 server_draining
pongsession_id、request_id?、timestamp

audio.audio 是 MessagePack 帧内的二进制字节数组,不是 Base64。客户端应按照 sequence 顺序拼接所选输出格式的音频帧。当 format 为 pcm 时,ready 和 audio 都会携带必需的 sample_rate、channels 和 bit_depth,客户端可以据此生成 WAV 文件头或初始化 PCM 播放器。

错误码

每个 error 事件都有稳定的 code、安全的 message、retryable 和 terminal。terminal: false 表示客户端可修正后继续当前连接;terminal: true 表示本会话终止。stage 和 path 用于定位失败阶段与字段。当前错误码如下:

类别错误码
鉴权authentication_failed、authentication_required、already_authenticated、permission_denied
消息状态invalid_message、invalid_messagepack、invalid_state、idempotency_conflict、empty_segment、segment_too_large
限制session_limit_exceeded、quota_exceeded、client_backpressure
能力unsupported_parameter、voice_not_found、model_not_found
供应商provider_unavailable、provider_timeout、generation_failed
生命周期billing_failed、connection_closed、internal_error

能力与请求状态

客户端可以在建连前读取 GET /v2/tts/capabilities,按站点返回可用供应商、模型、格式、参数、限制以及 simple、reliable 两种模式。

可靠模式客户端在网络中断后可查询 GET /v2/tts/requests/{request_id}。返回状态为 running、completed、failed_retryable 或 failed_terminal。result_available=true 时响应包含 segments 清单。

要重新执行 failed_retryable 请求,重新连接后在 start 中复用同一 request_id 并设置 retry_failed: true。每个重试分段必须复用相同 segment_id、顺序和完整文本,否则返回 idempotency_conflict。

Node.js 最小示例

安装 ws 和 @msgpack/msgpack:

import { writeFileSync } from 'node:fs';
import { decode, encode } from '@msgpack/msgpack';
import WebSocket from 'ws';

const audio = [];
const ws = new WebSocket('wss://realtime.fishaudio.org/v2/tts/live', 'realtime.tts.msgpack.v2', {
  headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});

ws.on('message', (frame) => {
  const event = decode(frame);
  if (event.event === 'authenticated') {
    ws.send(
      encode({
        event: 'start',
        request: {
          voice_id: process.env.VOICE_ID,
          model: 'fishaudio-s21pro-flash',
          format: 'mp3',
        },
      }),
    );
  } else if (event.event === 'ready') {
    ws.send(encode({ event: 'input', text: '你好,这是 Realtime TTS v2。' }));
  } else if (event.event === 'audio') {
    audio.push(event.audio);
  } else if (event.event === 'error') {
    console.error(event.code, event.message, event.retryable, event.terminal, event.trace_id);
  } else if (event.event === 'finish') {
    writeFileSync('realtime-output.mp3', Buffer.concat(audio.map((chunk) => Buffer.from(chunk))));
    console.log({ requestId: event.request_id, units: event.units });
    ws.close(1000);
  }
});

限制、计费与重试

简单模式中,commit: true 的 input 形成一个计费分段并自动结束。可靠模式中,每个非空 flush 形成独立计费分段,客户端应等待 input_ack 和 segment_completed 后再继续。服务端在调用供应商前预留额度,在第一块有效音频交付时提交计费。

协议默认限制为:简单模式每次输入最多 10,000 字符;可靠模式每个 text 最多 2,000 字符、每个分段最多 10,000 字符;每个会话最多 100,000 计费单位。

只有 retryable: true 的错误或 WebSocket 关闭码 1012、1013 可以自动重试,并应使用带随机抖动的指数退避。只有用户明确发起一次新生成时才创建新的 request_id,不要通过更换 ID 绕过重复保护来重放状态不确定的请求。

握手失败会在 101 Switching Protocols 之前以 HTTP 响应返回;会话内失败通过 MessagePack error 事件返回,随后关闭连接。