Mixbot en dos fases: publicar el texto pronto (--parte1) para adelantar traducciones + audios sin esperar a la multimedia de Carmenchu #181

Open
opened 2026-07-22 05:12:50 +00:00 by inma · 6 comments
Collaborator

Motivo

Hoy la carta no se cierra hasta tenerlo TODO, y eso incluye la multimedia de Carmenchu (voluntaria, elige el material cuando puede). Esperar a la multimedia retrasa el arranque de los audios de toda la semana.

Pero hay una asimetría que podemos aprovechar:

  • Lo que necesita audio (TTS) = el texto (editorial, comentarios al evangelio, artículos). Y eso ya está listo pronto, no depende de Carmenchu.
  • Lo que llega tarde = la multimedia (canciones, vídeos)… que NO necesita TTS (ya es audio/vídeo).

O sea: justo lo que retrasa la carta es lo que no necesita audio. Si publicamos el texto antes, Hermes puede empezar a traducir + locutar sin esperar a la multimedia. Cero retraso en los audios.

Lo que ya está hecho (lado Mixbot)

Implementado mixbot.py <carpeta> --parte1 (FASE 1):

  • Publica en producción solo el texto ya listo (editorial, comentarios, artículos) — mismo camino idempotente que --vivo (status=publish, autor real, alta de autores nuevos con /crear-autor).
  • NO compone la carta ni rota categorías (eso sigue siendo la FASE 2 = --vivo).
  • Deja en la carpeta 00mix_parte1_ids.txt con la lista de IDs de posts ES publicados, separando los de texto (para TTS) de la multimedia (no necesita TTS), y una línea IDs de texto (para TTS): 55001,55002,… lista para copiar.

FASE 2 (--vivo) no cambia: compone la carta entera, actualiza los posts de la fase 1 (idempotente, no duplica), añade la multimedia, rota categorías y genera el máster de BREVO.

Lo que pedimos coordinar (lado Hermes)

Hoy el pipeline de Hermes descubre qué locutar a partir de la carta (fea_parse_carta_sections necesita la carta compuesta). En la FASE 1 todavía no hay carta.

La pregunta: ¿puede Hermes arrancar traducciones (EN/FR/IT/PT) + TTS a partir de una lista de IDs de posts que le pasamos, en vez de descubrir el cluster desde la carta? Sus scripts de traducción/TTS ya trabajan por post, así que debería ser un cambio pequeño: alimentar la lista de IDs en lugar del paso de descubrimiento.

Flujo propuesto, de punta a punta:

  1. Inma/Mixbot: cuando el texto esté listo → --parte1 → publica y saca los IDs.
  2. Inma → Hermes (por el canal de WhatsApp que ya usamos): le pasa los IDs de texto.
  3. Hermes: traduce + TTS de esos posts, sin esperar a la carta.
  4. Más tarde, cuando llega la multimedia de Carmenchu → Inma/Mixbot: --vivo → compone la carta entera y rota. Los audios del texto ya están hechos.

Encaja con

#172 (autosuficiencia), #174 (cierre autónomo de la carta), #173 (entonación TTS). Como Rafa está descansando, Inma le ordena a Hermes el arranque por WhatsApp; este issue queda como referencia del flujo para cuando Rafa lo revise.

## Motivo Hoy la carta no se cierra hasta tenerlo TODO, y eso incluye la **multimedia de Carmenchu** (voluntaria, elige el material cuando puede). Esperar a la multimedia **retrasa el arranque de los audios** de toda la semana. Pero hay una asimetría que podemos aprovechar: - Lo que **necesita audio (TTS)** = el **texto** (editorial, comentarios al evangelio, artículos). Y eso **ya está listo pronto**, no depende de Carmenchu. - Lo que **llega tarde** = la **multimedia** (canciones, vídeos)… que **NO necesita TTS** (ya es audio/vídeo). O sea: justo lo que retrasa la carta es lo que no necesita audio. Si publicamos el texto antes, **Hermes puede empezar a traducir + locutar sin esperar a la multimedia**. Cero retraso en los audios. ## Lo que ya está hecho (lado Mixbot) Implementado **`mixbot.py <carpeta> --parte1`** (FASE 1): - Publica en producción **solo el texto ya listo** (editorial, comentarios, artículos) — mismo camino idempotente que `--vivo` (status=publish, autor real, alta de autores nuevos con `/crear-autor`). - **NO compone la carta ni rota categorías** (eso sigue siendo la FASE 2 = `--vivo`). - Deja en la carpeta **`00mix_parte1_ids.txt`** con la lista de **IDs de posts ES** publicados, separando los de **texto (para TTS)** de la **multimedia (no necesita TTS)**, y una línea `IDs de texto (para TTS): 55001,55002,…` lista para copiar. **FASE 2 (`--vivo`) no cambia:** compone la carta entera, actualiza los posts de la fase 1 (idempotente, no duplica), añade la multimedia, rota categorías y genera el máster de BREVO. ## Lo que pedimos coordinar (lado Hermes) Hoy el pipeline de Hermes descubre qué locutar **a partir de la carta** (`fea_parse_carta_sections` necesita la carta compuesta). En la FASE 1 **todavía no hay carta**. **La pregunta:** ¿puede Hermes arrancar traducciones (EN/FR/IT/PT) + TTS **a partir de una lista de IDs de posts** que le pasamos, en vez de descubrir el cluster desde la carta? Sus scripts de traducción/TTS ya trabajan por post, así que debería ser un cambio pequeño: **alimentar la lista de IDs** en lugar del paso de descubrimiento. Flujo propuesto, de punta a punta: 1. **Inma/Mixbot:** cuando el texto esté listo → `--parte1` → publica y saca los IDs. 2. **Inma → Hermes** (por el canal de WhatsApp que ya usamos): le pasa los IDs de texto. 3. **Hermes:** traduce + TTS de esos posts, sin esperar a la carta. 4. **Más tarde, cuando llega la multimedia de Carmenchu → Inma/Mixbot:** `--vivo` → compone la carta entera y rota. Los audios del texto ya están hechos. ## Encaja con #172 (autosuficiencia), #174 (cierre autónomo de la carta), #173 (entonación TTS). Como Rafa está descansando, Inma le ordena a Hermes el arranque por WhatsApp; este issue queda como referencia del flujo para cuando Rafa lo revise.
Owner

Gate obligatorio de calidad multilingüe antes de TTS/publicación (añadido 22-jul)

El estado 0 errores de translate_post.py solo confirma que el proceso técnico terminó: no equivale a una traducción editorialmente aprobada. En la primera ejecución de --parte1 se detectaron errores semánticos reales pese a que las 64 traducciones se crearon sin fallo (por ejemplo, cizaña acabó como cevada/espiga en PT y seme di mosto en IT).

A partir de ahora, el flujo de Hermes para cada lote 00mix_parte1_ids.txt queda así, sin publicar ni sincronizar nada a prod hasta el cierre explícito de Mixbot/Inma/Rafa:

  1. Importar prod → WP local por IDs, con backup y dry-run. Producción es solo lectura; no se crean ficheros temporales en ella.
  2. Comprobar alineación local/prod de ID, título, contenido, slug, estado e idioma.
  3. Traducir EN/FR/IT/PT en draft local con Gemma.
  4. Sanity-check automático: los 4 borradores existen, siguen en draft y no contienen artefactos (|||FIN>>>, caracteres de alfabetos ajenos, etc.).
  5. Revisión editorial multilingüe con Claude Haiku (claude-haiku-4-5) en modo solo lectura: por cada artículo compara el ES íntegro con EN/FR/IT/PT y devuelve por idioma approve, needs_review o rewrite, con cita exacta y reemplazo propuesto. Verifica especialmente terminología bíblica: cizaña → ivraie / zizzania / joio.
  6. Corregir solo en WP local los casos needs_review/rewrite; repetir el control de calidad hasta que no queden bloqueantes.
  7. Solo entonces generar TTS local en el orden de la lista de Mixbot. No subir MP3, no publicar traducciones y no rotar categorías hasta que el flujo de FASE 2 esté cerrado y se dé la orden correspondiente.

Evidencia de la primera corrida

  • 16 fuentes ES, 64 borradores local EN/FR/IT/PT.
  • Gemma: 53 min 42 s, 0 errores técnicos.
  • Informe local inicial: logs/issue-181-translation-quality-review.md.
  • Auditoría estructurada Haiku en curso: logs/issue-181-haiku-review.jsonl.

Esto convierte la revisión de calidad en parte fija del pipeline y evita que una traducción técnicamente generada llegue a producción sin una segunda lectura multilingüe.

## Gate obligatorio de calidad multilingüe antes de TTS/publicación (añadido 22-jul) El estado `0 errores` de `translate_post.py` solo confirma que el proceso técnico terminó: **no equivale a una traducción editorialmente aprobada**. En la primera ejecución de `--parte1` se detectaron errores semánticos reales pese a que las 64 traducciones se crearon sin fallo (por ejemplo, *cizaña* acabó como `cevada/espiga` en PT y `seme di mosto` en IT). A partir de ahora, el flujo de Hermes para cada lote `00mix_parte1_ids.txt` queda así, sin publicar ni sincronizar nada a prod hasta el cierre explícito de Mixbot/Inma/Rafa: 1. **Importar prod → WP local por IDs**, con backup y dry-run. Producción es solo lectura; no se crean ficheros temporales en ella. 2. **Comprobar alineación** local/prod de ID, título, contenido, slug, estado e idioma. 3. **Traducir EN/FR/IT/PT en `draft` local** con Gemma. 4. **Sanity-check automático**: los 4 borradores existen, siguen en draft y no contienen artefactos (`|||FIN>>>`, caracteres de alfabetos ajenos, etc.). 5. **Revisión editorial multilingüe con Claude Haiku** (`claude-haiku-4-5`) en modo solo lectura: por cada artículo compara el ES íntegro con EN/FR/IT/PT y devuelve por idioma `approve`, `needs_review` o `rewrite`, con cita exacta y reemplazo propuesto. Verifica especialmente terminología bíblica: `cizaña → ivraie / zizzania / joio`. 6. **Corregir solo en WP local** los casos `needs_review`/`rewrite`; repetir el control de calidad hasta que no queden bloqueantes. 7. Solo entonces generar **TTS local** en el orden de la lista de Mixbot. No subir MP3, no publicar traducciones y no rotar categorías hasta que el flujo de FASE 2 esté cerrado y se dé la orden correspondiente. ### Evidencia de la primera corrida - 16 fuentes ES, 64 borradores local EN/FR/IT/PT. - Gemma: 53 min 42 s, 0 errores técnicos. - Informe local inicial: `logs/issue-181-translation-quality-review.md`. - Auditoría estructurada Haiku en curso: `logs/issue-181-haiku-review.jsonl`. Esto convierte la revisión de calidad en parte fija del pipeline y evita que una traducción técnicamente generada llegue a producción sin una segunda lectura multilingüe.
Owner

Resultado del piloto Haiku — auditoría completa de FASE 1 (22-jul)

La revisión multilingüe ya terminó para los 16 artículos / 64 borradores. Un resultado salió inicialmente con JSON inválido (#54867), se reintentó con formato compacto y quedó auditado correctamente: 16/16 cubiertos.

Triage de Haiku (no son correcciones aplicadas todavía)

  • rewrite: 3 artículos
  • needs_review: 13 artículos
  • approve global: 0 artículos

Desglose por idioma:

  • EN: 7 approve / 9 needs_review
  • FR: 7 approve / 8 needs_review / 1 rewrite
  • IT: 4 approve / 9 needs_review / 3 rewrite
  • PT: 5 approve / 5 needs_review / 6 rewrite

Los hallazgos son sustantivos, no solo preferencias de estilo. Ejemplos verificables:

  • #54903 IT: grano de mostazaseme di mosto (debe ser seme/granello di senape); sedientosedioso.
  • #54903 PT: cizañacevada/espiga; debe ser solo joio.
  • #54868 EN: ministerio petrinopriestly ministry; debe ser Petrine ministry.
  • #54875 IT: egliaciuto di gioia, forma inexistente; debe ser pieno di gioia.
  • #54902 FR: notre perle est la fée; debe ser notre perle est la foi.

Decisión operativa que confirma el gate

Los borradores se mantienen solo en local. No se publicará ni sincronizará ninguna traducción hasta:

  1. aplicar/cotejar las correcciones propuestas en local;
  2. repetir la auditoría Haiku sobre los artículos corregidos; y
  3. tener el lote sin bloqueantes rewrite/needs_review graves.

Artefactos locales de trazabilidad:

  • logs/issue-181-haiku-review.jsonl
  • logs/issue-181-haiku-review-54867-retry.json
  • logs/issue-181-translation-quality-review.md

El TTS ES puede continuar en paralelo porque no depende de las traducciones, pero tampoco se subirá a producción hasta el cierre explícito de la FASE 2.

## Resultado del piloto Haiku — auditoría completa de FASE 1 (22-jul) La revisión multilingüe ya terminó para los **16 artículos / 64 borradores**. Un resultado salió inicialmente con JSON inválido (`#54867`), se reintentó con formato compacto y quedó auditado correctamente: **16/16 cubiertos**. ### Triage de Haiku (no son correcciones aplicadas todavía) - `rewrite`: **3** artículos - `needs_review`: **13** artículos - `approve` global: **0** artículos Desglose por idioma: - EN: 7 approve / 9 needs_review - FR: 7 approve / 8 needs_review / 1 rewrite - IT: 4 approve / 9 needs_review / 3 rewrite - PT: 5 approve / 5 needs_review / 6 rewrite Los hallazgos son sustantivos, no solo preferencias de estilo. Ejemplos verificables: - `#54903` IT: *grano de mostaza* → `seme di mosto` (debe ser `seme/granello di senape`); `sediento` → `sedioso`. - `#54903` PT: *cizaña* → `cevada/espiga`; debe ser solo `joio`. - `#54868` EN: *ministerio petrino* → `priestly ministry`; debe ser `Petrine ministry`. - `#54875` IT: `egliaciuto di gioia`, forma inexistente; debe ser `pieno di gioia`. - `#54902` FR: `notre perle est la fée`; debe ser `notre perle est la foi`. ### Decisión operativa que confirma el gate Los borradores se mantienen **solo en local**. No se publicará ni sincronizará ninguna traducción hasta: 1. aplicar/cotejar las correcciones propuestas en local; 2. repetir la auditoría Haiku sobre los artículos corregidos; y 3. tener el lote sin bloqueantes `rewrite`/`needs_review` graves. Artefactos locales de trazabilidad: - `logs/issue-181-haiku-review.jsonl` - `logs/issue-181-haiku-review-54867-retry.json` - `logs/issue-181-translation-quality-review.md` El TTS ES puede continuar en paralelo porque no depende de las traducciones, pero tampoco se subirá a producción hasta el cierre explícito de la FASE 2.
Owner

TTS FASE 1 — bloqueado por cuota MiniMax; comportamiento de reintento corregido (22-jul)

Al iniciar el TTS local de los 16 textos ES, MiniMax devolvió en el primer post (#54875) el código explícito:

2056 — Token Plan usage limit reached: Upgrade your Token Plan or purchase Credits for more usage.

Resultado: 0/16 audios generados. No se subió ningún MP3 ni se tocó producción.

Corrección aplicada y probada en local

El orquestador scripts/tts_produce.py reintentaba tres veces cada 30 minutos incluso ante 2056, desperdiciando una hora cuando la cuota ya estaba agotada. Ahora 2056 (cuota) y 1039 (rate limit) hacen que el proceso pare en el primer intento, registre fea_audio_error y quede reanudable para un relanzamiento posterior.

Prueba aislada sin MiniMax ni escritura WP: fast_fail_test=PASS | attempts=1 | sleep=0 | setflag=2056.

No hay cron TTS activo. El lote queda preparado y pendiente de que vuelva cuota/créditos; al relanzarlo respetará el orden de IDs de Mixbot y omitirá todo audio ya generado.

## TTS FASE 1 — bloqueado por cuota MiniMax; comportamiento de reintento corregido (22-jul) Al iniciar el TTS local de los 16 textos ES, MiniMax devolvió en el primer post (`#54875`) el código explícito: `2056 — Token Plan usage limit reached: Upgrade your Token Plan or purchase Credits for more usage.` Resultado: **0/16 audios generados**. No se subió ningún MP3 ni se tocó producción. ### Corrección aplicada y probada en local El orquestador `scripts/tts_produce.py` reintentaba tres veces cada 30 minutos incluso ante `2056`, desperdiciando una hora cuando la cuota ya estaba agotada. Ahora `2056` (cuota) y `1039` (rate limit) hacen que el proceso **pare en el primer intento**, registre `fea_audio_error` y quede reanudable para un relanzamiento posterior. Prueba aislada sin MiniMax ni escritura WP: `fast_fail_test=PASS | attempts=1 | sleep=0 | setflag=2056`. No hay cron TTS activo. El lote queda preparado y pendiente de que vuelva cuota/créditos; al relanzarlo respetará el orden de IDs de Mixbot y omitirá todo audio ya generado.
Owner

Diagnóstico de cuota MiniMax — causa confirmada (22-jul)

Se verificó en vivo la misma API key que usa scripts/minimax_tts.py y el medidor de cuota (/home/rafa/Feadulta/minimax.txt). Ambos endpoints de MiniMax responden HTTP 200 pero con:

  • base_resp.status_code: 2062
  • base_resp.status_msg: no active token plan subscription
  • model_remains: []

Esto significa que el TTS no consumió la cuota ni falló por cola/rate limit: la key es válida, pero no tiene un Token Plan activo asociado (posible plan caducado, cancelado o key de otra cuenta sin plan). Por eso la primera solicitud TTS recibió 2056 y se rechazó antes de generar audio.

También se corrigió el medidor ytsummaries/scripts/quota.py: antes ocultaba el base_resp y mostraba el ambiguo sin model_remains; ahora informa el diagnóstico real: API 2062: no active token plan subscription (prueba real: PASS).

No se relanzará TTS hasta que Rafa confirme que el plan/créditos de MiniMax están activos. Sigue sin haber audio generado ni cambios en producción.

## Diagnóstico de cuota MiniMax — causa confirmada (22-jul) Se verificó en vivo la misma API key que usa `scripts/minimax_tts.py` y el medidor de cuota (`/home/rafa/Feadulta/minimax.txt`). Ambos endpoints de MiniMax responden HTTP 200 pero con: - `base_resp.status_code: 2062` - `base_resp.status_msg: no active token plan subscription` - `model_remains: []` Esto significa que el TTS no consumió la cuota ni falló por cola/rate limit: **la key es válida, pero no tiene un Token Plan activo asociado** (posible plan caducado, cancelado o key de otra cuenta sin plan). Por eso la primera solicitud TTS recibió `2056` y se rechazó antes de generar audio. También se corrigió el medidor `ytsummaries/scripts/quota.py`: antes ocultaba el `base_resp` y mostraba el ambiguo `sin model_remains`; ahora informa el diagnóstico real: `API 2062: no active token plan subscription` (prueba real: PASS). No se relanzará TTS hasta que Rafa confirme que el plan/créditos de MiniMax están activos. Sigue sin haber audio generado ni cambios en producción.
Owner

TTS FASE 1 — completado en local (16/16)

Tras activar el Token Plan MiniMax y verificar status_code=0, se ejecutó la cola explícita de Mixbot en este orden:

54875, 54902, 54903, 54883, 54884, 54885, 54886, 54866, 54867, 54868, 54869, 54870, 54871, 54872, 54873, 54880

Resultado: 16/16 MP3 generados correctamente con speech-2.8-hd y las voces por autor configuradas.

Verificación local posterior:

  • los 16 archivos definitivos wp-content/uploads/tts/<ID>.mp3 existen y tienen tamaño > 0;
  • los 16 posts tienen fea_audio_done=1 y fea_audio_url configurado;
  • no hubo errores de cuota ni síntesis durante esta ejecución;
  • no se ejecutó sync_audio_to_prod.py: los audios siguen solo en WordPress local, como exige --parte1 hasta la Fase 2 y autorización expresa.
## TTS FASE 1 — completado en local (16/16) Tras activar el Token Plan MiniMax y verificar `status_code=0`, se ejecutó la cola explícita de Mixbot en este orden: `54875, 54902, 54903, 54883, 54884, 54885, 54886, 54866, 54867, 54868, 54869, 54870, 54871, 54872, 54873, 54880` Resultado: **16/16 MP3 generados correctamente** con `speech-2.8-hd` y las voces por autor configuradas. Verificación local posterior: - los 16 archivos definitivos `wp-content/uploads/tts/<ID>.mp3` existen y tienen tamaño > 0; - los 16 posts tienen `fea_audio_done=1` y `fea_audio_url` configurado; - no hubo errores de cuota ni síntesis durante esta ejecución; - **no se ejecutó `sync_audio_to_prod.py`**: los audios siguen solo en WordPress local, como exige `--parte1` hasta la Fase 2 y autorización expresa.
Owner

Preview local de revisión — traducciones publicadas solo en local

Por indicación de Rafa se publicó el lote exclusivamente en WordPress local para revisión visual/editorial:

  • 64/64 traducciones EN/FR/IT/PT (16 textos × 4 idiomas) pasaron de draft a publish local;
  • backup previo: logs/issue-181-local-preview-backup-20260722T190808Z.json;
  • dry-run previo: 64 publicaciones previstas, 0 fechas futuras;
  • comprobación en navegador local: EN y FR responden públicas; el ES tiene reproductor HTML5 visible y el audio local asociado;
  • no se ha ejecutado ninguna sincronización a producción.

Rotación

No se aplicó rotate_cartas.php, deliberadamente: los 16 IDs de --parte1 son textos sueltos (sin _carta_id ni categoría Carta de la Semana), no una carta madre. Ejecutar rotación ahora usaría un artículo como si fuera carta y alteraría categorías de forma incorrecta. Queda pendiente hasta que Mixbot entregue el ID de la carta de Fase 2.

El preview no equivale a aprobación editorial: siguen pendientes las correcciones del gate Haiku (por ejemplo, en FR aparece Que vivons la foi..., que necesita revisión).

## Preview local de revisión — traducciones publicadas solo en local Por indicación de Rafa se publicó el lote exclusivamente en WordPress local para revisión visual/editorial: - `64/64` traducciones EN/FR/IT/PT (16 textos × 4 idiomas) pasaron de `draft` a `publish` local; - backup previo: `logs/issue-181-local-preview-backup-20260722T190808Z.json`; - dry-run previo: `64` publicaciones previstas, `0` fechas futuras; - comprobación en navegador local: EN y FR responden públicas; el ES tiene reproductor HTML5 visible y el audio local asociado; - **no se ha ejecutado ninguna sincronización a producción**. ### Rotación No se aplicó `rotate_cartas.php`, deliberadamente: los 16 IDs de `--parte1` son textos sueltos (sin `_carta_id` ni categoría Carta de la Semana), no una carta madre. Ejecutar rotación ahora usaría un artículo como si fuera carta y alteraría categorías de forma incorrecta. Queda pendiente hasta que Mixbot entregue el ID de la carta de Fase 2. El preview no equivale a aprobación editorial: siguen pendientes las correcciones del gate Haiku (por ejemplo, en FR aparece `Que vivons la foi...`, que necesita revisión).
Sign in to join this conversation.
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/feadulta#181