From 1bb1eb925a600d78c48601081cb33bf7e2ec6c4a Mon Sep 17 00:00:00 2001 From: rafa Date: Mon, 31 Aug 2026 07:27:05 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20gu=C3=ADa=20de=20autoservicio=20de=20tr?= =?UTF-8?q?aducci=C3=B3n=20para=20Inma/Mixbot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Segunda parte del traspaso pedido por Rafa (audio ya en #223): reglas de traducción exactas, la técnica de contexto de título del #203 (sin fusionar a main todavía), checklist de QA reformulado en REST puro, y cómo leer la cuota de MiniMax. Señala el mismo tipo de hueco que tenía el audio antes del #222: no hay forma de fijar idioma/grupo Polylang de una traducción por REST. --- ...uia-traduccion-autoservicio-inma-mixbot.md | 161 ++++++++++++++++++ docs/guia-tts-traduccion-inma.md | 9 +- 2 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 docs/guia-traduccion-autoservicio-inma-mixbot.md diff --git a/docs/guia-traduccion-autoservicio-inma-mixbot.md b/docs/guia-traduccion-autoservicio-inma-mixbot.md new file mode 100644 index 0000000..32254c1 --- /dev/null +++ b/docs/guia-traduccion-autoservicio-inma-mixbot.md @@ -0,0 +1,161 @@ +# Guía de traducción (EN/FR/IT/PT) en autoservicio — para Inma / Mixbot + +> **Para quién es este documento:** para Inma y Mixbot, a partir de la conversación del +> 2026-08-31 en Buzz: además del audio ([#222](https://gitea.feadulta.com/rafa/feadulta/issues/222), +> ver `docs/guia-tts-audio-autoservicio-inma-mixbot.md`), Rafa quiere traspasar también la +> traducción. A diferencia del audio, hoy **no hay un issue abierto pidiéndolo** — este +> documento adelanta el trabajo para cuando se dispare. +> +> **Motores autorizados por Rafa (2026-08-31):** un agente local con Haiku desde el propio +> Claude/Cowork de Inma (no la API de pago de Rafa — es otra cuenta, otro caso), o MiniMax +> con el mismo token ya compartido para el audio. **Gemma queda fuera para vosotros**: es un +> modelo local que corre en la GPU del PC de Rafa, no accesible desde fuera. + +--- + +## 0. Antes de nada: esto también tiene un tope bloqueante + +Igual que pasaba con el audio, **hoy no hay forma de decirle a WordPress "esta traducción +va en inglés y es la versión de este post en español"** desde fuera. Ese enlace (idioma + +grupo de traducción) lo gestiona Polylang con dos funciones PHP internas +(`pll_set_post_language`, `pll_save_post_translations`) que **no están expuestas por REST** — +ni siquiera de lectura (el único endpoint que hay, `fea/v1/lang/{id}`, solo lee el idioma, no +permite fijarlo ni enlazar grupos). + +Podéis crear el post traducido por `POST /wp/v2/posts` sin problema (igual que cualquier +artículo), pero **quedaría suelto**: sin idioma asignado y sin enlace Polylang al original en +español, así que el selector de idioma del sitio no lo encontraría y no contaría como "la +traducción EN de este artículo". + +**Esto necesita el mismo tipo de solución que el audio**: un endpoint `fea/v1/crear-traduccion` +(o registrar la taxonomía `language` de Polylang en REST con permisos de administrador) que +haga internamente lo mismo que ya hace `scripts/fea_translate_helper.php::create` en local: +crear el post, `pll_set_post_language($id, $lang)`, y `pll_save_post_translations($grupo)` +enlazándolo con el ES. No lo he encargado todavía — es una pieza más grande que la del audio +(toca la lógica central de multiidioma del sitio) y prefiero que Rafa decida el momento y el +alcance antes de que Codix la construya. Documento aquí el resto del proceso para que, en +cuanto ese hueco se cierre, solo falte la llamada final. + +--- + +## 1. Las reglas de traducción (igual las use vuestro Claude/Haiku o MiniMax) + +Esto es el prompt real que usa el pipeline de Rafa (`scripts/translate_post.py`), verificado +palabra por palabra el 2026-08-31 contra el código — usadlo tal cual, no lo resumáis: + +> Eres un traductor profesional de textos religiosos cristianos (espiritualidad y teología +> católica). Traduce del español al {idioma destino}. REGLAS ESTRICTAS: +> 1. Conserva EXACTAMENTE el marcado HTML (etiquetas y atributos) y los shortcodes entre `[ ]` +> y `{ }`. No los traduzcas ni los reordenes. +> 2. NO traduzcas las referencias bíblicas ni sus abreviaturas (p. ej. "Jn 3, 16", "Isaías 5, +> 1-7", "Mt 5"). Déjalas idénticas. +> 3. Conserva los nombres propios de persona y lugar (salvo exónimos establecidos). +> 4. Glosario fijo: "Fe Adulta" → "Fe Adulta" (en/fr/it/pt, no se traduce); "EFFA" → "EFFA" +> (igual, en los 4 idiomas). +> 5. Traducción FIEL: no resumas, no añadas, no comentes. + +Para el **título**, además: que quede natural en el idioma destino (no lo dejéis en español +salvo que sea un nombre propio o una marca), y si es un modismo, traducid el sentido, no lo +calquéis literal. + +## 2. El "learning" del título — dadle el primer párrafo como contexto + +Esto es lo que pedía Rafa explícitamente documentar. **Aviso de precisión:** este cambio +existe como commit (`4475ebb`, rama `feat/issue-200-title-context`) pero **no está fusionado +a `main`** — verificado el 2026-08-31 comparando el histórico. O sea: si alguna vez volvéis a +usar `scripts/translate_post.py` tal cual desde main, el título se traduce SIN este contexto. +Para vuestro proceso propio (agente Haiku o llamada directa a MiniMax) aplicad la técnica de +todas formas, es la que ya dio mejor resultado en pruebas: + +- **Traducid primero el cuerpo del artículo, el título al final** — necesitáis el cuerpo ya + traducido (o al menos leído) para poder darle contexto al título. +- Al traducir el título, añadid al prompt el **primer párrafo del cuerpo en español** + (recortado a 2000 caracteres), como contexto de significado — no se traduce ni se incluye + literal en la salida, solo ayuda al modelo a entender modismos o dobles sentidos del + título que sin ese contexto salen mal traducidos. +- Instrucción exacta añadida al prompt del título: *"Si es un modismo, interpreta su sentido + según el contexto, no lo calques."* + +## 3. Troceo de artículos largos + +Si usáis MiniMax para traducir (no Haiku, que admite el artículo entero de una vez gracias a +su contexto de 200k), trocead el HTML por párrafos completos (nunca a mitad de una etiqueta) +en bloques de ~5.000 caracteres, y unid las traducciones de cada trozo en el mismo orden. + +## 4. QA — checklist antes de dar una traducción por buena + +Reformulado en REST puro (el script original, `gate_mec2.php`, corre dentro de WP y usa +funciones de Polylang no disponibles desde fuera — pero las comprobaciones sí son igual de +válidas mirando el JSON de cada post por la API): + +Para cada origen ES y cada idioma que hayáis traducido, comparad contra el post ES: + +1. **Cobertura**: los 4 idiomas presentes (o los que toque — Pagola nunca lleva traducción + automática, ver §5). +2. **Estado**: la traducción en `draft` hasta que se revise (salvo que el ES ya esté + `publish` y la carta lo pida — ver `docs/guia-publicacion-carta-inma.md`). +3. **Sin residuos de generación**: buscar literalmente en el `content` devuelto por la API + cadenas como `**`, ``, `<>`, `<<>>`, `<<>>`, + `|||FIN`, o cualquier resto de las marcas del prompt. +4. **Sin alfabetos ajenos**: ningún carácter árabe/cirílico/CJK en el resultado (residuo + típico de generación que se cuela cuando el modelo "piensa" en otro idioma). +5. **Mismo nº de párrafos** que el ES (contar apariciones de ``** que el ES — **es el check que más falla y el más + importante**: en la carta 739, el italiano perdió 15 de 39 enlaces en uno de los trozos + troceados mientras EN/FR salieron bien, y nada posterior lo detecta si no lo comprobáis + aquí. Si hay menos enlaces en la traducción que en el ES, **no la deis por buena**. +7. **Referencias bíblicas equivalentes**: extraer patrones tipo `capítulo,versículo` de + ambos textos y comparar solo capítulo:versículo, **no la abreviatura del libro completa** + (el inglés cambia la coma por dos puntos y traduce el nombre: `Mt 15,21-28` en ES pasa a + `Matthew 15:21-28` en EN — comparar literal daría un falso positivo de "referencia + perdida"). +8. **Título distinto del ES** (salvo portugués, donde algunos nombres propios/citas + coinciden de forma legítima). + +Capa editorial adicional si tenéis acceso a un modelo capaz de juzgar fidelidad (vuestro +Claude/Haiku local sirve para esto): pedidle que lea origen y traducción y devuelva un +veredicto `approve` / `needs_review` / `rewrite` con la cita exacta del problema — descartad +cualquier hallazgo cuya cita no aparezca literal en el texto (evita ediciones basadas en +alucinaciones del propio revisor). + +## 5. Excepciones que no lleváis por la vía automática + +- **Autores que aportan su propia traducción humana** (hoy, Pagola: 4 DOCX por carta, + adjuntos en el issue de la semana) — nunca generéis fallback automático para ellos aunque + falte alguno de los 4 idiomas. +- **Textos litúrgicos enlazados desde la carta** (evangelio, lecturas) — confirmar con Rafa + si entran en el alcance de "todo lo de la carta" o se dejan fuera; ha habido confusión + antes sobre esto (no dar por hecho que "ya deben estar traducidos"). + +## 6. Cómo leer la cuota de MiniMax + +Con el mismo token que ya tenéis para el audio: + +```bash +curl -s https://api.minimax.io/v1/token_plan/remains \ + -H "Authorization: Bearer " -H "Content-Type: application/json" +``` + +Del JSON de respuesta: +- `base_resp.status_code` debe ser `0` (cualquier otro valor es error de cuenta/plan, ver + `base_resp.status_msg`). +- `model_remains` es una lista por modelo. El de texto/traducción es el que tiene + `model_name == "general"`; los de audio son los `speech-2.8-*` que ya usáis para TTS. +- De cada entrada: `current_interval_remaining_percent` (cuánto queda de la ventana de 5h + que se resetea sola — `end_time` es cuándo) y `current_weekly_remaining_percent` / + `weekly_end_time` (la ventana semanal, más amplia). Restad a 100 para saber "cuánto habéis + gastado" si preferís verlo así. + +Igual que con el audio: un HTTP 200 no es garantía de cuota — cuando `t2a_v2` o el endpoint +de traducción devuelvan `base_resp.status_code=2056` (plan agotado) o `1039` (límite de +ritmo), parad y reintentad más tarde, no machaquéis la API. + +## 7. Qué falta para que esto sea autoservicio de verdad + +- **Bloqueante (§0):** endpoint o mecanismo para fijar idioma + enlazar grupo Polylang de + cada traducción — sin esto podéis generar el texto pero no "engancharlo" al sitio como + traducción real, igual que pasaba con el audio antes del #222. +- Decisión pendiente de Rafa (no la resuelvo yo aquí): si vuestro agente de traducción va a + tener acceso de shell/SSH al WordPress (como tenía Hermes) o va a ser puramente REST como + el resto de vuestro trabajo — cambia bastante el diseño del endpoint que haría falta. diff --git a/docs/guia-tts-traduccion-inma.md b/docs/guia-tts-traduccion-inma.md index d06ed3e..f6b686e 100644 --- a/docs/guia-tts-traduccion-inma.md +++ b/docs/guia-tts-traduccion-inma.md @@ -14,8 +14,13 @@ > token de MiniMax. La §4 de abajo describe el flujo viejo (Hermes ejecutando > `scripts/tts_produce.py` en el PC de Rafa); para el flujo nuevo de autoservicio, con la receta > exacta de preparación de texto y pausas, usar -> **`docs/guia-tts-audio-autoservicio-inma-mixbot.md`**. Las **traducciones** siguen por ahora -> como se describe en §3 de este documento — no incluidas todavía en el traspaso. +> **`docs/guia-tts-audio-autoservicio-inma-mixbot.md`**. Rafa confirmó el mismo día que las +> **traducciones** van también hacia autoservicio (agente local con Haiku desde el Claude de +> Inma, o MiniMax con el mismo token) aunque todavía sin un issue como el #222 que lo dispare +> — ver **`docs/guia-traduccion-autoservicio-inma-mixbot.md`** para las reglas, el QA y el +> hueco de infraestructura equivalente (falta enlazar idioma/grupo Polylang por REST). La §3 +> de abajo sigue describiendo el flujo viejo vía Hermes, todavía válido mientras no se cierre +> ese hueco. ---