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,服务端会拒绝 tokenapi_key 查询参数。正式浏览器产品不得把长期 API 密钥下发给浏览器。

快速接入:简单模式

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

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

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

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

客户端事件包括 authstartinputtextflushstopping。简单模式通常只使用 startinputtextflushstop 属于可靠模式。

客户端事件入参

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

事件适用模式必填字段可选字段与默认值约束与行为
auth选择模式前eventtokenevent_id仅在握手没有携带 Authorization 时使用;token 是一次性浏览器票据。
start简单、可靠eventrequestmode: "simple"event_idrequest_idretry_failed可靠模式必须提供 event_idrequest_idretry_failed: true 仅限可靠模式。
input简单eventtextevent_idcommit: truetext 不得为空;整个缓冲请求最多 10,000 个字符。
text可靠eventevent_idsequencetextsequence 是正整数且必须等于服务端期待的下一个值;每帧最多 2,000 个字符。
flush可靠eventevent_idsegment_id提交非空缓冲区;segment_id 是该分段唯一的 1–128 字符幂等键。
stop可靠eventevent_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
formatGET /v2/tts/capabilities 返回的格式
speed0.52 的数字
volume旧 v2 为 010product_v1-2020
stabilityproduct_v1 稳定性;数值越高越稳定
similarityproduct_v1 音色相似度
pitchproduct_v1 音高;仅模型支持时生效
language1–32 个字符的语言提示
chunk_length501000 的整数
latency仅在所选供应商和模型的能力列表中存在时可用
emotion仅在所选供应商和模型的能力列表中存在时可用
instructions仅在所选供应商和模型的能力列表中存在时可用
optimize_instructions仅在所选供应商和模型的能力列表中存在时可用
text_normalizationproduct_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_idsiteprotocol_versionquota
readymoderequest_idsession_idprovidermodelvoice_idformat、PCM 元数据
input_ackrequest_id、已接收的 sequence 和字符数、当前缓冲字符数、剩余容量
segment_acceptedrequest_idsegment_id、分段字符数和预留计费单位
audiorequest_idsession_idsegment_id、递增的 sequence、二进制 audioformat、PCM 元数据
usagerequest_idsegment_idsegment_unitssession_unitsquota_remainingaudio_bytes
segment_completedrequest_idsegment_id、分段计费单位、音频字节数
request_status重复请求的 stateretryableunitsresult_available;不会重新生成
warningrequest_id?codemessage
errorrequest_id?session_id?、稳定的 codemessageretryableterminalstage?path?
finishrequest_idsession_idreasonunits;终态原因为 completederrortimeoutserver_draining
pongsession_idrequest_id?timestamp

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

错误码

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

类别错误码
鉴权authentication_failedauthentication_requiredalready_authenticatedpermission_denied
消息状态invalid_messageinvalid_messagepackinvalid_stateidempotency_conflictempty_segmentsegment_too_large
限制session_limit_exceededquota_exceededclient_backpressure
能力unsupported_parametervoice_not_foundmodel_not_found
供应商provider_unavailableprovider_timeoutgeneration_failed
生命周期billing_failedconnection_closedinternal_error

能力与请求状态

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

可靠模式客户端在网络中断后可查询 GET /v2/tts/requests/{request_id}。返回状态为 runningcompletedfailed_retryablefailed_terminalresult_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: trueinput 形成一个计费分段并自动结束。可靠模式中,每个非空 flush 形成独立计费分段,客户端应等待 input_acksegment_completed 后再继续。服务端在调用供应商前预留额度,在第一块有效音频交付时提交计费。

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

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

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