TTS: voz clonada por autor (a partir de feedback #78 / registro 54227) #152

Open
opened 2026-07-07 13:00:52 +00:00 by rafa · 4 comments
Owner

Origen

Feedback de usuario en el CPT fea_feedback (registro 54231... concretamente el 54227, 04/07, sobre "Mi carga es ligera"):

"No se si tengo derecho a opinar. Particularmente no me agrada la voz de 'escucha'. Tal vez sería interesante poder seleccionar la voz, como sucede en word."

Propuesta

En vez de (o además de) permitir elegir voz genérica, clonar la voz de cada autor habitual y usarla para locutar (TTS) sus propios artículos. Ya tenemos el pipeline validado con la voz de Nico (voice cloning MiniMax, scripts/minimax_tts.py, voice_id NicoFeadulta2026), así que el camino técnico ya existe — solo falta la materia prima por autor.

Qué necesitamos de cada autor (para Inma, que es quien tiene contacto directo)

Que cada autor habitual grabe UNA vez su propio artículo leído en voz alta, y nos lo mande. Requisitos de calidad imprescindibles:

  • Grabadora de sonidos del teléfono o vídeo (audio nítido, sin compresión agresiva).
  • NO vale nota de voz de WhatsApp (audio muy comprimido/baja calidad, no sirve para clonar bien el timbre).
  • Ideal: 3-5 minutos de lectura continua, ambiente silencioso, sin ruido de fondo ni música.

Plan técnico (una vez llegue el audio)

  1. Clonar voz con MiniMax Rapid Voice Cloning (minimax_tts.py clone <audio> <voice_id>) — coste $1.5/voz (cobrado en la 1ª síntesis).
  2. Guardar el voice_id por autor (mapear author_id → voice_id en algún meta o config).
  3. Al generar el TTS de un artículo, usar la voz del autor si existe clon; si no, caer a la voz por defecto (Nico) como hasta ahora.
  4. Ojo cuota: la voz clonada caduca si no se usa en 168h — hay que sintetizar algo pronto tras clonar para no perder el clon.

Pendiente

  • Inma consigue las grabaciones de los autores que quieran participar (empezar por los habituales / los que tengan más artículos).
  • Nosotros mapeamos voice_id ↔ autor y adaptamos minimax_tts.py / el orquestador para elegir voz por autor.

Relacionado: #78 (feedback Beta, CPT fea_feedback).

## Origen Feedback de usuario en el CPT `fea_feedback` (registro 54231... concretamente el 54227, 04/07, sobre "Mi carga es ligera"): > "No se si tengo derecho a opinar. Particularmente no me agrada la voz de 'escucha'. Tal vez sería interesante poder seleccionar la voz, como sucede en word." ## Propuesta En vez de (o además de) permitir elegir voz genérica, **clonar la voz de cada autor habitual** y usarla para locutar (TTS) sus propios artículos. Ya tenemos el pipeline validado con la voz de Nico (voice cloning MiniMax, `scripts/minimax_tts.py`, voice_id `NicoFeadulta2026`), así que el camino técnico ya existe — solo falta la materia prima por autor. ## Qué necesitamos de cada autor (para Inma, que es quien tiene contacto directo) Que cada autor habitual grabe **UNA vez** su propio artículo leído en voz alta, y nos lo mande. Requisitos de calidad imprescindibles: - **Grabadora de sonidos del teléfono o vídeo** (audio nítido, sin compresión agresiva). - **NO vale nota de voz de WhatsApp** (audio muy comprimido/baja calidad, no sirve para clonar bien el timbre). - Ideal: 3-5 minutos de lectura continua, ambiente silencioso, sin ruido de fondo ni música. ## Plan técnico (una vez llegue el audio) 1. Clonar voz con MiniMax Rapid Voice Cloning (`minimax_tts.py clone <audio> <voice_id>`) — coste $1.5/voz (cobrado en la 1ª síntesis). 2. Guardar el `voice_id` por autor (mapear `author_id → voice_id` en algún meta o config). 3. Al generar el TTS de un artículo, usar la voz del autor si existe clon; si no, caer a la voz por defecto (Nico) como hasta ahora. 4. Ojo cuota: la voz clonada **caduca si no se usa en 168h** — hay que sintetizar algo pronto tras clonar para no perder el clon. ## Pendiente - Inma consigue las grabaciones de los autores que quieran participar (empezar por los habituales / los que tengan más artículos). - Nosotros mapeamos voice_id ↔ autor y adaptamos `minimax_tts.py` / el orquestador para elegir voz por autor. Relacionado: #78 (feedback Beta, CPT `fea_feedback`).
Author
Owner

Voz de Fray Marcos clonada (2026-07-08)

Origen: documental "Fray Marcos, buscador de silencios" (Paula Hierro) en YouTube, tramo de 2 min a partir de t=973s (voz limpia, sin música de fondo, verificado con espectrograma antes de clonar).

voice_id = FrayMarcosFeadulta2026 (MiniMax, misma cuenta/saldo que Nico). Clip fuente en tts-voices/fraymarcos/ (WSL local, no versionado en git).

Implementado

  • scripts/minimax_tts.py: dict AUTHOR_VOICES = {382: "FrayMarcosFeadulta2026"} (382 = user_id de Fray Marcos, mismo mapping que assign_author_photos.php) + voice_for_author(author_id, default_voice). get_post_text() ahora devuelve también el author (post_author) — cambia el contrato a 3-tuplo (title, text, author).
  • scripts/fea_post_io.php: acción get incluye author; acción setaudio <id> <relpath> [voice_id] ahora acepta la voz como 3er argumento opcional (default NicoFeadulta2026 si no se pasa, retrocompatible).
  • scripts/tts_produce.py: por cada post calcula voice = mm.voice_for_author(author, VOICE) y la usa en la síntesis y en setaudio. El resto de autores sigue con Nico sin cambios.
  • scripts/sync_audio_to_prod.py: al publicar en prod, lee el meta local fea_audio_voice real y lo propaga (antes forzaba siempre NicoFeadulta2026 al llamar setaudio en prod — bug latente, corregido de paso).

Regenerado

El único artículo de Fray Marcos de la carta 734 (post #54251, «Creerme tierra buena es el mayor peligro») se había locutado esta mañana con Nico (antes de tener el clon). Se regeneró con FrayMarcosFeadulta2026 y se resincronizó a prod; verificado byte-a-byte local↔prod y meta fea_audio_voice correcto en ambos.

Pendiente

  • Resto de autores del mapping de assign_author_photos.php: sin voz clonada todavía, caen a Nico por defecto (comportamiento esperado hasta que Inma consiga más grabaciones, ver cuerpo del issue).
## Voz de Fray Marcos clonada (2026-07-08) Origen: documental *"Fray Marcos, buscador de silencios"* (Paula Hierro) en YouTube, tramo de 2 min a partir de t=973s (voz limpia, sin música de fondo, verificado con espectrograma antes de clonar). `voice_id = FrayMarcosFeadulta2026` (MiniMax, misma cuenta/saldo que Nico). Clip fuente en `tts-voices/fraymarcos/` (WSL local, no versionado en git). ### Implementado - **`scripts/minimax_tts.py`**: dict `AUTHOR_VOICES = {382: "FrayMarcosFeadulta2026"}` (382 = user_id de Fray Marcos, mismo mapping que `assign_author_photos.php`) + `voice_for_author(author_id, default_voice)`. `get_post_text()` ahora devuelve también el `author` (post_author) — cambia el contrato a 3-tuplo `(title, text, author)`. - **`scripts/fea_post_io.php`**: acción `get` incluye `author`; acción `setaudio <id> <relpath> [voice_id]` ahora acepta la voz como 3er argumento opcional (default `NicoFeadulta2026` si no se pasa, retrocompatible). - **`scripts/tts_produce.py`**: por cada post calcula `voice = mm.voice_for_author(author, VOICE)` y la usa en la síntesis y en `setaudio`. El resto de autores sigue con Nico sin cambios. - **`scripts/sync_audio_to_prod.py`**: al publicar en prod, lee el meta local `fea_audio_voice` real y lo propaga (antes forzaba siempre `NicoFeadulta2026` al llamar `setaudio` en prod — bug latente, corregido de paso). ### Regenerado El único artículo de Fray Marcos de la carta 734 (**post #54251**, «Creerme tierra buena es el mayor peligro») se había locutado esta mañana con Nico (antes de tener el clon). Se regeneró con `FrayMarcosFeadulta2026` y se resincronizó a prod; verificado byte-a-byte local↔prod y meta `fea_audio_voice` correcto en ambos. ### Pendiente - Resto de autores del mapping de `assign_author_photos.php`: sin voz clonada todavía, caen a Nico por defecto (comportamiento esperado hasta que Inma consiga más grabaciones, ver cuerpo del issue).
Author
Owner

Voz de José Antonio Pagola clonada (2026-07-08)

Origen: vídeo de YouTube (https://youtu.be/_O0rbalEVFk), tramo de 2 min desde t=249s (los tramos en t=24 y t=27.5 tenían música de fondo colada, descartados tras revisar espectrograma).

voice_id = PagolaFeadulta2026. Cableado en AUTHOR_VOICES de scripts/minimax_tts.py (author_id 383 = José Antonio Pagola, mismo mapping que assign_author_photos.php). Mismo mecanismo que Fray Marcos (#152): solo sus artículos usan su voz, el resto sigue con Nico.

Regenerado

El único artículo de Pagola de la carta 734 (post #54252, «Sembrar con fe») se había locutado con Nico. Regenerado con PagolaFeadulta2026 y resincronizado a prod; verificado byte-a-byte y meta correcto en ambos.

Pendiente (decisión de Rafa: dejarlos para más adelante)

Otros 8 artículos de Pagola con audio ya generado con Nico, sin regenerar por ahora:

  • #45012 «El nuevo domingo» (carta 44997)
  • #45032 «Programa liberador» (carta 45018)
  • #46951 «Liberar del miedo a nuestras comunidades» (carta 46956) + sus 4 traducciones EN/FR/IT/PT (#46952-46955)
  • #53639 «Aprender a dar» (carta 53644)
  • #53982 «Dios es para gente sencilla» (carta 53984)
## Voz de José Antonio Pagola clonada (2026-07-08) Origen: vídeo de YouTube (`https://youtu.be/_O0rbalEVFk`), tramo de 2 min desde t=249s (los tramos en t=24 y t=27.5 tenían música de fondo colada, descartados tras revisar espectrograma). `voice_id = PagolaFeadulta2026`. Cableado en `AUTHOR_VOICES` de `scripts/minimax_tts.py` (author_id **383** = José Antonio Pagola, mismo mapping que `assign_author_photos.php`). Mismo mecanismo que Fray Marcos (#152): solo sus artículos usan su voz, el resto sigue con Nico. ### Regenerado El único artículo de Pagola de la carta 734 (**post #54252**, «Sembrar con fe») se había locutado con Nico. Regenerado con `PagolaFeadulta2026` y resincronizado a prod; verificado byte-a-byte y meta correcto en ambos. ### Pendiente (decisión de Rafa: dejarlos para más adelante) Otros 8 artículos de Pagola con audio ya generado con Nico, **sin regenerar por ahora**: - #45012 «El nuevo domingo» (carta 44997) - #45032 «Programa liberador» (carta 45018) - #46951 «Liberar del miedo a nuestras comunidades» (carta 46956) + sus 4 traducciones EN/FR/IT/PT (#46952-46955) - #53639 «Aprender a dar» (carta 53644) - #53982 «Dios es para gente sencilla» (carta 53984)
Author
Owner

Voz de José Luis Sicre clonada (2026-07-08)

Origen: vídeo de YouTube (https://www.youtube.com/watch?v=MWmvTK5b1Jw), tramo de 2 min desde t=1s. Limpio a la primera (sin música colada como en el caso de Pagola).

voice_id = SicreFeadulta2026. Cableado en AUTHOR_VOICES de scripts/minimax_tts.py (author_id 774 = José Luis Sicre).

Regenerado

El único artículo de Sicre de la carta 734 (post #54250, «Respuestas para una crisis de la Iglesia») se había locutado con Nico. Regenerado con SicreFeadulta2026 y resincronizado a prod; verificado byte-a-byte y meta correcto en ambos.

Pendiente (igual criterio que Pagola: dejarlos para más adelante)

Otros 6 artículos de Sicre con audio ya generado (3 con Nico, 3 sin meta de voz registrado — anteriores a ese tracking), sin regenerar por ahora:

  • #44977 «Fiesta de la Santísima Trinidad» (carta 44975)
  • #45000 «El maná y el pan de vida» (carta 44997)
  • #45021 «Compasivo hasta la muerte» (carta 45018)
  • #46939 «Domingo 12 del tiempo ordinario. Ciclo A» (carta 46956)
  • #53626 «Exigencias y recompensa» (carta 53644)
  • #53980 «Mejor ser sencillo que sabio» (carta 53984)

Estado de voces clonadas hasta ahora

  • 382 Fray Marcos → FrayMarcosFeadulta2026
  • 383 José Antonio Pagola → PagolaFeadulta2026
  • 774 José Luis Sicre → SicreFeadulta2026
  • Resto de autores del mapping de assign_author_photos.php: siguen con Nico por defecto.
## Voz de José Luis Sicre clonada (2026-07-08) Origen: vídeo de YouTube (`https://www.youtube.com/watch?v=MWmvTK5b1Jw`), tramo de 2 min desde t=1s. Limpio a la primera (sin música colada como en el caso de Pagola). `voice_id = SicreFeadulta2026`. Cableado en `AUTHOR_VOICES` de `scripts/minimax_tts.py` (author_id **774** = José Luis Sicre). ### Regenerado El único artículo de Sicre de la carta 734 (**post #54250**, «Respuestas para una crisis de la Iglesia») se había locutado con Nico. Regenerado con `SicreFeadulta2026` y resincronizado a prod; verificado byte-a-byte y meta correcto en ambos. ### Pendiente (igual criterio que Pagola: dejarlos para más adelante) Otros 6 artículos de Sicre con audio ya generado (3 con Nico, 3 sin meta de voz registrado — anteriores a ese tracking), sin regenerar por ahora: - #44977 «Fiesta de la Santísima Trinidad» (carta 44975) - #45000 «El maná y el pan de vida» (carta 44997) - #45021 «Compasivo hasta la muerte» (carta 45018) - #46939 «Domingo 12 del tiempo ordinario. Ciclo A» (carta 46956) - #53626 «Exigencias y recompensa» (carta 53644) - #53980 «Mejor ser sencillo que sabio» (carta 53984) ### Estado de voces clonadas hasta ahora - 382 Fray Marcos → `FrayMarcosFeadulta2026` - 383 José Antonio Pagola → `PagolaFeadulta2026` - 774 José Luis Sicre → `SicreFeadulta2026` - Resto de autores del mapping de `assign_author_photos.php`: siguen con Nico por defecto.
Author
Owner

Voz de José Arregi clonada (2026-07-08)

Origen: 2 candidatos probados.

  • https://youtu.be/7vxJcFQHg-c t=2118s: descartado — ruido de fondo más alto de lo normal (~-41dB en huecos vs ~-55dB de los otros) + tono fino persistente ~12.5kHz en el espectrograma.
  • https://www.youtube.com/live/Sp3nNwb3mdY t=477s: usado, limpio (huecos de silencio real por debajo de -45dB, sin tono).

voice_id = ArregiFeadulta2026. Cableado en AUTHOR_VOICES de scripts/minimax_tts.py (author_id 386 = José Arregi).

Sin regenerar nada

Arregi tiene 3 artículos con audio antiguo (#45004, #45028, #45033 — todos anteriores al tracking de fea_audio_voice, sin meta de voz registrado) pero ninguno en la carta 734, así que no aplica el patrón de regenerar-el-más-reciente esta vez.

Estado de voces clonadas hasta ahora

  • 382 Fray Marcos → FrayMarcosFeadulta2026
  • 383 José Antonio Pagola → PagolaFeadulta2026
  • 774 José Luis Sicre → SicreFeadulta2026
  • 386 José Arregi → ArregiFeadulta2026
  • Resto de autores del mapping de assign_author_photos.php: siguen con Nico por defecto.
## Voz de José Arregi clonada (2026-07-08) Origen: 2 candidatos probados. - `https://youtu.be/7vxJcFQHg-c` t=2118s: descartado — ruido de fondo más alto de lo normal (~-41dB en huecos vs ~-55dB de los otros) + tono fino persistente ~12.5kHz en el espectrograma. - `https://www.youtube.com/live/Sp3nNwb3mdY` t=477s: **usado**, limpio (huecos de silencio real por debajo de -45dB, sin tono). `voice_id = ArregiFeadulta2026`. Cableado en `AUTHOR_VOICES` de `scripts/minimax_tts.py` (author_id **386** = José Arregi). ### Sin regenerar nada Arregi tiene 3 artículos con audio antiguo (#45004, #45028, #45033 — todos anteriores al tracking de `fea_audio_voice`, sin meta de voz registrado) pero **ninguno en la carta 734**, así que no aplica el patrón de regenerar-el-más-reciente esta vez. ### Estado de voces clonadas hasta ahora - 382 Fray Marcos → `FrayMarcosFeadulta2026` - 383 José Antonio Pagola → `PagolaFeadulta2026` - 774 José Luis Sicre → `SicreFeadulta2026` - 386 José Arregi → `ArregiFeadulta2026` - Resto de autores del mapping de `assign_author_photos.php`: siguen con Nico por defecto.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/feadulta#152