Doubao TTS (TTS + Podcast + ASR)
Resumen
Doubao / Volcengine (豆包语音) es ampliamente reconocido como la mejor IA de voz en chino y es el proveedor de calidad predeterminado para el pipeline de escritura de Liz. Prefiere 火山引擎豆包 sobre alternativas genéricas de TTS a menos que esté bloqueado.
Este skill cubre tres productos de 豆包语音: TTS (texto→voz para audio de artículos), Podcast (conversación AI de dos hablantes) y ASR (voz→texto con diarización opcional). En la nueva consola, una sola clave API autentica estos servicios a través de X-Api-Key. Los endpoints y los ID de recursos aún difieren por producto.
ElevenLabs tiene una API HTTP más limpia pero una calidad de voz/modelo preferido más débil para este flujo de trabajo: solo como recurso de último recurso (elevenlabs-tts). No lo elijas por conveniencia.
Configuración inicial (nueva consola — preferida)
No comiences en la consola antigua para nuevas configuraciones: es más difícil de navegar. Usa la nueva consola de 豆包语音:
- Abre la 火山引擎豆包语音新版控制台.
- Recarga / activa los productos de voz que necesites (TTS, ASR, Podcast, etc.).
- Crea o copia una sola Clave API desde la gestión de claves API de la nueva consola.
- Guárdala como
DOUBAO_API_KEY(canónica) en la ruta de secretos del perfil de escritura a continuación. Los aliasDOUBAO_SPEECH_API_KEY/ heredadoDOUBAO_TTS2_API_KEYson aceptados. - Entrega la clave al agente. Si la autenticación o el enrutamiento de productos no está claro, también entrega el 豆包语音产品简介 / 能力总览文档 (o la página API relevante de Referencias / 参考文献).
Una clave, muchos servicios: Después de recargar en la nueva consola, esa Clave API es la credencial para TTS, ASR (voz→texto), generación de Podcast y otras llamadas relacionadas de 豆包语音 que acepten X-Api-Key. Ya no necesitas un par separado de App ID + Access Token para flujos de trabajo de la nueva consola.
Los scripts incluidos existentes (tts-generate.py, podcast-generate.py, asr-transcribe.py) aún leen las variables de entorno heredadas de App ID / Access Token y las formas de encabezado de la consola antigua. Mantén esas variables pobladas hasta que los scripts se migren; para nuevo código de agente, prefiere DOUBAO_API_KEY + X-Api-Key.
Cuándo usar
- TTS: Liz pide convertir un proyecto de escritura,
final.md, ensayo o publicación de lizliz.xyz en audio hablado (豆包 / 火山引擎 / ByteDance TTS). - Podcast: Liz pide convertir un artículo, TXT, URL o tema en un podcast AI de dos hablantes (豆包语音播客大模型). Producto separado: actívalo a través de la nueva consola (el enlace de activación heredado también se enumera en Referencias).
- ASR: Liz pide transcribir MP3 / WAV / OGG / nota de voz / audio de video a texto textual (prefiere Flash ASR).
- Depuración de voces de Doubao, payloads, ubicación de audio en artículos, enlaces de audio de lizliz.xyz o calidad de ASR.
No usar para:
- Generación con ElevenLabs como primera opción →
elevenlabs-tts - Etiquetado de música / separación de fuentes / MIDI / detección de ritmo → líneas de producto separadas SAMI / 智能K歌 (ver
references/volcengine-audio-ecosystem.md) - Agentes de voz S2S en tiempo real → 端到端实时语音大模型 (fuera de alcance; ver Referencias)
Reglas principales
- No leer Markdown en voz alta. Elimina YAML, marcadores de encabezados, énfasis, notas al pie, barras de tablas, HRs, URLs sin procesar, imágenes, bloques de código a menos que el contenido en sí deba ser hablado.
- No narrar Referencias / Notas al pie por defecto. Detente antes de
References/参考资料/Footnotes/脚注/Sources/引用. Audio de apéndices de fuentes solo si Liz lo pide. - Mantén la voz del artículo. Preserva la puntuación del chino, los saltos de párrafo, las comillas y los términos técnicos en inglés.
- Salta las pruebas de voz múltiples cuando Liz ya haya elegido la predeterminada.
- Voz predeterminada:
zh_female_vv_uranus_bigtts(Vivi2.0) a menos que Liz elija otra o la cuota lo bloquee. - Ruta TTS de producción: V1 verificado
https://openspeech.bytedance.com/api/v1/ttsconcluster: volcano_tts. V3 streaming es la ruta de migración/tiempo real, no la predeterminada para artículos. - Prefiere
DOUBAO_API_KEYde la nueva consola para trabajo nuevo; mantén el App ID / Access Token heredado solo para scripts existentes o payloads V1 Bearer hasta que se migren. - ElevenLabs solo como último recurso — fallo de cuota/autenticación/plataforma, o solicitud explícita. Mantén el proveedor visible en nombres de archivos/manifiestos.
- Comienza desde este skill cuando Liz mencione Doubao TTS / audio de artículo (
skill_view/ registro) — no hagas una búsqueda amplia de notas enterradas primero.
Contrato de entorno
Los secretos se quedan fuera de este archivo. Solo registra nombres de variables y rutas.
Secretos canónicos + enlaces simbólicos:
/home/ubuntu/.hermes/secrets/doubao-tts.env
/home/ubuntu/.hermes/secrets/elevenlabs.env
/home/ubuntu/.hermes/profiles/writing/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
/home/ubuntu/.hermes/profiles/trading/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
/home/ubuntu/.hermes/.env.d/*.env -> /home/ubuntu/.hermes/secrets/*.env
También refleja en el .env del perfil cuando sea conveniente (los scripts más antiguos solo usan .env). Los nuevos scripts deben cargar .env y .env.d/*.env.
Directorio del perfil de escritura: /home/ubuntu/.hermes/profiles/writing/.env
Preferido: Clave API única (nueva consola)
DOUBAO_API_KEY=... # canónica — X-Api-Key para TTS / ASR / Podcast (nueva consola)
# alias aceptados (mismo valor):
DOUBAO_SPEECH_API_KEY=...
DOUBAO_TTS2_API_KEY=... # nombre histórico de muestras TTS 2.0; mantener como alias
Orden de resolución para nuevo código: DOUBAO_API_KEY → DOUBAO_SPEECH_API_KEY → DOUBAO_TTS2_API_KEY.
Opcional (compartido): DOUBAO_TTS_CLUSTER=volcano_tts, DOUBAO_TTS_VOICE_TYPE=zh_female_vv_uranus_bigtts.
Autenticación heredada (consola antigua) — scripts existentes / V1 HTTP
Obsoleto para nuevas configuraciones. Mantén poblado mientras tts-generate.py, podcast-generate.py y asr-transcribe.py aún los esperen.
DOUBAO_TTS_APP_ID=... # App ID de consola antigua → X-Api-App-Key / X-Api-App-Id / V1 app.appid
DOUBAO_TTS_ACCESS_TOKEN=... # Access Token antiguo → X-Api-Access-Key / V1 Authorization: Bearer; …
DOUBAO_TTS_SECRET_KEY=... # opcional; algunas variantes de SDK
Alias (compat): VOLCENGINE_TTS_*, VOLC_TTS_*.
| Ruta | Forma de autenticación |
|---|---|
| Nueva consola | Solo X-Api-Key: $DOUBAO_API_KEY (ASR Flash, TTS V3 y APIs relacionadas de la nueva consola) |
| Consola antigua / scripts actuales | X-Api-App-Key/X-Api-App-Id + X-Api-Access-Key, o V1 Authorization: Bearer; <token> + JSON app.appid/app.token |
No pongas la Clave API en el encabezado V1 Bearer; ni el Access Token en X-Api-Key de forma intercambiable: los formatos difieren.
Problema de exportación de shell: un source .env simple puede no exportar a Python hijo:
set -a; . /home/ubuntu/.hermes/profiles/writing/.env; set +a
Verificación de presencia (sin volcado de secretos):
python3 - <<'PY'
import os, re
for name in sorted(k for k in os.environ if re.search(r'(DOUBAO|VOLC|TTS)', k)):
print(f"{name}=<set>")
PY
Si ni DOUBAO_API_KEY (o sus alias) ni el App ID / Access Token heredado están configurados: detente. No recurras a Edge/OpenAI ni afirmes que se generó audio de Doubao.
TTS (文字→语音)
V1 HTTP — predeterminado de producción
Verificado como funcional para audio de artículos. La documentación oficial ahora enumera esto bajo docs históricos/小模型, pero el endpoint permanece activo y es la ruta confiable de Liz desde este servidor. Notas completas de parámetros: V1 HTTP API.
Esta ruta aún usa el heredado App ID + Access Token en el cuerpo JSON y Authorization: Bearer; <AccessToken> — no DOUBAO_API_KEY / X-Api-Key. El script incluido tts-generate.py coincide con esta forma.
POST https://openspeech.bytedance.com/api/v1/tts
Authorization: Bearer; <AccessToken>
Content-Type: application/json
(Bearer; con punto y coma es intencional: formato oficial.)
{
"app": {"appid": "APPID", "token": "TOKEN", "cluster": "volcano_tts"},
"user": {"uid": "unique_user_identifier"},
"audio": {
"voice_type": "zh_female_vv_uranus_bigtts",
"encoding": "mp3",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
},
"request": {
"reqid": "uuid",
"text": "plain text",
"text_type": "plain",
"operation": "query",
"with_frontend": 1
}
}
Éxito: code == 3000; audio en base64 data. reqid único por llamada (UUID).
Límites: Los docs oficiales de modelos pequeños citan ~1024 bytes UTF-8 por solicitud; HTTP también tiene un tiempo de espera RPC de ~60s. Para la App bigtts de Liz, el tamaño de fragmento seguro práctico es de ~1800–2000 caracteres. Fragmentos de 5000+ a menudo fallan con code:3031 / RPC timeout.
V3 / TTS 2.0 streaming — migración y tiempo real
Prefiere para tiempo real / texto en streaming; mantén V1 para audio de artículos por lotes hasta que se conecte un helper de protocolo en los scripts.
| Endpoint | Rol |
|---|---|
wss://openspeech.bytedance.com/api/v3/tts/bidirection | Flujo bidireccional (token de LLM → audio) |
wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream | Texto completo de entrada, flujo de audio de salida (WS) |
https://openspeech.bytedance.com/api/v3/tts/unidirectional | HTTP Chunked unidireccional |
https://openspeech.bytedance.com/api/v3/tts/unidirectional/sse | HTTP SSE unidireccional |
Encabezados bidireccionales (nueva consola):
X-Api-Key: $DOUBAO_API_KEY
X-Api-Resource-Id: seed-tts-2.0
X-Api-Connect-Id: <uuid>
X-Control-Require-Usage-Tokens-Return: *
(Los alias DOUBAO_SPEECH_API_KEY / DOUBAO_TTS2_API_KEY se resuelven al mismo valor de encabezado.)
IDs de recursos: seed-tts-2.0 / seed-tts-1.0 / seed-tts-1.0-concurr / seed-icl-2.0 / seed-icl-1.0 (+ concurr). Payload completo, adiciones (disable_markdown_filter, subtítulos, dialectos) y texto largo asíncrono (/api/v3/tts/submit|query) → references/tts-streaming-v3.md. Páginas oficiales: 双向流式 TTS 2.0, V3 HTTP Chunked/SSE.
Voces conocidas
Prueba las voces en la App actual en lugar de confiar ciegamente en una guía. Conjunto de comparación común:
| voice_type | Notas |
|---|---|
zh_female_vv_uranus_bigtts | Predeterminada Vivi2.0 — modelo doubao-seed-tts-2.0; no envíes emotion/neutral (ignorado) |
zh_female_xueayi_saturn_bigtts | 薛艾依 / 绘本艾依 — observada funcionando en V1 |
zh_female_wanwanxiaohe_moon_bigtts | Conflicto previo de autenticación/recurso — volver a probar después del cambio de paquete |
zh_female_shuangkuaisisi_moon_bigtts | Conflicto previo de autenticación/recurso — volver a probar después del cambio de paquete |
Valores predeterminados de Vivi: velocidad 1.0, volumen 1.0, frecuencia de muestreo 24000, formato mp3. Si es demasiado animada, prueba velocidad 0.98 después de una línea base a 1.0.
Descubre voces a través de la consola o la API OpenAPI ListSpeakers / ListBigModelTTSTimbres.
Lista de verificación de limpieza de texto
MP3 se hornea: limpia antes de sintetizar. Trabaja en memoria o /tmp; nunca modifiques el manuscrito fuente para TTS.
- Elimina el frontmatter YAML (
---\n...\n---). - Corta desde
## References/参考资料/Footnotes/脚注/Sources/引用/ Claim Check en adelante. - Elimina todo el HTML (
<a id>,<span>, etc.). La fuga se leyó como "IA Intro". - Elimina los enlaces de citas por completo:
[N](#ref-N)→ eliminar (no elNdesnudo). - Elimina MD:
#,**,*,[text](url)→text, imágenes,---, backticks,>,[^N]. - Elimina los enlaces de audio superiores (
[收听音频版...](...)). - Guarda el texto limpio en
/tmppara auditoría.
Automatizado: scripts/strip-for-tts.py.
Flujo de trabajo de audio de artículo
Directorio del skill:
SKILL_DIR="$HOME/.hermes/profiles/writing/skills/media/doubao-tts"
VENV_PY="/home/ubuntu/.hermes/hermes-agent/venv/bin/python3"
- Limpia:
python3 "$SKILL_DIR/scripts/strip-for-tts.py" <final.md> /tmp/<slug>-tts.txt - Genera (fragmento → 2 partes por debajo del límite de 25 MiB de CF):
python3 "$SKILL_DIR/scripts/tts-generate.py" /tmp/<slug>-tts.txt /tmp/<slug>-tts/ <slug>→<slug>-part1.mp3,<slug>-part2.mp3. Fusiona si el total es < 25 MiB:ffmpeg -y -i "concat:...-part1.mp3|...-part2.mp3" -c copy /tmp/<slug>-tts/<slug>.mp3 - Coloca el audio del sitio:
public/audio/articles/<slug>/<slug>.mp3(o convención del proyecto). - Enlaza cerca de la parte superior:
[收听音频版](/audio/articles/<slug>/<slug>.mp3). - Verifica tamaño, duración, enlace; empuja los repos de escritura y sitio (la acción de escritura sincroniza Markdown, no audio local arbitrario).
Borrador solo de audio (正文 no listo): final.md mínimo con frontmatter + marcador de posición + enlace de audio; copia MP3 en sitio public/audio/articles/; solo verificaciones de sincronización ligeras — no una auditoría de publicación completa.
Narración de fuente de múltiples partes: archivos de límite tts-part-N.txt; text_type: plain; un MP3 + manifiesto por segmento; ffprobe cada archivo.
Fragmentación y calidad
- Máximo ~2000 caracteres / solicitud; dividir en
\n\n. - Concatenación:
ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp3. - Agrupa en 2+ partes para el límite de 25 MiB/archivo de CF Pages.
- Prefiere la tasa de bits nativa de Doubao (~160 kbps). Mínimo para publicación: 96 kbps. Re-codifica solo si supera el límite:
ffmpeg -i in.mp3 -codec:a libmp3lame -b:a 96k -ac 1 out.mp3. Verreferences/cf-pages-size-limit.md.
Podcast (AI 播客)
Producto separado de TTS. Protocolo completo: references/podcast-api.md. Trampas de sesión: references/podcast-session-learnings.md. Publicación: references/lizliz.xyz-podcast-page.md. Protocolo WS oficial: 播客 API websocket-v3.
wss://openspeech.bytedance.com/api/v3/sami/podcasttts
Nueva consola (preferida para nuevos clientes):
X-Api-Key: $DOUBAO_API_KEY
X-Api-Resource-Id: volc.service_type.10050
X-Api-App-Key: aGjiRDfUWi # clave de producto fija (aún requerida por los docs del protocolo)
X-Api-Request-Id: <uuid>
Encabezados heredados / actuales de podcast-generate.py:
X-Api-App-Id / X-Api-Access-Key / X-Api-Resource-Id: volc.service_type.10050
X-Api-App-Key: aGjiRDfUWi # fija
message_type de trama binaria = 0b0001 (byte de encabezado1 0x14). No uses TTS bidireccional 0b0011 → "unsupported message type (3)".
| action | Modo |
|---|---|
| 0 | Texto largo / URL resumir → diálogo dual (predeterminado) |
| 3 | Sintetizar diálogo directo de nlp_texts |
| 4 | prompt_text web-search resumir |
Valores predeterminados de Liz (2026-07): action=0, mp3/24000/speech_rate=0, hablantes dayi+mizai, random_speaker deshabilitado, prompt_tags usado para control de contenido.
Flujo de trabajo de Podcast
Actualiza references/podcast-session-learnings.md para atajos de sesión y patrones de error.
ASR (语音→文字)
Flash ASR (nueva consola)
Preferido — baja latencia, buena precisión. Autenticación: X-Api-Key. Soporta diarización. Documentación oficial: Docs API Flash ASR.
Modelo grande (consola antigua)
wss://openspeech.bytedance.com/api/v2/asr — App ID + Access Token heredados. Mayor latencia, a veces mejor precisión en entornos ruidosos. Documentos: Docs API ASR v2.
Scripts incluidos
scripts/strip-for-tts.py: Limpiafinal.mdpara síntesis de voz.scripts/tts-generate.py: Convierte texto limpio en MP3 fragmentados usando la API V1.scripts/podcast-generate.py: Genera diálogo de podcast desde URL/texto usando la API WebSocket.scripts/asr-transcribe.py: Transcribe archivos de audio a texto usando ASR heredado o Flash.
Referencias / 参考文献
| Documento | Propósito |
|---|---|
| 豆包语音产品简介 / 能力总览文档 | Visión general de productos, activación y límites de cuota |
| Docs API V1 TTS HTTP | Ruta TTS de producción (heredada pero funcional) |
| Docs API TTS 2.0 Bidireccional / TTS 3.0 | Streaming V3 / migración TTS 2.0 |
| Docs API V3 TTS HTTP Chunked/SSE | V3 HTTP para texto largo / fragmentación |
| Docs API Podcast WebSocket V3 | Protocolo de podcast |
| Docs API Flash ASR | ASR rápida, nueva consola |
| Límite de tamaño de archivo de Cloudflare Pages | 25 MiB por archivo |