Aplicación de escritorio para generar, validar y exportar datasets en Guaraní usando múltiples modelos de IA.
Proyecto desarrollado en el marco de la hackathon organizada por GuaranIA, del CIDIT.
- Marcos Codas — Lead Dev. Director de Alianzas Estratégicas y Educación en GDevelop.
- Samira Ríos — Linguist Hero. Lic. en Lengua y Cultura Guaraní.
- Marcelo Pesallaccia — Data Wrangler. Co-fundador de CrossNextion, empresa de desarrollo de software.
La consigna de la hackathon pedía producir datos sintéticos. Para nuestro equipo, la calidad de esos datos y la reproducibilidad del proceso de generación —a través de una herramienta pensada para la accesibilidad— importaban igual.
Nuestra lingüista guía durante esta hackathon fue la Lic. en Lengua y Cultura Guaraní Samira Ríos, quien tiene discapacidad visual. Construimos la aplicación en Python + Qt para que ella pudiera evaluar cada oración y agregar las correcciones correspondientes usando su lector de pantalla NVDA.
Probamos dos estrategias de generación:
- Traducción directa de oraciones provenientes del corpus Jojajovai, traducidas con Gemini.
- Generación sintética, aplicando reglas gramaticales del guaraní directamente en el prompt.
Hicimos varias rondas de validación en los 5 dominios del generador (salud, agricultura, educación, comercio, familia): Samira usó nuestra herramienta de validación para puntuar cada oración del 1 al 5 en sintaxis y en semántica, y para agregar las correcciones manuales que hicieran falta.
También recurrimos a Ñe'ẽryru Guaraní Rayhupape 3, del Ateneo de la Lengua y Cultura Guaraní: fotografiamos las páginas relevantes, les hicimos OCR, y de ahí extrajimos reglas y vocabulario que nos faltaba (días de la semana, posposiciones, y más reglas de construcción de oraciones).
Así quedó el pipeline final:
- Generación 100% sintética — el prompt, con los guardrails gramaticales (al estilo RAG), se envía a Gemini. La respuesta pasa por un filtro que verifica el cumplimiento de nuestras reglas; si lo cumple, se guarda en la base de datos; si no, Gemini la corrige y se vuelve a evaluar hasta que pasa.
- Generación por traducción — se toma una muestra del corpus Jojajovai como ejemplo, Gemini genera una variación, se valida contra nuestras reglas, se traduce con Gemini, se vuelve a validar, y solo entra a la base de datos si pasa el test; si no, se rehace con Gemini + nuestras reglas hasta que pase.
Los resultados de esas rondas de validación y de la evaluación automática del pipeline están más abajo, en Calidad del Dataset (Evaluación).
Medimos tres variantes del pipeline contra un held-out gold set: 95 pares español→guaraní del corpus Jojajovai, tomados exclusivamente de split=="test" (nunca usado como seed de generación — ver jojajovai_seeds.py), con traducción humana real (gn) como referencia.
| Variante | Qué es |
|---|---|
| Gemini alone | Prompt de traducción mínimo, sin reglas de dominio |
| Gemini + our rules | Prompt actual del generador: reglas Batch3, glosario de préstamos, vocabulario por dominio (get_generation_prompt) |
| + validation gate | Igual que arriba, pero los pares que fallan el validador se descartan en vez de conservarse |
| Guaraní Translator API | El traductor ES↔GN dedicado de la hackathon (guarani_translator_api.py) — sin prompt, sin reglas, sin RAG posible. Solo corre si el servidor está alcanzable (red Wi-Fi local de la hackathon); si no, el script lo omite sin fallar el resto de la evaluación. |
Resultado, con el proceso de depuración incluido:
Las primeras corridas mostraron a "Gemini alone" ganándole en chrF++/BLEU a "Gemini + our rules" — y en vez de reportar solo el número final, revisamos ejemplos concretos para entender por qué:
- El prompt traducía nombres propios que el propio validador ya sabía que no debía traducir — "Mercado 4" se convertía en "Ñemuhãguasu 4-gua...". Corregimos el prompt (nombres propios y de organizaciones nunca se traducen, y llevan guion antes de una partícula guaraní).
- La regla "sin código-switching" era un exceso: batch4 corrigió una lista curada de ~20 préstamos específicos, no "traducí toda palabra española". El prompt generalizaba esa lista a un rechazo total, y terminaba traduciendo cosas como "comisión" o "miembro titular" que la propia referencia humana de Jojajovai deja en español (jopara periodístico normal). Acotamos la regla al glosario curado: todo lo demás puede quedar en jopara, igual que lo haría "Gemini alone".
Con ambas correcciones, "Gemini + our rules" le gana a "Gemini alone" en las tres métricas: chrF++ 40.8 → 46.8, BLEU 13.7 → 16.3, y cumplimiento de reglas Batch3 75% → 78% (100% de los pares que conserva el validation gate, al costo de descartar ~22%; el bootstrap pareado de 1000 remuestreos favorece a "rules" en el 94.8% de los casos, IC 95% de la diferencia [-0.7, 7.1]).
¿Y contra un traductor dedicado? Corrimos también el Guaraní Translator API de la hackathon (opción 2 de la guía) — sin prompt, sin reglas, sin posibilidad de RAG, solo la oración en español. Le gana claramente a ambos brazos de Gemini en chrF++/BLEU (56.8 / 29.6, diferencia significativa: 0% de los remuestreos bootstrap favorecen a "rules" frente a este traductor). Tiene sentido: es un modelo de traducción dedicado, no un LLM general traduciendo zero-shot — no pretendemos superarlo en fidelidad léxica contra la referencia. Donde sí lo superamos es en cumplimiento de nuestras propias reglas Batch3 (74% vs. 78% de "rules"), esperable porque ese traductor nunca vio nuestro glosario ni nuestras convenciones de dominio; ese número mide conformidad con nuestras reglas, no la calidad real de su traducción.
El pipeline completo, incluidas las dos correcciones y el traductor dedicado, puede reproducirse con:
python -m scripts.evaluate_quality --per-domain 20 --out results/quality_eval.json
python -m scripts.plot_quality_eval --in results/quality_eval.json --out-dir publicEl cuarto arm (Guaraní Translator API, el traductor dedicado de la hackathon) se suma automáticamente al correr ese mismo comando desde la red Wi-Fi local de la hackathon — el script hace un healthcheck primero y lo omite sin fallar si no está alcanzable.
Este proyecto está licenciado bajo Apache License 2.0.
Versión: 4.1 | Actualizado: Agosto 8, 2026 | Líneas de código: ~3,800


