enpaiva's picture
Update app.py
d4b1b0f verified
import re
import gradio as gr
import pickle
import numpy as np
from dataclasses import dataclass
from typing import Dict, Any, List, Tuple
import os
try:
import faiss
from sentence_transformers import SentenceTransformer
RAG_AVAILABLE = True
except ImportError:
RAG_AVAILABLE = False
print("⚠️ FAISS o SentenceTransformers no disponibles. El buscador RAG estará deshabilitado.")
"""
Diccionario normalizado de partículas del Guaraní
(Prefijos, Sufijos y Circunfijos)
"""
# ==============================================================================
# CIRCUNFIJOS (PREFIJO-SUFIJO)
# ==============================================================================
CIRCUNFIJOS_GUARANI = {
"nd-i": {
'descripcion': 'Negación verbal discontinua para verbos orales (nd-...i / nd-...ri cuando la base termina en i). Forma negativa circunfija. Expresa negación simple en presente, pasado o futuro. Equivale a "no" + verbo en español. Se usa para negar acciones con verbos de articulación oral (no nasales). Variante: ndVrVi cuando el verbo termina en vocal. Términos relacionados: negación, no hacer, no realizar, forma negativa.',
'ejemplos': [('ndajapói', 'no hago'), ('ndoguatái', 'no camina'), ('ndajupíri', 'no subo')]
},
"nd-ri": {
'descripcion': 'Negación verbal discontinua para verbos orales (nd-...i / nd-...ri cuando la base termina en i). Forma negativa circunfija. Expresa negación simple en presente, pasado o futuro. Equivale a "no" + verbo en español. Se usa para negar acciones con verbos de articulación oral (no nasales). Variante: ndVrVi cuando el verbo termina en vocal. Términos relacionados: negación, no hacer, no realizar, forma negativa.',
'ejemplos': [('ndajapói', 'no hago'), ('ndoguatái', 'no camina'), ('ndajupíri', 'no subo')]
},
"n-i": {
'descripcion': 'Negación verbal discontinua para verbos nasales (n-...i / n-...ri cuando la base termina en i). Forma negativa circunfija nasal. Expresa negación para verbos de pronunciación nasal. Equivale a "no" + verbo nasal en español. Variante nasal del circunfijo negativo. Términos relacionados: negación nasal, no hacer (verbos nasales), forma negativa nasal.',
'ejemplos': [('nakororõi', 'no ronca'), ('nomañái', 'no mira'), ('nembotýi', 'no cierra')]
},
"n-ri": {
'descripcion': 'Negación verbal discontinua para verbos nasales (n-...i / n-...ri cuando la base termina en i). Forma negativa circunfija nasal. Expresa negación para verbos de pronunciación nasal. Equivale a "no" + verbo nasal en español. Variante nasal del circunfijo negativo. Términos relacionados: negación nasal, no hacer (verbos nasales), forma negativa nasal.',
'ejemplos': [('nakororõi', 'no ronca'), ('nomañái', 'no mira'), ('nembotýi', 'no cierra')]
},
"nde-i": {
'descripcion': 'Negación verbal discontinua de segunda persona singular para verbos orales (nde-re...i). Forma negativa circunfija con marcador personal. Expresa "tú no" + verbo oral. Combina negación con pronombre de segunda persona. Términos relacionados: negación segunda persona, tú no, vos no, usted no (informal), forma negativa personal.',
'ejemplos': [('nderejapói', 'tú no haces'), ('ndereguatái', 'tú no caminas')]
},
"nde-ri": {
'descripcion': 'Negación verbal discontinua de segunda persona singular para verbos orales (nde-re...i). Forma negativa circunfija con marcador personal. Expresa "tú no" + verbo oral. Combina negación con pronombre de segunda persona. Términos relacionados: negación segunda persona, tú no, vos no, usted no (informal), forma negativa personal.',
'ejemplos': [('nderejapói', 'tú no haces'), ('ndereguatái', 'tú no caminas')]
},
"ne-i": {
'descripcion': 'Negación verbal discontinua de segunda persona singular para verbos nasales (ne-re...i). Forma negativa circunfija nasal con marcador personal. Expresa "tú no" + verbo nasal. Variante nasal de la negación de segunda persona. Términos relacionados: negación segunda persona nasal, tú no (verbos nasales), vos no (verbos nasales).',
'ejemplos': [('nerembotýi', 'tú no cierras'), ('neremañái', 'tú no miras')]
},
"ne-ri": {
'descripcion': 'Negación verbal discontinua de segunda persona singular para verbos nasales (ne-re...i). Forma negativa circunfija nasal con marcador personal. Expresa "tú no" + verbo nasal. Variante nasal de la negación de segunda persona. Términos relacionados: negación segunda persona nasal, tú no (verbos nasales), vos no (verbos nasales).',
'ejemplos': [('nerembotýi', 'tú no cierras'), ('neremañái', 'tú no miras')]
},
"nda-i": {
'descripcion': 'Negación verbal discontinua de primera persona plural inclusiva para verbos orales (ndaja-ja...i). Forma negativa circunfija con marcador de plural inclusivo. Expresa "nosotros no" (incluyendo al oyente) + verbo oral. Términos relacionados: negación primera persona plural, nosotros no, no hacemos (inclusivo), forma negativa plural inclusiva.',
'ejemplos': [('ndajajapói', 'no hacemos (incluyéndote)'), ('ndajaguatái', 'no caminamos (incluyéndote)')]
},
"nda-ri": {
'descripcion': 'Negación verbal discontinua de primera persona plural inclusiva para verbos orales (ndaja-ja...i). Forma negativa circunfija con marcador de plural inclusivo. Expresa "nosotros no" (incluyendo al oyente) + verbo oral. Términos relacionados: negación primera persona plural, nosotros no, no hacemos (inclusivo), forma negativa plural inclusiva.',
'ejemplos': [('ndajajapói', 'no hacemos (incluyéndote)'), ('ndajaguatái', 'no caminamos (incluyéndote)')]
},
"na-i": {
'descripcion': 'Negación verbal discontinua de primera persona plural inclusiva para verbos nasales (naña-ña...i). Forma negativa circunfija nasal con marcador de plural inclusivo. Expresa "nosotros no" (incluyendo al oyente) + verbo nasal. Variante nasal de la negación plural inclusiva. Términos relacionados: negación primera persona plural nasal, nosotros no (inclusivo, verbos nasales).',
'ejemplos': [('nañambotýi', 'no cerramos (incluyéndote)'), ('nañamañái', 'no miramos (incluyéndote)')]
},
"na-ri": {
'descripcion': 'Negación verbal discontinua de primera persona plural inclusiva para verbos nasales (naña-ña...i). Forma negativa circunfija nasal con marcador de plural inclusivo. Expresa "nosotros no" (incluyendo al oyente) + verbo nasal. Variante nasal de la negación plural inclusiva. Términos relacionados: negación primera persona plural nasal, nosotros no (inclusivo, verbos nasales).',
'ejemplos': [('nañambotýi', 'no cerramos (incluyéndote)'), ('nañamañái', 'no miramos (incluyéndote)')]
},
}
# ==============================================================================
# PREFIJOS
# ==============================================================================
PREFIJOS_GUARANI = {
"ñembo": {
'descripcion': 'Voz reflexiva causativa. Marca acción que uno hace sobre sí mismo o se hace hacer. Equivale a "hacerse" + verbo, "se hace" + infinitivo. Combina reflexividad con causatividad. Términos relacionados: reflexivo causativo, hacerse, autoinfligirse, autoaplicar, pronombre reflexivo causativo.',
'ejemplos': [('oñembohory', 'se hace reír'), ('oñembopuká', 'se hace reír a carcajadas')]
},
"jembo": {
'descripcion': 'Voz reflexiva causativa (variante de ñembo). Marca acción reflexiva con elemento causativo. Indica que el sujeto causa la acción sobre sí mismo o se deja hacer algo. Equivale a "dejarse" + infinitivo, "hacerse" + verbo. Términos relacionados: reflexivo causativo, dejarse hacer, permitirse, autoinducir.',
'ejemplos': [('ojembojaru', 'se deja engañar'), ('ojembohasa', 'se hace pasar')]
},
"ñande": {
'descripcion': 'Marcador posesivo de primera persona plural inclusivo (incluye al oyente). Prefijo posesivo que indica "nuestro/a" (de todos, incluyendo a quien escucha). Se usa con sustantivos orales. Términos relacionados: posesivo inclusivo, nuestro de todos, posesión compartida, posesivo primera persona plural inclusivo.',
'ejemplos': [('ñanderóga', 'nuestra casa (de todos)'), ('ñandesy', 'nuestra madre (de todos)')]
},
"ñane": {
'descripcion': 'Marcador posesivo de primera persona plural inclusivo nasal (incluye al oyente). Prefijo posesivo nasal que indica "nuestro/a" (de todos, incluyendo a quien escucha). Variante nasal de ñande, se usa con sustantivos nasales. Términos relacionados: posesivo inclusivo nasal, nuestro de todos (nasal), posesión compartida nasal.',
'ejemplos': [('ñaneretã', 'nuestro país'), ("ñaneñe'ẽ", 'nuestro idioma')]
},
"pende": {
'descripcion': 'Marcador posesivo de segunda persona plural. Prefijo posesivo que indica "de ustedes", "su/sus" (de varias personas a quienes se habla). Se usa con sustantivos orales. Términos relacionados: posesivo segunda persona plural, de ustedes, su de ustedes, posesión plural oyentes.',
'ejemplos': [('penderóga', 'la casa de ustedes'), ('penderu', 'el padre de ustedes')]
},
"pene": {
'descripcion': 'Marcador posesivo de segunda persona plural nasal. Prefijo posesivo nasal que indica "de ustedes", "su/sus" (de varias personas a quienes se habla). Variante nasal de pende. Términos relacionados: posesivo segunda persona plural nasal, de ustedes (nasal), su de ustedes (nasal).',
'ejemplos': [("peneñe'ẽ", 'el idioma de ustedes'), ('penembyte', 'entre ustedes')]
},
"taja": {
'descripcion': 'Modo optativo/hortativo de primera persona plural inclusiva (verbos orales). Expresa exhortación, sugerencia o deseo de acción conjunta. Equivale a "vayamos", "hagamos" (incluyendo al oyente). Términos relacionados: hortativo inclusivo, exhortación conjunta, invitación a actuar juntos, subjuntivo exhortativo, modo cohortativo.',
'ejemplos': [('tajaha', 'vayamos (todos)'), ('tajajapo', 'hagamos (todos)')]
},
"taña": {
'descripcion': 'Modo optativo/hortativo de primera persona plural inclusiva nasal (verbos nasales). Expresa exhortación o sugerencia de acción conjunta con verbos nasales. Equivale a "vayamos", "hagamos" (incluyendo al oyente). Variante nasal del hortativo inclusivo. Términos relacionados: hortativo inclusivo nasal, exhortación conjunta nasal, invitación nasal.',
'ejemplos': [("tañañe'ẽ", 'hablemos (todos)'), ('tañamomba', 'terminemos (todos)')]
},
"toro": {
'descripcion': 'Modo optativo/hortativo de primera persona plural exclusiva (excluye al oyente). Expresa exhortación o sugerencia de acción que no incluye a quien escucha. Equivale a "vayamos" (sin ti), "hagamos" (sin incluirte). Términos relacionados: hortativo exclusivo, exhortación excluyente, nosotros sin ti, cohortativo exclusivo.',
'ejemplos': [('toroho', 'vayamos (sin ti)'), ('torojapo', 'hagamos (sin ti)')]
},
"tape": {
'descripcion': 'Modo optativo/hortativo de segunda persona plural. Expresa exhortación, mandato suave o sugerencia dirigida a varias personas. Equivale a "vayan ustedes", "hagan ustedes", imperativo plural suave. Términos relacionados: hortativo segunda persona plural, imperativo plural suave, exhortación plural, que ustedes.',
'ejemplos': [('tapeho', 'vayan ustedes'), ('tapejapo', 'hagan ustedes')]
},
"tere": {
'descripcion': 'Modo optativo/hortativo de segunda persona singular. Expresa deseo, sugerencia o mandato suave dirigido a una persona. Equivale a "que tú", "ojalá que tú", subjuntivo desiderativo singular. Términos relacionados: hortativo segunda persona singular, optativo singular, deseo para otro, subjuntivo desiderativo.',
'ejemplos': [('tereho', 'que vayas'), ('terejapo', 'que hagas')]
},
"guero": {
'descripcion': 'Voz subsuntiva o comitativa. Indica acción realizada junto con otro, llevando o acompañando. Equivale a "con", "llevando consigo", "acompañado de". Marca simultaneidad de acción con persona/objeto. Términos relacionados: comitativo, junto con, acompañamiento, llevando consigo, subsuntivo.',
'ejemplos': [('oguerojeroky', 'baila con él/ella'), ('oguerosapukái', 'grita llevándolo consigo')]
},
"poro": {
'descripcion': 'Voz objetiva para personas. Marca objeto directo humano o animado. Indica que la acción recae sobre personas en general o gente. Equivale a complemento directo de persona. Términos relacionados: objeto directo humano, acción sobre personas, marca de objeto animado, objeto personal.',
'ejemplos': [('oporohayhu', 'ama a la gente'), ('oporoipytyvõ', 'ayuda a la gente')]
},
"ñemí": {
'descripcion': 'Voz reflexiva diminutiva o atenuativa. Indica acción reflexiva de poca intensidad o duración. Combina reflexividad con aspecto diminutivo. Equivale a "se...un poco", "se...levemente". Términos relacionados: reflexivo diminutivo, acción atenuada, auto-acción leve, reflexivo mitigado.',
'ejemplos': [('oñemĩmbotýi', 'se cierra un poco'), ('oñemĩmonda', 'se roba poquito')]
},
"mbo": {
'descripcion': 'Voz causativa factitiva. Marca acción que causa que otro haga algo o que algo ocurra. Equivale a "hacer" + infinitivo, "causar que", verbo factitivo. Transforma verbos intransitivos en transitivos causativos. Términos relacionados: causativo, factitivo, hacer hacer, causar, transitivizador causativo.',
'ejemplos': [('omboguata', 'hace caminar'), ('ombohory', 'hace reír')]
},
"che": {
'descripcion': 'Marcador posesivo de primera persona singular. Prefijo que indica posesión "mi", "mío/a". Se usa con sustantivos para expresar pertenencia del hablante. Términos relacionados: posesivo primera persona, mi, mío, posesión del hablante, pronombre posesivo singular.',
'ejemplos': [('cheróga', 'mi casa'), ('chesy', 'mi madre')]
},
"nde": {
'descripcion': 'Marcador posesivo de segunda persona singular. Prefijo que indica posesión "tu", "tuyo/a", "su" (de usted). Se usa con sustantivos para expresar pertenencia del oyente. Términos relacionados: posesivo segunda persona, tu, tuyo, de usted, posesión del oyente.',
'ejemplos': [('nderóga', 'tu casa'), ('nderu', 'tu padre')]
},
"ore": {
'descripcion': 'Marcador posesivo de primera persona plural exclusiva (excluye al oyente). Prefijo que indica "nuestro/a" (de nosotros, sin incluir a quien escucha). Marca posesión plural excluyente. Términos relacionados: posesivo exclusivo, nuestro sin ti, posesión plural excluyente, nosotros sin el oyente.',
'ejemplos': [('oreróga', 'nuestra casa (sin ti)'), ('oresy', 'nuestra madre (sin ti)')]
},
"jai": {
'descripcion': 'Marcador de persona aireal de primera persona plural inclusiva. Prefijo verbal que indica sujeto "nosotros" (incluyendo al oyente) para verbos con raíz aireal (inicio vocálico). Términos relacionados: sujeto inclusivo aireal, nosotros todos aireal, primera persona plural aireal inclusivo.',
'ejemplos': [('jaikuaa', 'sabemos (todos)'), ('jaipota', 'queremos (todos)')]
},
"roi": {
'descripcion': 'Marcador de persona aireal de primera persona plural exclusiva. Prefijo verbal que indica sujeto "nosotros" (sin el oyente) para verbos con raíz aireal. Términos relacionados: sujeto exclusivo aireal, nosotros sin ti aireal, primera persona plural aireal exclusivo.',
'ejemplos': [('roikuaa', 'sabemos (sin ti)'), ('roipota', 'queremos (sin ti)')]
},
"pei": {
'descripcion': 'Marcador de persona aireal de segunda persona plural. Prefijo verbal que indica sujeto "ustedes" para verbos con raíz aireal. Términos relacionados: sujeto segunda persona plural aireal, ustedes aireal, segunda persona plural aireal.',
'ejemplos': [('peikuaa', 'ustedes saben'), ('peipota', 'ustedes quieren')]
},
"mba": {
'descripcion': 'Voz objetiva para cosas o animales. Marca objeto directo inanimado. Indica que la acción recae sobre objetos, animales o cosas en general. Equivale a complemento directo de cosa. Términos relacionados: objeto directo inanimado, acción sobre cosas, marca de objeto no humano, objeto no personal.',
'ejemplos': [("omba'ejuka", 'mata animales'), ("omba'ejapo", 'hace cosas')]
},
"ja": {
'descripcion': 'Marcador de persona de primera persona plural inclusiva (verbos orales). Prefijo verbal que indica sujeto "nosotros" (incluyendo al oyente). Se usa con verbos de articulación oral. Términos relacionados: sujeto inclusivo, nosotros todos, primera persona plural inclusivo, concordancia inclusiva.',
'ejemplos': [('jaha', 'vamos (todos)'), ('jajapo', 'hacemos (todos)')]
},
"ña": {
'descripcion': 'Marcador de persona de primera persona plural inclusiva nasal (verbos nasales). Prefijo verbal que indica sujeto "nosotros" (incluyendo al oyente). Variante nasal de ja. Términos relacionados: sujeto inclusivo nasal, nosotros todos nasal, primera persona plural nasal inclusivo.',
'ejemplos': [("ñañe'ẽ", 'hablamos (todos)'), ('ñamomba', 'terminamos (todos)')]
},
"ro": {
'descripcion': 'Marcador de persona de primera persona plural exclusiva. Prefijo verbal que indica sujeto "nosotros" (sin el oyente). Marca exclusión del interlocutor. Términos relacionados: sujeto exclusivo, nosotros sin ti, primera persona plural exclusivo, concordancia exclusiva.',
'ejemplos': [('roho', 'vamos (sin ti)'), ('rojapo', 'hacemos (sin ti)')]
},
"pe": {
'descripcion': 'Marcador de persona de segunda persona plural. Prefijo verbal que indica sujeto "ustedes". Marca plural de oyentes. Términos relacionados: sujeto segunda persona plural, ustedes, segunda persona plural, concordancia plural segunda persona.',
'ejemplos': [('peho', 'ustedes van'), ('pejapo', 'ustedes hacen')]
},
"re": {
'descripcion': 'Marcador de persona de segunda persona singular. Prefijo verbal que indica sujeto "tú", "vos", "usted" (informal). Marca singular del oyente. Términos relacionados: sujeto segunda persona singular, tú, vos, segunda persona singular, concordancia singular segunda persona.',
'ejemplos': [('reho', 'tú vas'), ('rejapo', 'tú haces')]
},
"je": {
'descripcion': 'Voz pasiva (verbos orales). Marca construcción pasiva donde el sujeto recibe la acción. Equivale a "ser" + participio, voz pasiva. Términos relacionados: pasiva, ser hecho, construcción pasiva, paciente como sujeto, pasiva oral.',
'ejemplos': [('ojejuka', 'es matado'), ('ojejapo', 'es hecho')]
},
"ñe": {
'descripcion': 'Voz pasiva nasal (verbos nasales). Marca construcción pasiva con verbos de articulación nasal. Variante nasal de je. Equivale a "ser" + participio (verbos nasales). Términos relacionados: pasiva nasal, ser hecho (nasal), construcción pasiva nasal, paciente como sujeto nasal.',
'ejemplos': [('oñemomba', 'es terminado'), ("oñeñe'ẽ", 'es hablado')]
},
"jo": {
'descripcion': 'Voz recíproca (verbos orales). Marca acción mutua entre participantes. Indica que los sujetos realizan la acción entre sí. Equivale a "se...mutuamente", "entre sí". Términos relacionados: recíproco, mutuamente, entre sí, acción mutua, reciprocidad oral.',
'ejemplos': [('ojojuhu', 'se encuentran mutuamente'), ('ojojuka', 'se matan entre sí')]
},
"ño": {
'descripcion': 'Voz recíproca nasal (verbos nasales). Marca acción mutua con verbos de articulación nasal. Variante nasal de jo. Equivale a "se...mutuamente" (verbos nasales). Términos relacionados: recíproco nasal, mutuamente nasal, entre sí nasal, acción mutua nasal.',
'ejemplos': [('oñomoirũ', 'se acompañan mutuamente'), ('oñomongeta', 'conversan entre sí')]
},
"mo": {
'descripcion': 'Voz causativa (verbos nasales). Marca acción que causa que otro haga algo. Variante nasal de mbo. Equivale a "hacer" + infinitivo (verbos nasales). Términos relacionados: causativo nasal, hacer hacer (nasal), causar (nasal), factitivo nasal.',
'ejemplos': [("omoñe'ẽ", 'hace hablar'), ("omombe'u", 'hace contar')]
},
"ta": {
'descripcion': 'Modo optativo de primera persona singular. Expresa deseo o posibilidad de acción del hablante. Equivale a "que yo", "ojalá yo", subjuntivo desiderativo. Términos relacionados: optativo primera persona, subjuntivo desiderativo singular, deseo del hablante, ojalá yo.',
'ejemplos': [('taha', 'que yo vaya'), ('tajapo', 'que yo haga')]
},
"to": {
'descripcion': 'Modo optativo de tercera persona. Expresa deseo o posibilidad de acción de terceros. Equivale a "que él/ella", "ojalá", subjuntivo desiderativo tercera persona. Términos relacionados: optativo tercera persona, subjuntivo desiderativo, deseo para otro, ojalá él/ella.',
'ejemplos': [('toho', 'que vaya él/ella'), ('tojapo', 'que haga él/ella')]
},
"ha": {
'descripcion': 'Marcador de persona hareal de primera persona singular. Prefijo verbal para verbos con raíz hareal (inicio con h). Indica sujeto "yo" en estos verbos. Términos relacionados: primera persona hareal, yo hareal, sujeto hareal singular.',
'ejemplos': [("ha'u", 'yo como'), ("ha'a", 'yo caigo')]
},
"ho": {
'descripcion': 'Marcador de persona hareal de tercera persona. Prefijo verbal para verbos con raíz hareal. Indica sujeto "él/ella" en verbos haréales. Términos relacionados: tercera persona hareal, él/ella hareal, sujeto hareal tercera persona.',
'ejemplos': [("ho'u", 'él/ella come'), ("ho'a", 'él/ella cae')]
},
"ai": {
'descripcion': 'Marcador de persona aireal de primera persona singular. Prefijo verbal para verbos con raíz aireal. Indica sujeto "yo" en verbos con inicio vocálico. Términos relacionados: primera persona aireal, yo aireal, sujeto aireal singular.',
'ejemplos': [('aikuaa', 'yo sé'), ('aipota', 'yo quiero')]
},
"oi": {
'descripcion': 'Marcador de persona aireal de tercera persona. Prefijo verbal para verbos con raíz aireal. Indica sujeto "él/ella" en verbos con inicio vocálico. Términos relacionados: tercera persona aireal, él/ella aireal, sujeto aireal tercera persona.',
'ejemplos': [('oikuaa', 'él/ella sabe'), ('oipota', 'él/ella quiere')]
},
"ne": {
'descripcion': 'Marcador posesivo de segunda persona singular nasal. Prefijo posesivo nasal que indica "tu", "tuyo/a". Variante nasal de nde. Términos relacionados: posesivo segunda persona nasal, tu nasal, tuyo nasal, posesión oyente nasal.',
'ejemplos': [("neñe'ẽ", 'tu palabra'), ('nememby', 'tu hijo/a')]
},
"hi": {
'descripcion': 'Marcador posesivo de tercera persona (variante h + i). Prefijo que indica posesión "su", "de él/ella". Se usa en contextos específicos. Términos relacionados: posesivo tercera persona, su, de él/ella, posesión tercera persona.',
'ejemplos': [("hi'ári", 'sobre él/ella'), ("hi'ãri", 'su sombra')]
},
"ij": {
'descripcion': 'Marcador posesivo de tercera persona (variante i + j). Prefijo que indica posesión "su", "de él/ella". Forma alternativa del posesivo de tercera. Términos relacionados: posesivo tercera persona, su, de él/ella, pertenencia tercera persona.',
'ejemplos': [('ijao', 'su ropa'), ('ijapyka', 'su asiento')]
},
"iñ": {
'descripcion': 'Marcador posesivo de tercera persona nasal (variante i + ñ). Prefijo posesivo nasal de tercera persona. Indica "su" (de él/ella) con sustantivos nasales. Términos relacionados: posesivo tercera persona nasal, su nasal, de él/ella nasal.',
'ejemplos': [('iñakã', 'su cabeza'), ("iñe'ẽ", 'su palabra')]
},
"a": {
'descripcion': 'Marcador de persona de primera persona singular (verbos chendal). Prefijo que indica sujeto "yo". Se usa con verbos de articulación oral. Términos relacionados: primera persona, yo, sujeto primera persona, concordancia primera persona singular.',
'ejemplos': [('aha', 'yo voy'), ('ajapo', 'yo hago')]
},
"o": {
'descripcion': 'Marcador de persona de tercera persona. Prefijo verbal que indica sujeto "él", "ella". Marca más común de tercera persona. Términos relacionados: tercera persona, él, ella, sujeto tercera persona, concordancia tercera persona.',
'ejemplos': [('oho', 'él/ella va'), ('ojapo', 'él/ella hace')]
},
"e": {
'descripcion': 'Modo imperativo de segunda persona singular. Prefijo que marca mandato u orden directa. Equivale al imperativo "tú" en español. Términos relacionados: imperativo, mandato, orden, comando, imperativo singular.',
'ejemplos': [('eho', 'vé (tú)'), ('ejapo', 'hacé (tú)')]
},
"h": {
'descripcion': 'Marcador posesivo de tercera persona (forma base h-). Prefijo posesivo que indica "su", "de él/ella". Alomorfo más básico del posesivo de tercera. Términos relacionados: posesivo tercera persona, su, de él/ella, posesión tercera.',
'ejemplos': [('hóga', 'su casa'), ('hesa', 'su ojo')]
},
"i": {
'descripcion': 'Marcador posesivo de tercera persona (forma base i-). Prefijo posesivo que indica "su", "de él/ella". Variante del posesivo de tercera persona. Términos relacionados: posesivo tercera persona, su, de él/ella, pertenencia tercera.',
'ejemplos': [('ipy', 'su pie'), ('ikuña', 'su esposa')]
},
"r": {
'descripcion': 'Consonante de enlace posesivo relacional. Consonante que aparece entre poseedor y sustantivo que inicia con vocal. Marca relacional de posesión. No es un morfema independiente sino un elemento fonológico de enlace. Términos relacionados: enlace posesivo, consonante relacional, marcador relacional.',
'ejemplos': [('cheróga', 'mi casa'), ('nderesa', 'tu ojo')]
},
"t": {
'descripcion': 'Consonante de enlace posesivo absoluto o genérico. Marca forma no poseída de sustantivos. Indica sustantivo en forma absoluta o genérica. Términos relacionados: forma absoluta, no poseído, genérico, forma base sustantivo.',
'ejemplos': [('tóga', 'casa (genérico)'), ('tesa', 'ojo (genérico)')]
},
}
# ==============================================================================
# SUFIJOS
# ==============================================================================
SUFIJOS_GUARANI = {
"itereirasa": {
'descripcion': 'Grado ultrasuperlativo intensificador (mega-). Máximo grado de intensidad para vocales fuertes (a,ã,e,ẽ,o,õ). Equivale a "mega", "ultra", "extremadamente". Intensificación máxima. Términos relacionados: superlativo extremo, ultra, mega, intensificación máxima, grado máximo.',
'ejemplos': [('mitãitereirasa', 'meganiño'), ("kuimba'etereirasa", 'megahombre')]
},
"etereirasa": {
'descripcion': 'Grado ultrasuperlativo intensificador (mega-) para vocales débiles. Máximo grado de intensidad para vocales débiles (i,ĩ,u,ũ,y,ỹ). Variante del ultrasuperlativo. Términos relacionados: superlativo extremo débil, ultra, mega, intensificación máxima débil.',
'ejemplos': [("karia'yetereirasa", 'megacaballero'), ('hatãetereirasa', 'durísimo en extremo')]
},
"tereirasa": {
'descripcion': 'Grado ultrasuperlativo intensificador (mega-) para palabras terminadas en -e. Variante del ultrasuperlativo según terminación. Máxima intensidad. Términos relacionados: superlativo extremo -e, ultra -e, mega -e.',
'ejemplos': [('hete tereirasa', 'megacuerpo')]
},
"iterei": {
'descripcion': 'Grado supersuperlativo (hiper-, muy muy). Intensificación alta para vocales fuertes (a,ã,e,ẽ,o,õ). Equivale a "muy muy", "sumamente", "hiper". Términos relacionados: supersuperlativo, hiper, muy muy, sumamente, intensificación alta.',
'ejemplos': [('kuñaiterei', 'hipermujer'), ('iporãiterei', 'muy muy bonito')]
},
"eterei": {
'descripcion': 'Grado supersuperlativo (hiper-) para vocales débiles. Intensificación alta para vocales débiles (i,ĩ,u,ũ,y,ỹ). Variante del supersuperlativo. Términos relacionados: supersuperlativo débil, hiper débil, muy muy débil.',
'ejemplos': [("karia'yeterei", 'hipercaballero'), ('ivaieterei', 'muy muy feo')]
},
"terei": {
'descripcion': 'Grado supersuperlativo (hiper-) para palabras terminadas en -e. Variante del supersuperlativo según terminación. Términos relacionados: supersuperlativo -e, hiper -e, muy muy -e.',
'ejemplos': [('hete terei', 'hipercuerpo')]
},
"rasa": {
'descripcion': 'Grado superlativísimo (ultra-, super-). Intensificación muy alta, grado ultra. Equivale a "ultra", "super", "extremadamente". Términos relacionados: superlativísimo, ultra, extremadamente, intensificación muy alta.',
'ejemplos': [("karia'yrasa", 'ultracaballero'), ('karairasa', 'ultrahombre'), ('mitãrasa', 'ultraniño')]
},
"ite": {
'descripcion': 'Grado superlativo (super-, muy) para vocales fuertes. Intensificación considerable para vocales fuertes (a,ã,e,ẽ,o,õ). Equivale a "muy", "super", "realmente". Términos relacionados: superlativo, muy, super, bastante, intensificación considerable.',
'ejemplos': [('kuñaite', 'toda una dama, supermujer'), ('iporãite', 'muy bonito')]
},
"ete": {
'descripcion': 'Grado superlativo (super-, muy) para vocales débiles. Intensificación considerable para vocales débiles (i,ĩ,u,ũ,y,ỹ). Equivale a "verdadero", "auténtico", "muy". Términos relacionados: superlativo débil, muy débil, verdadero, auténtico, genuino.',
'ejemplos': [("karia'yete", 'todo un caballero, supercaballero'), ("kuimba'ete", 'todo un hombre, superhombre')]
},
"te": {
'descripcion': 'Grado superlativo (super-) para palabras terminadas en -e. Variante del superlativo según terminación. Términos relacionados: superlativo -e, muy -e, super -e.',
'ejemplos': [('hete te', 'supercuerpo')]
},
"pavẽ": {
'descripcion': 'Grado excelso supremo. Grado de máxima jerarquía o excelencia. Reservado para dignidades supremas o conceptos de máximo honor. Términos relacionados: excelso, supremo, máxima jerarquía, dignidad suprema.',
'ejemplos': [("vy'apavẽ", 'felicidades')]
},
"vete": {
'descripcion': 'Grado excelso de autoridad máxima. Marca de máxima jerarquía, especialmente en títulos y cargos. Reservado para autoridades supremas. Términos relacionados: excelso, autoridad máxima, jerarquía suprema, dignidad suprema.',
'ejemplos': [('mburuvichavete', 'Jefe de Estado')]
},
"vusu": {
'descripcion': 'Grado excelso de grandeza suprema. Marca de máxima grandeza o poder. Se usa en contextos religiosos o de máxima autoridad. Términos relacionados: excelso, grandioso, todopoderoso, supremo, máximo poder.',
'ejemplos': [('Ñanderuvusu', 'Dios todopoderoso')]
},
"ruvicha": {
'descripcion': 'Grado de superioridad o liderazgo. Marca de preeminencia, autoridad o superioridad en una categoría. Equivale a "jefe", "líder", "superior". Términos relacionados: superior, líder, jefe, preeminente, autoridad.',
'ejemplos': [('taguato ruvicha', 'águila harpía')]
},
"véntema": {
'descripcion': 'Modo comparativo de superioridad aseverativo-confirmativo. Indica que algo ya es más que antes, comparación confirmada. Equivale a "ya es más", "ahora sí es más". Términos relacionados: comparativo confirmado, ya es más, comparación aseverativa, más confirmado.',
'ejemplos': [('iporãvéntema', 'ya es más bonito'), ("omba'apovéntema", 'ya trabaja más')]
},
"va'ekue": {
'descripcion': 'Tiempo verbal pluscuamperfecto (había + participio). Marca acción completada antes de otro momento pasado. Equivale a "había hecho", tiempo ante-pasado. Términos relacionados: pluscuamperfecto, había hecho, pasado anterior, ante-pretérito.',
'ejemplos': [("oguatava'ekue", 'había caminado'), ("okañyva'ekue", 'se había perdido')]
},
"va'erã": {
'descripcion': 'Tiempo futuro obligatorio deóntico (deberá). Marca acción futura con sentido de obligación o necesidad. Equivale a "deberá", "tendrá que". Términos relacionados: futuro obligatorio, deberá, tendrá que, futuro deóntico, obligación futura.',
'ejemplos': [("oguatava'erã", 'deberá caminar'), ("ojapova'erã", 'deberá hacer')]
},
"raka'e": {
'descripcion': 'Tiempo pasado remoto o lejano (pretérito antiguo). Marca acción ocurrida hace mucho tiempo. Equivale a "hizo hace tiempo", pasado lejano. Términos relacionados: pasado remoto, hace tiempo, pasado lejano, pretérito antiguo.',
'ejemplos': [("okéraka'e", 'durmió hace tiempo'), ("ohoraka'e", 'fue hace tiempo')]
},
"manterei": {
'descripcion': 'Modo frecuentativo-habitual enfático (siempre, todo el tiempo). Marca acción repetida constantemente con énfasis. Equivale a "siempre", "constantemente", frecuencia enfática. Términos relacionados: frecuentativo enfático, siempre, habitualmente, constantemente, iterativo enfático.',
'ejemplos': [("oku'emanterei", 'siempre madruga'), ('oñembotavymanterei', 'siempre se emborracha')]
},
"míkena": {
'descripcion': 'Imperativo compuesto rogativo (por favor, te ruego). Marca mandato suave o petición cortés. Imperativo atenuado. Términos relacionados: imperativo cortés, por favor imperativo, petición, ruego, mandato atenuado.',
'ejemplos': [('epytamíkena', 'quédate por favor'), ('ejumíkena', 'ven por favor')]
},
"rãngue": {
'descripcion': 'Nominal frustrativo (lo que iba a ser, ex-futuro). Marca sustantivo que iba a cumplir una función pero no la cumplió. Equivale a "lo que iba a ser". Términos relacionados: frustrativo nominal, ex-futuro, proyecto frustrado, expectativa no cumplida.',
'ejemplos': [('cheaorãngue', 'lo que iba a ser mi ropa'), ('cherembiaporãngue', 'lo que iba a ser mi trabajo')]
},
"hikóni": {
'descripcion': 'Aspecto intermitente o esporádico. Marca acción realizada de manera irregular o de vez en cuando. Equivale a "de vez en cuando", "ocasionalmente". Términos relacionados: intermitente, ocasional, esporádico, de vez en cuando.',
'ejemplos': [('ojapohikóni', 'hace de vez en cuando'), ('oguatahikóni', 'camina de vez en cuando')]
},
"katuete": {
'descripcion': 'Modo confirmativo-enfático absoluto (definitivamente, sin duda). Marca confirmación total o certeza absoluta. Equivale a "definitivamente", "sin duda alguna". Términos relacionados: confirmativo absoluto, definitivamente, certeza absoluta, sin duda.',
'ejemplos': [('ahókatuete', 'definitivamente fui'), ('aikuaakatuete', 'definitivamente sé')]
},
"mínte": {
'descripcion': 'Modo diminutivo-restrictivo exclusivo (solamente, nada más). Marca cantidad mínima o exclusividad. Equivale a "solamente", "nada más que", "solo". Términos relacionados: exclusivo diminutivo, solamente, solo, nada más, restrictivo.',
'ejemplos': [('michĩmínte', 'solamente un poquito'), ('petẽimínte', 'solamente uno')]
},
"nguéra": {
'descripcion': 'Marcador de plural nominal (los, las). Pluralizador de sustantivos, indica múltiples entidades. Equivale a artículo plural. Términos relacionados: plural, pluralizador, los, las, múltiples.',
'ejemplos': [('mitãnguéra', 'los niños'), ('kuñanguéra', 'las mujeres')]
},
"kuéra": {
'descripcion': 'Marcador de plural nominal (los, las) variante. Pluralizador alternativo de sustantivos. Variante de nguéra. Términos relacionados: plural variante, pluralizador alternativo, los, las.',
'ejemplos': [('karaikuéra', 'los señores'), ('jaguakuéra', 'los perros')]
},
"eténe": {
'descripcion': 'Grado superlativo con modalidad epistémica probable (probablemente muy). Intensificación con matiz de probabilidad. Equivale a "probablemente muy", superlativo epistémico. Términos relacionados: superlativo probable, probablemente muy, epistémico intensificado.',
'ejemplos': [('iporãeténe', 'probablemente muy bonito'), ('oúeténe', 'probablemente vendrá')]
},
"míma": {
'descripcion': 'Aspecto progresivo-inminente enfático (ya está, ya se está). Marca acción en progreso que ya comenzó o está por completarse. Equivale a "ya está -ndo", gerundio inminente. Términos relacionados: progresivo inminente, ya está -ndo, gerundio enfático, acción en marcha.',
'ejemplos': [('ahámíma', 'ya me estoy yendo'), ('oúmíma', 'ya está viniendo')]
},
"mbota": {
'descripcion': 'Tiempo futuro próximo inmediato (está por, a punto de). Marca acción inminente en el futuro cercano. Equivale a "está por", "a punto de". Términos relacionados: futuro inmediato, está por, a punto de, futuro inminente.',
'ejemplos': [('osẽmbota', 'está por salir'), ('omañambota', 'está por mirar')]
},
"ningo": {
'descripcion': 'Modo evidencial reportativo verosímil (dicen que es verdad). Marca información reportada considerada creíble. Equivale a "dicen que (y es cierto)", evidencial confiable. Términos relacionados: evidencial verosímil, dicen que es verdad, reportativo confiable.',
'ejemplos': [('ojoguáningo', 'compró (es verdad)'), ('ohóningo', 'fue (es verdad)')]
},
"ndaje": {
'descripcion': 'Modo evidencial reportativo inverosímil o dudoso (dicen que). Marca información reportada con dudas sobre su veracidad. Equivale a "dicen que", "supuestamente". Términos relacionados: evidencial dudoso, dicen que, supuestamente, reportativo inverosímil, rumor.',
'ejemplos': [('ojavýndaje', 'dicen que erró'), ('okañýndaje', 'dicen que se perdió')]
},
"nga'u": {
'descripcion': 'Modo desiderativo-anhelativo (ojalá, deseo que). Expresa deseo o anhelo del hablante. Equivale a "ojalá", modo optativo desiderativo. Términos relacionados: desiderativo, ojalá, anhelo, deseo, optativo desiderativo.',
'ejemplos': [("okueránga'u", 'ojalá sane'), ("oúnga'u", 'ojalá venga')]
},
"gua'u": {
'descripcion': 'Modo simulativo o aparencial (finge, aparenta). Marca acción fingida o aparente. Equivale a "finge", "aparenta", "hace como que". Términos relacionados: simulativo, finge, aparenta, hace como que, modo aparencial.',
'ejemplos': [("ojevygua'u", 'finge volver'), ("okégua'u", 'finge dormir')]
},
"mo'ã": {
'descripcion': 'Modo intencional frustrado (iba a, estaba por). Marca intención no realizada. Equivale a "iba a", "estaba por", intención frustrada. Términos relacionados: intención frustrada, iba a, estaba por, propósito no cumplido.',
'ejemplos': [("ojerokymo'ã", 'iba a bailar'), ("oguatamo'ã", 'iba a caminar')]
},
"pota": {
'descripcion': 'Tiempo futuro próximo o inmediato (está por, va a). Marca acción próxima a ocurrir. Equivale a "está por", "va a" (cercano). Términos relacionados: futuro próximo, está por, va a pronto, futuro cercano.',
'ejemplos': [('oguatapota', 'está por caminar'), ('oúpota', 'está por venir')]
},
"hína": {
'descripcion': 'Aspecto progresivo-durativo continuo (está -ndo, gerundio). Marca acción en desarrollo o progreso. Equivale a "estar" + gerundio, acción continua. Términos relacionados: progresivo, gerundio, está haciendo, acción en curso, continuo, durativo.',
'ejemplos': [('oguatahína', 'está caminando'), ("oñe'ẽhína", 'está hablando')]
},
"aína": {
'descripcion': 'Aspecto progresivo de primera persona singular (estoy -ndo). Marca progresivo específico para primera persona. Equivale a "estoy" + gerundio. Términos relacionados: progresivo primera persona, estoy haciendo, gerundio primera persona.',
'ejemplos': [("aguata'aína", 'estoy caminando'), ("ajapo'aína", 'estoy haciendo')]
},
"eína": {
'descripcion': 'Aspecto progresivo de segunda persona singular (estás -ndo). Marca progresivo específico para segunda persona. Equivale a "estás" + gerundio. Términos relacionados: progresivo segunda persona, estás haciendo, gerundio segunda persona.',
'ejemplos': [("reguata'eína", 'estás caminando'), ("rejapo'eína", 'estás haciendo')]
},
"akue": {
'descripcion': 'Tiempo perfecto o pretérito completo (hizo, ha hecho). Marca acción completada en el pasado. Equivale a pretérito perfecto simple. Términos relacionados: perfecto, pretérito, pasado completo, acción terminada.',
'ejemplos': [('ogueruakue', 'trajo'), ('ojapoakue', 'hizo')]
},
"kuri": {
'descripcion': 'Tiempo pasado reciente o inmediato (recién, hace poco). Marca acción ocurrida hace poco tiempo. Equivale a "recién", "hace poco", pasado inmediato. Términos relacionados: pasado reciente, recién, hace poco, pretérito inmediato.',
'ejemplos': [('okarúkuri', 'almorzó hace poco'), ('ohókuri', 'fue hace poco')]
},
"ra'e": {
'descripcion': 'Tiempo pasado anterior o pretérito simple. Marca acción pasada simple. Equivale a pretérito indefinido. Términos relacionados: pasado simple, pretérito, pasado anterior.',
'ejemplos': [("okáira'e", 'se quemó'), ("oñembosara'ira'e", 'se resbaló')]
},
"'arã": {
'descripcion': 'Tiempo futuro necesario u obligatorio (necesitará, habrá de). Marca acción futura con matiz de necesidad. Equivale a "necesitará", "habrá de". Términos relacionados: futuro necesario, necesitará, habrá de, futuro obligado.',
'ejemplos': [("ojohéi'arã", 'necesitará lavar'), ("oguata'arã", 'necesitará caminar')]
},
"mante": {
'descripcion': 'Modo frecuentativo-habitual (siempre, habitualmente). Marca acción repetida regularmente. Equivale a "siempre", "habitualmente", frecuencia habitual. Términos relacionados: frecuentativo, habitual, siempre, usualmente, iterativo.',
'ejemplos': [('ojeímante', 'siempre se baña'), ('ohómante', 'siempre va')]
},
"nunga": {
'descripcion': 'Modo proximal o casi-efectivo (casi, por poco). Marca acción que casi ocurre pero no se completa. Equivale a "casi", "por poco". Términos relacionados: proximal, casi, por poco, acción frustrada cercana.',
'ejemplos': [('ajeínunga', 'casi me baño'), ('ahánunga', 'casi voy')]
},
"ngatu": {
'descripcion': 'Modo confirmativo-asertivo (efectivamente, realmente). Marca confirmación o verificación de la acción. Equivale a "efectivamente", "de verdad". Términos relacionados: confirmativo, efectivamente, realmente, verificado, asertivo.',
'ejemplos': [('ohóngatu', 'efectivamente fue'), ('oikuaángatu', 'efectivamente sabe')]
},
"mimi": {
'descripcion': 'Modo iterativo gradual o intermitente leve (de a poco, gradualmente). Marca acción repetida gradualmente. Equivale a "de a poco", "poco a poco". Términos relacionados: iterativo gradual, de a poco, gradualmente, poco a poco.',
'ejemplos': [('ohupytymimi', 'alcanza de a poco'), ('oguatamimi', 'camina de a poco')]
},
"jepi": {
'descripcion': 'Modo habitual-usual (suele, acostumbra). Marca acción habitual o costumbre. Equivale a "suele", "acostumbra". Términos relacionados: habitual, suele, acostumbra, usual, consuetudinario.',
'ejemplos': [('oguatájepi', 'suele caminar'), ('okarujepi', 'suele comer')]
},
"jepe": {
'descripcion': 'Modo concesivo-antelativo (aunque, a pesar de). Marca concesión o contraste. Equivale a "aunque", "a pesar de". Términos relacionados: concesivo, aunque, a pesar de, contraste, adversativo.',
'ejemplos': [('ojerurejepe', 'aunque pidió'), ('ohójepe', 'aunque fue')]
},
"nipo": {
'descripcion': 'Modo epistémico supositivo (supongo que, probablemente). Marca suposición o probabilidad. Equivale a "supongo que", "probablemente". Términos relacionados: supositivo, supongo, probablemente, epistémico, conjetural.',
'ejemplos': [('oguerúnipo', 'supongo que trae'), ('oúnipo', 'supongo que viene')]
},
"pipo": {
'descripcion': 'Modo epistémico supositivo alternativo (supongo que, tal vez). Marca suposición, variante de nipo. Equivale a "supongo que", "tal vez". Términos relacionados: supositivo alternativo, supongo, tal vez, conjetural.',
'ejemplos': [('ohópipo', 'supongo que fue'), ('oikuaápipo', 'supongo que sabe')]
},
"katu": {
'descripcion': 'Modo confirmativo-verificado (efectivamente, realmente sí). Marca confirmación o verificación enfática. Equivale a "efectivamente", "sí que". Términos relacionados: confirmativo, efectivamente, realmente sí, verificado.',
'ejemplos': [('ohókatu', 'efectivamente fue'), ('oúkatu', 'efectivamente vino')]
},
"niko": {
'descripcion': 'Modo evidencial narrativo verosímil (es verdad que, realmente). Marca información verificada en narración. Equivale a "es verdad que", "realmente". Términos relacionados: evidencial verosímil, es verdad, narrativo confiable.',
'ejemplos': [('ohóniko', 'fue (es verdad)'), ('ojaponiko', 'hizo (es verdad)')]
},
"anga": {
'descripcion': 'Modo pietativo-compasivo (pobrecito, lamentablemente). Expresa lástima o compasión hacia el sujeto. Equivale a "pobrecito", modo compasivo. Términos relacionados: pietativo, compasivo, pobrecito, lástima, empatía.',
'ejemplos': [("ohejá'anga", 'pobrecito dejó'), ("okañy'anga", 'pobrecito se perdió')]
},
"ramo": {
'descripcion': 'Modo condicional existencial o identitativo (si fuera). Marca condición de identidad o existencia. Equivale a "si fuera", condicional ser/estar. Términos relacionados: condicional existencial, si fuera, condicional identitativo.',
'ejemplos': [('ndéveramo', 'si fuera por ti'), ("ha'éramo", 'si fuera él')]
},
"guasu": {
'descripcion': 'Grado aumentativo (grande, muy grande). Marca aumento de tamaño o intensidad. Equivale a "grande", aumentativo. Términos relacionados: aumentativo, grande, grandote, intensificador de tamaño.',
'ejemplos': [('tujaguasu', 'muy viejo'), ('óguasu', 'casona')]
},
"ngue": {
'descripcion': 'Nominal temporal pasado (ex-, antiguo). Marca sustantivo que dejó de ser. Equivale a "ex-", "antiguo". Términos relacionados: ex, antiguo, pasado nominal, ya no es.',
'ejemplos': [('tembiapo ngue', 'ex-trabajo'), ('tembireko ngue', 'ex-esposa')]
},
"piko": {
'descripcion': 'Marcador interrogativo enfático (¿acaso?, ¿será que?). Forma preguntas con matiz de duda o sorpresa. Equivale a "¿acaso?", interrogativo enfático. Términos relacionados: interrogativo enfático, acaso, será que, pregunta dubitativa.',
'ejemplos': [('rejúpiko', '¿acaso vienes?'), ('reikuaápiko', '¿acaso sabes?')]
},
"tiko": {
'descripcion': 'Marcador interrogativo simple (¿...?). Forma preguntas simples. Equivale a signo de interrogación. Términos relacionados: interrogativo, pregunta, interrogación simple.',
'ejemplos': [('rejútiko', '¿vienes?'), ('rehótiko', '¿vas?')]
},
"icha": {
'descripcion': 'Modo comparativo de similaridad ecuativo (como, igual que). Marca comparación de igualdad o similitud. Equivale a "como", "igual que". Términos relacionados: comparativo ecuativo, como, igual que, similaridad, símil.',
'ejemplos': [('nde icha', 'como tú'), ('jagua icha', 'como un perro')]
},
"'ive": {
'descripcion': 'Grado comparativo de inferioridad (menos, menos que). Marca comparación inferior. Equivale a "menos", comparativo de inferioridad. Términos relacionados: comparativo inferior, menos, menos que, inferioridad.',
'ejemplos': [("iporã'ive", 'menos bonito'), ("hatã'ive", 'menos duro')]
},
"guive": {
'descripcion': 'Posposición temporal-locativa ablativa (desde, a partir de). Marca punto de origen temporal o espacial. Equivale a "desde", ablativo. Términos relacionados: desde, a partir de, origen, ablativo, punto de partida.',
'ejemplos': [("ko'ãga guive", 'desde ahora'), ('upe ára guive', 'desde ese día')]
},
"peve": {
'descripcion': 'Posposición temporal-locativa terminativa (hasta, límite). Marca punto final temporal o espacial. Equivale a "hasta", terminativo. Términos relacionados: hasta, límite, terminativo, punto final.',
'ejemplos': [("ko'ẽrõ peve", 'hasta mañana'), ('pyhare peve', 'hasta la noche')]
},
"meve": {
'descripcion': 'Posposición terminativa nasal (hasta). Marca límite temporal o espacial, variante nasal. Equivale a "hasta" (nasal). Términos relacionados: hasta nasal, límite nasal, terminativo nasal.',
'ejemplos': [('ñembyahýi meve', 'hasta el hambre'), ('tesãi meve', 'hasta la salud')]
},
"ndive": {
'descripcion': 'Posposición comitativa (con, junto a). Marca compañía o instrumento. Equivale a "con", comitativo. Términos relacionados: comitativo, con, junto a, compañía, instrumental.',
'ejemplos': [('che ndive', 'conmigo'), ('isy ndive', 'con su madre')]
},
"rehe": {
'descripcion': 'Posposición referencial-causal (por, sobre, acerca de). Marca referencia, causa o tema. Equivale a "por", "sobre", "acerca de". Términos relacionados: referencial, causal, por, sobre, acerca de, tema.',
'ejemplos': [('ore rehe', 'por nosotros'), ('nde rehe', 'por ti')]
},
"rupi": {
'descripcion': 'Posposición trayectiva-perlativa (por, a través de). Marca trayecto o paso. Equivale a "por", "a través de", perlativo. Términos relacionados: trayectivo, perlativo, por, a través de, mediante.',
'ejemplos': [('tape rupi', 'por el camino'), ("ka'aguy rupi", 'por el monte')]
},
"rire": {
'descripcion': 'Posposición temporal posterior (después de). Marca secuencia temporal posterior. Equivale a "después de", posterioridad. Términos relacionados: después de, posterior, secuencia temporal, consecutivo.',
'ejemplos': [('okaru rire', 'después de comer'), ('oké rire', 'después de dormir')]
},
"gotyo": {
'descripcion': 'Posposición direccional alativa (hacia, rumbo a). Marca dirección o destino. Equivale a "hacia", alativo. Términos relacionados: direccional, hacia, rumbo a, alativo, destino.',
'ejemplos': [('yvága gotyo', 'hacia el cielo'), ('óga gotyo', 'hacia la casa')]
},
"hag̃ua": {
'descripcion': 'Posposición final o propositiva verbal (para + infinitivo). Marca propósito o finalidad con verbos. Equivale a "para" + infinitivo, final. Términos relacionados: final, propósito, para infinitivo, objetivo, finalidad.',
'ejemplos': [('okaru hag̃ua', 'para comer'), ("oñe'ẽ hag̃ua", 'para hablar')]
},
"guarã": {
'descripcion': 'Posposición benefactiva o dativa (para + sustantivo). Marca beneficiario o destinatario con sustantivos. Equivale a "para" + sustantivo, dativo. Términos relacionados: benefactivo, dativo, para sustantivo, destinatario, beneficiario.',
'ejemplos': [('che ao guarã', 'para mi ropa'), ('nde guarã', 'para ti')]
},
"uka": {
'descripcion': 'Voz mediativa o delegativa (hace hacer por otro). Marca acción delegada a tercero. Equivale a "hacer hacer", causativo indirecto. Términos relacionados: mediativo, delegativo, hacer hacer por otro, causativo indirecto.',
'ejemplos': [('ojapouka', 'hace hacer por otro'), ('ombotyuka', 'hace cerrar por otro')]
},
"kue": {
'descripcion': 'Nominal temporal pasado posesivo (ex-, mi antiguo). Marca posesión pasada que ya no existe. Equivale a "mi ex-", "mi antiguo". Términos relacionados: ex posesivo, mi antiguo, posesión pasada.',
'ejemplos': [('cheaokue', 'mi ex-ropa'), ('cheógakue', 'mi ex-casa')]
},
"eta": {
'descripcion': 'Marcador de plural abundante (muchos, gran cantidad). Pluralizador con énfasis en abundancia. Equivale a "muchos", plural abundante. Términos relacionados: plural abundante, muchos, abundancia, gran cantidad.',
'ejemplos': [('kavajueta', 'muchos caballos'), ('mbarakajeta', 'muchos gatos')]
},
"ita": {
'descripcion': 'Marcador de plural abundante alternativo (muchos). Pluralizador abundante, variante de eta. Equivale a "muchos", plural numeroso. Términos relacionados: plural abundante alternativo, muchos, numerosos.',
'ejemplos': [('jaguaita', 'muchos perros'), ('guyraita', 'muchos pájaros')]
},
"ári": {
'descripcion': 'Posposición locativa superesiva (sobre, encima de). Marca ubicación superior. Equivale a "sobre", "encima", superesivo. Términos relacionados: locativo superior, sobre, encima, superesivo.',
'ejemplos': [('mesa ári', 'sobre la mesa'), ('yvy ári', 'sobre la tierra')]
},
"jey": {
'descripcion': 'Modo reiterativo-repetitivo (de nuevo, otra vez). Marca acción repetida. Equivale a "de nuevo", "otra vez", reiterativo. Términos relacionados: reiterativo, de nuevo, otra vez, repetición.',
'ejemplos': [('ojapojey', 'hace de nuevo'), ('ohójey', 'va de nuevo')]
},
"joa": {
'descripcion': 'Modo colectivo o socio-común (juntos, en grupo). Marca acción colectiva o compartida. Equivale a "juntos", colectivo. Términos relacionados: colectivo, juntos, en grupo, conjunto, compartido.',
'ejemplos': [("ovy'ajoa", 'se alegran juntos'), ('okañyjoa', 'se pierden juntos')]
},
"nte": {
'descripcion': 'Modo inmotivado o gratuito (sin motivo, porque sí). Marca acción sin razón aparente. Equivale a "sin motivo", "porque sí". Términos relacionados: inmotivado, sin motivo, sin razón, gratuito.',
'ejemplos': [("opytu'únte", 'descansa sin motivo'), ('ohónte', 'va sin motivo')]
},
"ngy": {
'descripcion': 'Modo cuasiaccional o simulativo (medio, casi). Marca acción incompleta o parcial. Equivale a "medio", "casi", cuasi-acción. Términos relacionados: cuasiaccional, medio, casi, parcial, incompleto.',
'ejemplos': [('oguatangy', 'medio camina'), ('okevy', 'medio duerme')]
},
"mba": {
'descripcion': 'Modo totalitativo o completivo exhaustivo (todo, completamente). Marca totalidad o exhaustividad de la acción. Equivale a "todo", completivo total. Términos relacionados: totalitativo, todo, completamente, exhaustivo, total.',
'ejemplos': [('osẽmba', 'sale todo'), ('okañymba', 'se pierde todo')]
},
"rei": {
'descripcion': 'Modo frustrativo o vano (en vano, inútilmente). Marca acción sin resultado exitoso. Equivale a "en vano", "inútilmente", frustrativo. Términos relacionados: frustrativo, en vano, inútilmente, sin resultado.',
'ejemplos': [('okyhyjerei', 'tiene miedo en vano'), ("oñeha'ãrei", 'se esfuerza en vano')]
},
"míme": {
'descripcion': 'Posposición limitativa leve (en/a un poco). Marca límite o extensión reducida. Equivale a "un poco", limitativo. Términos relacionados: limitativo, un poco, levemente, límite reducido.',
'ejemplos': [('ohómíme', 'va un poco'), ('oúmíme', 'viene un poco')]
},
"gui": {
'descripcion': 'Posposición ablativa-separativa (de, desde, procedente de). Marca origen o separación. Equivale a "de", "desde", ablativo. Términos relacionados: ablativo, de, desde, origen, procedencia.',
'ejemplos': [('Paraguaýgui', 'de Paraguay'), ('ógagui', 'de la casa')]
},
"ndi": {
'descripcion': 'Posposición comitativa alternativa (con). Marca compañía, variante de ndive. Equivale a "con", comitativo. Términos relacionados: comitativo alternativo, con, compañía.',
'ejemplos': [('chendi', 'conmigo'), ('hendi', 'con él/ella')]
},
"rõ": {
'descripcion': 'Modo condicional hipotético (si + subjuntivo). Marca condición hipotética. Equivale a "si" + subjuntivo, condicional. Términos relacionados: condicional, si, hipótesis, subjuntivo condicional.',
'ejemplos': [('ojapórõ', 'si hace'), ('ohórõ', 'si va')]
},
"rã": {
'descripcion': 'Nominal temporal futuro prospectivo (futuro, próximo). Marca sustantivo con proyección futura. Equivale a "futuro", prospectivo. Términos relacionados: futuro nominal, prospectivo, futuro sustantivo.',
'ejemplos': [('cheaorã', 'mi futura ropa'), ('cheógara', 'mi futura casa')]
},
"se": {
'descripcion': 'Modo volitivo desiderativo (quiere, desea). Marca voluntad o deseo de realizar la acción. Equivale a "quiere" + infinitivo. Términos relacionados: volitivo, quiere, desea, voluntad, deseo.',
'ejemplos': [('ojapóse', 'quiere hacer'), ('ohóse', 'quiere ir')]
},
"pa": {
'descripcion': 'Modo totalitativo exhaustivo (todo, completamente). Marca realización total de la acción. Equivale a "todo", completivo. Términos relacionados: totalitativo, todo, completamente, exhaustivo.',
'ejemplos': [('ojapópa', 'hace todo'), ('oguatápa', 'camina todo')]
},
"vy": {
'descripcion': 'Modo cuasiaccional gradual (medio, parcialmente). Marca acción parcial o atenuada. Equivale a "medio", cuasi. Términos relacionados: cuasiaccional, medio, parcialmente, atenuado.',
'ejemplos': [('okevy', 'medio duerme'), ('ombovyvy', 'medio calienta')]
},
"ha": {
'descripcion': 'Nominalizador locativo-instrumental (donde, con qué). Convierte verbo en lugar o instrumento de acción. Equivale a "donde", locativo. Términos relacionados: nominalizador locativo, donde, lugar de acción, instrumental.',
'ejemplos': [('ojekoha', 'donde vive'), ('oñembyatyha', 'donde se reúne')]
},
"vo": {
'descripcion': 'Modo concomitante-temporal simultáneo (mientras, al + infinitivo). Marca simultaneidad de acciones. Equivale a "mientras", "al" + infinitivo, gerundio temporal. Términos relacionados: concomitante, mientras, simultáneo, al mismo tiempo, gerundio temporal.',
'ejemplos': [('ohechávo', 'mientras ve'), ('oguatávo', 'mientras camina')]
},
"va": {
'descripcion': 'Nominalizador agentivo-relativizador (el que, quien). Convierte verbo en sustantivo agente o cláusula relativa. Equivale a "el que", relativo. Términos relacionados: nominalizador agentivo, el que, quien, agente, relativo, participio activo.',
'ejemplos': [('oguatáva', 'el que camina'), ("oñe'ẽva", 'el que habla')]
},
"mo": {
'descripcion': 'Modo condicional subjuntivo (si + imperfecto subjuntivo). Marca condición irreal o hipotética. Equivale a "si" + imperfecto subjuntivo. Términos relacionados: condicional subjuntivo, si imperfecto, hipótesis irreal, contrafactual.',
'ejemplos': [('ohejámo', 'si dejara'), ('ohómo', 'si fuera')]
},
"ma": {
'descripcion': 'Modo aseverativo-confirmativo temporal (ya). Marca acción ya realizada o confirmada. Equivale a "ya", perfectivo enfático. Términos relacionados: aseverativo, ya, confirmativo, acción cumplida.',
'ejemplos': [('oguerúma', 'ya trajo'), ('ohóma', 'ya fue')]
},
"po": {
'descripcion': 'Modo epistémico supositivo breve (supongo). Marca suposición, forma corta. Equivale a "supongo", epistémico. Términos relacionados: supositivo, supongo, conjetura, epistémico.',
'ejemplos': [('ohópo', 'supongo que fue'), ('oúpo', 'supongo que vino')]
},
"je": {
'descripcion': 'Modo evidencial reportativo dubitativo (dicen). Marca información reportada con distancia epistémica. Equivale a "dicen que", evidencial. Términos relacionados: evidencial, dicen que, reportativo, información ajena.',
'ejemplos': [('ohóje', 'dicen que fue'), ('oúje', 'dicen que vino')]
},
"ko": {
'descripcion': 'Modo evidencial narrativo aseverativo (es verdad). Marca información verificada en narración. Equivale a "es verdad", evidencial confiable. Términos relacionados: evidencial aseverativo, es verdad, narrativo verificado.',
'ejemplos': [('ohóko', 'fue (es verdad)'), ('oúko', 'vino (es verdad)')]
},
"ve": {
'descripcion': 'Grado comparativo de superioridad (más, más que). Marca comparación superior. Equivale a "más", comparativo de superioridad. Términos relacionados: comparativo superior, más, más que, superioridad.',
'ejemplos': [('iporãve', 'más bonito'), ('hatãve', 'más duro')]
},
"ke": {
'descripcion': 'Imperativo conminativo enfático (¡hazlo!). Marca mandato fuerte o urgente. Equivale a imperativo enfático. Términos relacionados: imperativo enfático, orden fuerte, mandato urgente, conminativo.',
'ejemplos': [('eguatáke', '¡camina!'), ('ejapóke', '¡hacé!')]
},
"na": {
'descripcion': 'Imperativo rogativo atenuado (por favor). Marca petición cortés en imperativo. Equivale a "por favor", imperativo suave. Términos relacionados: imperativo cortés, por favor, petición suave, rogativo.',
'ejemplos': [('ehejána', 'deja por favor'), ('ejúna', 'ven por favor')]
},
"mi": {
'descripcion': 'Partícula atenuativa o enfática pragmática (pues, entonces). Marca atenuación o énfasis pragmático. Equivale a "pues", "entonces". Términos relacionados: atenuativo, pues, entonces, pragmático.',
'ejemplos': [('ejoguami', 'compra pues'), ('ehómi', 'anda pues')]
},
"pe": {
'descripcion': 'Posposición locativa-dativa alativa (a, en, hacia). Marca ubicación o destino. Equivale a "a", "en", locativo-dativo. Términos relacionados: locativo, dativo, a, en, ubicación, destino.',
'ejemplos': [('ógape', 'a/en la casa'), ('chéve pe', 'a mí')]
},
"me": {
'descripcion': 'Posposición locativa-dativa nasal (a, en). Marca ubicación o destino, variante nasal. Equivale a "a", "en" (nasal). Términos relacionados: locativo nasal, dativo nasal, a nasal, en nasal.',
'ejemplos': [('ñúme', 'al campo'), ('tendáme', 'al lugar')]
},
"re": {
'descripcion': 'Posposición causal-referencial (por, a causa de). Marca causa o referencia. Equivale a "por", causal. Términos relacionados: causal, por, a causa de, referencial, razón.',
'ejemplos': [('ndére', 'por ti'), ("mba'ére", '¿por qué?')]
},
"ta": {
'descripcion': 'Tiempo futuro simple predictivo (hará, va a hacer). Marca acción futura simple. Equivale a futuro simple. Términos relacionados: futuro simple, hará, futuro predictivo.',
'ejemplos': [('oguatáta', 'caminará'), ('ojapóta', 'hará')]
},
"ne": {
'descripcion': 'Modo epistémico dubitativo (quizás, tal vez). Marca duda o incertidumbre. Equivale a "quizás", "tal vez", dubitativo. Términos relacionados: dubitativo, quizás, tal vez, incertidumbre, duda.',
'ejemplos': [('ojohéine', 'quizás lave'), ('ohóne', 'quizás vaya')]
},
}
def normalizar_palabra(palabra: str, quitar_acentos: bool = False) -> str:
"""Normaliza una palabra para comparación."""
resultado = palabra.lower().strip()
# Normalizar caracteres especiales
resultado = resultado.replace('ꞌ', "'")
resultado = resultado.replace('\u2019', "'")
resultado = resultado.replace('\u2018', "'")
resultado = resultado.replace('´', "'")
if quitar_acentos:
acentos = {
'á': 'a', 'é': 'e', 'í': 'i', 'ó': 'o', 'ú': 'u', 'ý': 'y',
'à': 'a', 'è': 'e', 'ì': 'i', 'ò': 'o', 'ù': 'u',
}
for acentuado, sin_acento in acentos.items():
resultado = resultado.replace(acentuado, sin_acento)
return resultado
class TrieNode:
__slots__ = ['children', 'is_end', 'weight']
def __init__(self):
self.children = {}
self.is_end = False
self.weight = 0.0
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word, weight=1.0):
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True
node.weight = weight
def search_from(self, text, start):
"""Retorna lista de (longitud, peso) de matches desde posición start"""
matches = []
node = self.root
for i in range(start, len(text)):
char = text[i]
if char not in node.children:
break
node = node.children[char]
if node.is_end:
matches.append((i - start + 1, node.weight))
return matches
class SegmentadorMorfologico:
# Pesos del sistema
PESO_RAIZ = 20.0
PESO_PREFIJO = 2.0
PESO_SUFIJO = 2.0
PESO_CIRCUNFIJO = 3.0
PENALIZACION_SIN_RAIZ = -10000.0
PENALIZACION_MULTIPLES_RAICES = -10000.0
PENALIZACION_FRAGMENTACION = 0
BONUS_RAIZ_LARGA = 3.0
BONUS_ESTRUCTURA_COMPLETA = 2.0
PENALIZACION_POR_SEGMENTO = -1.5
def __init__(self, raices, prefijos, sufijos, circunfijos, dic_gua_es=None, dic_es_gua=None):
self.trie_raices = Trie()
self.trie_prefijos = Trie()
self.trie_sufijos = Trie()
self.trie_circunfijos_inicio = Trie()
self.trie_circunfijos_fin = Trie()
# Diccionarios para búsqueda de raíces
self.dic_gua_es = dic_gua_es if dic_gua_es else []
self.dic_es_gua = dic_es_gua if dic_es_gua else []
self.usar_diccionarios = bool(dic_gua_es or dic_es_gua)
# Mapeo de inicio -> posibles fines para validación
self.circunfijos_map = {}
self.prefijos_ordenados = sorted(PREFIJOS_GUARANI.keys(), key=len, reverse=True)
self.sufijos_ordenados = sorted(SUFIJOS_GUARANI.keys(), key=len, reverse=True)
self.raices_validas = set()
for entrada in self.dic_gua_es + self.dic_es_gua:
clave = re.split(r'[=\s\(,]', entrada)[0]
clave_norm = normalizar_palabra(
self._normalizar_clave(clave),
quitar_acentos=True
)
self.raices_validas.add(clave_norm)
# Preconstruir set de sufijos normalizados para excluirlos de raíces
self.sufijos_set = set()
for sufijo in SUFIJOS_GUARANI.keys():
sufijo_norm = normalizar_palabra(
self._normalizar_clave(sufijo),
quitar_acentos=True
)
self.sufijos_set.add(sufijo_norm)
# Preconstruir set de prefijos normalizados
self.prefijos_set = set()
for prefijo in PREFIJOS_GUARANI.keys():
prefijo_norm = normalizar_palabra(
self._normalizar_clave(prefijo),
quitar_acentos=True
)
self.prefijos_set.add(prefijo_norm)
for raiz in raices:
raiz_norm = normalizar_palabra(raiz, quitar_acentos=True)
self.trie_raices.insert(raiz_norm, self.PESO_RAIZ)
for prefijo in prefijos:
prefijo_norm = normalizar_palabra(prefijo, quitar_acentos=True)
self.trie_prefijos.insert(prefijo_norm, self.PESO_PREFIJO)
prefijo_orig = normalizar_palabra(prefijo, quitar_acentos=False)
if prefijo_orig != prefijo_norm:
self.trie_prefijos.insert(prefijo_orig, self.PESO_PREFIJO)
for sufijo in sufijos:
sufijo_norm = normalizar_palabra(sufijo, quitar_acentos=True)
# Insertar tanto con acento como sin acento
self.trie_sufijos.insert(sufijo_norm, self.PESO_SUFIJO)
# Si el original es diferente, insertarlo también
sufijo_orig = normalizar_palabra(sufijo, quitar_acentos=False)
if sufijo_orig != sufijo_norm:
self.trie_sufijos.insert(sufijo_orig, self.PESO_SUFIJO)
for circunfijo in circunfijos:
if '-' in circunfijo:
inicio, fin = circunfijo.split('-', 1)
self.trie_circunfijos_inicio.insert(inicio, self.PESO_CIRCUNFIJO)
self.trie_circunfijos_fin.insert(fin, self.PESO_CIRCUNFIJO)
if inicio not in self.circunfijos_map:
self.circunfijos_map[inicio] = set()
self.circunfijos_map[inicio].add(fin)
# =========================
# Mapas de descripciones
# =========================
self.desc_prefijos = {}
self.desc_sufijos = {}
self.desc_circunfijos = {}
# Prefijos (guardar versión normalizada y original)
for k, v in PREFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.desc_prefijos[k1] = v.get("descripcion", "")
self.desc_prefijos[k2] = v.get("descripcion", "")
# Sufijos (guardar versión normalizada y original)
for k, v in SUFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.desc_sufijos[k1] = v.get("descripcion", "")
self.desc_sufijos[k2] = v.get("descripcion", "")
# Circunfijos (clave tipo "nd-i")
for k, v in CIRCUNFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.desc_circunfijos[k1] = v.get("descripcion", "")
self.desc_circunfijos[k2] = v.get("descripcion", "")
self.ej_prefijos = {}
self.ej_sufijos = {}
self.ej_circunfijos = {}
# Prefijos
for k, v in PREFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.ej_prefijos[k1] = v.get("ejemplos", [])
self.ej_prefijos[k2] = v.get("ejemplos", [])
# Sufijos
for k, v in SUFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.ej_sufijos[k1] = v.get("ejemplos", [])
self.ej_sufijos[k2] = v.get("ejemplos", [])
# Circunfijos (clave "nd-i")
for k, v in CIRCUNFIJOS_GUARANI.items():
k1 = normalizar_palabra(k, quitar_acentos=True)
k2 = normalizar_palabra(k, quitar_acentos=False)
self.ej_circunfijos[k1] = v.get("ejemplos", [])
self.ej_circunfijos[k2] = v.get("ejemplos", [])
def buscar_raiz_en_diccionarios(self, palabra, start, max_length=None):
"""Busca raíz en diccionarios con coincidencias de palabra completa"""
if not self.usar_diccionarios:
return []
matches = []
max_len = max_length if max_length else len(palabra) - start
chars_palabra = "a-záéíóúãẽĩõũỹàèìòùýñꞌ'\\-"
# mínimo 2 caracteres para evitar demasiado ruido
for length in range(2, max_len + 1):
substring = palabra[start:start + length].lower()
pattern = re.compile(
rf"(?<![{chars_palabra}]){re.escape(substring)}(?![{chars_palabra}])"
)
resultados = [] # (peso, fila, diccionario)
for entrada in self.dic_gua_es:
entrada_lower = entrada.lower()
match = pattern.search(entrada_lower)
if match:
pos = match.start()
if pos <= 10:
peso = 100 - pos
elif pos <= 50:
peso = 90 - (pos - 10)
else:
peso = max(10, 50 - (pos - 50) // 2)
resultados.append((peso, entrada, "gn-es"))
for entrada in self.dic_es_gua:
entrada_lower = entrada.lower()
match = pattern.search(entrada_lower)
if match:
pos = match.start()
if pos <= 10:
peso = 100 - pos
elif pos <= 50:
peso = 90 - (pos - 10)
else:
peso = max(10, 50 - (pos - 50) // 2)
resultados.append((peso, entrada, "es-gn"))
if resultados:
resultados.sort(reverse=True, key=lambda x: x[0])
mejor_peso = resultados[0][0]
peso_normalizado = self.PESO_RAIZ * (mejor_peso / 100.0)
top_resultados = resultados[:5]
matches.append((length, peso_normalizado, top_resultados))
return matches
def _matchear_prefijos(self, texto: str) -> list:
resultado = []
pos = 0
texto_norm = normalizar_palabra(texto, quitar_acentos=True) # ← normalizar
while pos < len(texto_norm):
match = None
for prefijo in self.prefijos_ordenados:
prefijo_norm = normalizar_palabra(prefijo, quitar_acentos=True)
if texto_norm[pos:].startswith(prefijo_norm):
match = prefijo_norm
break
if match:
resultado.append(match)
pos += len(match)
else:
return []
return resultado
def _matchear_sufijos(self, texto: str) -> list:
resultado = []
pos = 0
texto_norm = normalizar_palabra(texto, quitar_acentos=True) # ← normalizar
while pos < len(texto_norm):
match = None
for sufijo in self.sufijos_ordenados:
sufijo_norm = normalizar_palabra(sufijo, quitar_acentos=True)
if texto_norm[pos:].startswith(sufijo_norm):
match = sufijo_norm
break
if match:
resultado.append(match)
pos += len(match)
else:
return []
return resultado
def _normalizar_clave(self, texto: str) -> str:
"""Normaliza apóstrofes y minúsculas para comparación."""
return (texto.lower()
.replace('ꞌ', "'")
.replace('\u2019', "'")
.replace('\u2018', "'")
.replace('´', "'")
.strip())
def _es_raiz_valida(self, texto: str) -> bool:
norm = normalizar_palabra(
self._normalizar_clave(texto),
quitar_acentos=True
)
# Excluir sufijos y prefijos conocidos
if norm in self.sufijos_set or norm in self.prefijos_set:
return False
# Trie
matches = self.trie_raices.search_from(norm, 0)
if any(length == len(norm) for length, _ in matches):
return True
# Set lookup O(1)
if self.usar_diccionarios:
return norm in self.raices_validas
return False
def _buscar_raiz_con_afijos(self, palabra: str) -> list | None:
n = len(palabra)
mejor = None
mejor_raiz_len = 0 # ← priorizar raíz más larga
for inicio_raiz in range(n):
for fin_raiz in range(n, inicio_raiz + 1, -1):
raiz_candidata = palabra[inicio_raiz:fin_raiz]
raiz_len = fin_raiz - inicio_raiz
# Si ya tenemos una raíz más larga, skip
if raiz_len < mejor_raiz_len:
continue
if not self._es_raiz_valida(raiz_candidata):
continue
prefijos = self._matchear_prefijos(palabra[:inicio_raiz])
sufijos = self._matchear_sufijos(palabra[fin_raiz:])
cubierto = (
sum(len(p) for p in prefijos) == inicio_raiz and
sum(len(s) for s in sufijos) == n - fin_raiz
)
if cubierto:
segmentacion = (
[("PRE", p) for p in prefijos] +
[("RAIZ", raiz_candidata)] +
[("SUF", s) for s in sufijos]
)
# Priorizar: 1ro raíz más larga, 2do menos morfemas
if (raiz_len > mejor_raiz_len or
(raiz_len == mejor_raiz_len and len(segmentacion) < len(mejor))):
mejor = segmentacion
mejor_raiz_len = raiz_len
return mejor
def segmentar_greedy(self, palabra: str) -> dict:
n = len(palabra)
mejor = None
circunfijos_ordenados = sorted(
self.circunfijos_map.items(),
key=lambda x: len(x[0]),
reverse=True
)
# ── CASO 1: con circunfijo ──
for circ_ini, fines_validos in circunfijos_ordenados:
if not palabra.startswith(circ_ini):
continue
interior_y_resto = palabra[len(circ_ini):]
for circ_fin in sorted(fines_validos, key=len, reverse=True):
# Buscar circ_fin en CUALQUIER posición (no solo al final)
pos = interior_y_resto.find(circ_fin)
while pos != -1:
interior = interior_y_resto[:pos]
resto = interior_y_resto[pos + len(circ_fin):]
if not interior:
pos = interior_y_resto.find(circ_fin, pos + 1)
continue
# Sufijos después del CIRC_FIN
sufijos_post = self._matchear_sufijos(resto)
if resto and not sufijos_post:
pos = interior_y_resto.find(circ_fin, pos + 1)
continue
# Buscar raíz + prefijos en el interior
resultado_interior = self._buscar_raiz_con_afijos(interior)
if resultado_interior is None:
pos = interior_y_resto.find(circ_fin, pos + 1)
continue
segmentacion = (
[("CIRC_INI", circ_ini)] +
resultado_interior +
[("CIRC_FIN", circ_fin)] +
[("SUF", s) for s in sufijos_post]
)
if mejor is None or len(segmentacion) < len(mejor):
mejor = segmentacion
pos = interior_y_resto.find(circ_fin, pos + 1)
# ── CASO 2: sin circunfijo ──
resultado = self._buscar_raiz_con_afijos(palabra)
if resultado:
if mejor is None or len(resultado) < len(mejor):
mejor = resultado
return mejor
def segmentar(self, palabra: str, top_k: int = 10) -> list:
# 1. Intentar con acentos originales
resultado = self.segmentar_greedy(palabra)
# 2. Fallback sin acentos
palabra_sin_acento = normalizar_palabra(palabra, quitar_acentos=True)
if resultado is None and palabra_sin_acento != palabra:
resultado_norm = self.segmentar_greedy(palabra_sin_acento)
if resultado_norm:
resultado = self._restaurar_acentos(resultado_norm, palabra)
# 3. Fallback final: palabra completa como raíz desconocida
if resultado is None:
resultado = [("RAIZ", palabra)]
score = sum(len(texto) for _, texto in resultado) - len(resultado) * 1.5
return [(score, resultado, {})]
def _segmentar_substring(self, substring, top_k=10):
"""Segmenta una subcadena (usado para contenido de circunfijos)"""
n = len(substring)
dp = [[] for _ in range(n + 1)]
dp[n] = [(0.0, [], False, {})]
for i in range(n - 1, -1, -1):
candidatos = []
# Prefijos
for length, weight in self.trie_prefijos.search_from(substring, i):
for score, seg, tiene_raiz, meta in dp[i + length]:
if not tiene_raiz:
continue
nuevo_score = score + weight + self.PENALIZACION_FRAGMENTACION
nueva_seg = [('PRE', substring[i:i+length])] + seg
candidatos.append((nuevo_score, nueva_seg, tiene_raiz, meta))
# Raíces del Trie
for length, weight in self.trie_raices.search_from(substring, i):
for score, seg, tiene_raiz, meta in dp[i + length]:
if tiene_raiz:
continue
bonus_longitud = length * self.BONUS_RAIZ_LARGA
nuevo_score = score + weight + bonus_longitud + self.PENALIZACION_FRAGMENTACION
nueva_seg = [('RAIZ', substring[i:i+length])] + seg
nuevo_meta = meta.copy()
nuevo_meta['raiz_source'] = 'trie'
candidatos.append((nuevo_score, nueva_seg, True, nuevo_meta))
# Raíces de diccionarios
if self.usar_diccionarios:
for length, weight, dic_matches in self.buscar_raiz_en_diccionarios(substring, i):
for score, seg, tiene_raiz, meta in dp[i + length]:
if tiene_raiz:
continue
bonus_longitud = length * self.BONUS_RAIZ_LARGA
nuevo_score = score + weight + bonus_longitud + self.PENALIZACION_FRAGMENTACION
nueva_seg = [('RAIZ', substring[i:i+length])] + seg
nuevo_meta = meta.copy()
nuevo_meta['raiz_source'] = 'diccionario'
nuevo_meta['dic_matches'] = dic_matches
candidatos.append((nuevo_score, nueva_seg, True, nuevo_meta))
# Sufijos
for length, weight in self.trie_sufijos.search_from(substring, i):
for score, seg, tiene_raiz, meta in dp[i + length]:
if tiene_raiz:
continue
nuevo_score = score + weight + self.PENALIZACION_FRAGMENTACION
nueva_seg = [('SUF', substring[i:i+length])] + seg
candidatos.append((nuevo_score, nueva_seg, tiene_raiz, meta))
if candidatos:
candidatos.sort(reverse=True, key=lambda x: x[0])
dp[i] = candidatos[:top_k]
# Retornar segmentaciones válidas
resultados = []
for score, seg, tiene_raiz, meta in dp[0]:
longitud_cubierta = sum(len(comp[1]) for comp in seg)
if longitud_cubierta == n:
resultados.append((score, seg, tiene_raiz, meta))
return resultados if resultados else [(0.0, [], False, {})]
# def formatear_resultado(self, resultado):
# """Formatea una segmentación para mostrarla"""
# score, segmentacion, meta = resultado
# partes = []
# for tipo, texto in segmentacion:
# partes.append(f"{texto}[{tipo}]")
# resultado_str = f"{'-'.join(partes)} (score: {score:.2f})"
# # Agregar info de diccionario si existe
# if meta.get('raiz_source') == 'diccionario' and 'dic_matches' in meta:
# resultado_str += "\n Encontrado en diccionarios:"
# for peso, entrada, dic in meta['dic_matches'][:3]: # Top 3
# resultado_str += f"\n [{dic}] {entrada[:80]}..."
# return resultado_str
def formatear_resultado(self, resultado):
"""Formatea una segmentación para mostrarla"""
score, segmentacion, meta = resultado
partes = []
for tipo, texto in segmentacion:
partes.append(f"{texto}[{tipo}]")
# Detectar casos ambiguos
es_ambiguo = False
if len(segmentacion) == 1 and segmentacion[0][0] in ('SUF', 'PRE'):
es_ambiguo = True
resultado_str = f"{'-'.join(partes)} (score: {score:.2f})"
if es_ambiguo:
resultado_str += " ⚠️ AMBIGUO: puede ser palabra independiente"
# Agregar info de diccionario si existe
if meta.get('raiz_source') == 'diccionario' and 'dic_matches' in meta:
resultado_str += "\n Encontrado en diccionarios:"
for peso, entrada, dic in meta['dic_matches'][:3]: # Top 3
resultado_str += f"\n [{dic}] {entrada}..."
return resultado_str
def segmentar_oracion(self, oracion, top_k=3):
import re
oracion = oracion.replace('ꞌ', "'").replace('\u2019', "'").replace('\u2018', "'").replace('´', "'")
# Tokenizar SIN lower() para conservar acentos originales
tokens = re.findall(r"[a-záéíóúãẽĩõũỹàèìòùýñꞌ'\-]+|[^\s\w]", oracion, re.IGNORECASE)
resultados = []
for token in tokens:
if not re.match(r"[a-záéíóúãẽĩõũỹàèìòùýñꞌ'\-]+$", token, re.IGNORECASE):
resultados.append({
'palabra_original': token,
'segmentaciones': [],
'mejor_segmentacion': None,
'es_puntuacion': True
})
continue
# Pasar en minúscula CON acentos — segmentar maneja fallback internamente
palabra = token.lower()
segmentaciones = self.segmentar(palabra, top_k=top_k)
resultados.append({
'palabra_original': token,
'segmentaciones': segmentaciones,
'mejor_segmentacion': segmentaciones[0] if segmentaciones else None,
'es_puntuacion': False
})
return resultados
def formatear_oracion(self, resultado_oracion, mostrar_alternativas=False):
"""
Enumera candidatos de segmentación para cada palabra.
Ya no separa "mejor" y "alternativas": lista todos los candidatos en orden.
"""
def _fmt_ejemplos(ejs, max_ej=2):
if not ejs:
return ""
ejs = ejs[:max_ej]
return " | ".join([f"{gn} = {es}" for (gn, es) in ejs])
def _extraer_descripciones(seg):
"""
Devuelve lista de strings con descripción + ejemplos para morfemas encontrados.
Maneja circunfijo como par CIRC_INI + CIRC_FIN => "ini-fin".
"""
lineas = []
circ_ini = None
for tipo, texto in seg:
if tipo == "PRE":
d = self.desc_prefijos.get(texto, "")
ejs = self.ej_prefijos.get(texto, [])
ej_txt = _fmt_ejemplos(ejs)
if d or ej_txt:
s = f" • {texto} [PRE]: {d}".rstrip()
if ej_txt:
s += f" (ej.: {ej_txt})"
lineas.append(s)
elif tipo == "SUF":
d = self.desc_sufijos.get(texto, "")
ejs = self.ej_sufijos.get(texto, [])
ej_txt = _fmt_ejemplos(ejs)
if d or ej_txt:
s = f" • {texto} [SUF]: {d}".rstrip()
if ej_txt:
s += f" (ej.: {ej_txt})"
lineas.append(s)
elif tipo == "CIRC_INI":
circ_ini = texto
elif tipo == "CIRC_FIN":
if circ_ini:
clave = f"{circ_ini}-{texto}"
d = self.desc_circunfijos.get(clave, "")
ejs = self.ej_circunfijos.get(clave, [])
ej_txt = _fmt_ejemplos(ejs)
if d or ej_txt:
s = f" • {clave} [CIRC]: {d}".rstrip()
if ej_txt:
s += f" (ej.: {ej_txt})"
lineas.append(s)
circ_ini = None
return lineas
lineas = []
for item in resultado_oracion:
if item.get("es_puntuacion"):
continue
palabra = item["palabra_original"]
lineas.append(f"\n== {palabra} ==")
# (Opcional) mostrar origen ganador si viene de segmentar_oracion nuevo
# if "mejor_origen" in item and item["mejor_origen"]:
# lineas.append(f" 🔤 origen: {item['mejor_origen']}")
candidatos = item.get("segmentaciones", [])
if not candidatos:
lineas.append(" ❌ No se encontraron candidatos")
continue
lineas.append("\n # Candidatos:")
for idx, (score, seg, meta) in enumerate(candidatos, 1):
partes = [f"{texto}[{tipo}]" for tipo, texto in seg]
lineas.append(f" {idx}. {'-'.join(partes)} (score: {score:.2f})")
# Morfemas (desc + ejemplos)
descs = _extraer_descripciones(seg)
if descs:
lineas.append(" ## Morfemas:")
lineas.extend([d.replace(" •", " •") for d in descs])
# Diccionario (si aplica)
if meta and meta.get("raiz_source") == "diccionario" and "dic_matches" in meta:
lineas.append(" ## Diccionario:")
for peso, entrada, dic in meta["dic_matches"][:2]:
lineas.append(f" [{dic}] {entrada}.")
return "\n".join(lineas)
"""
Aplicación Gradio para Segmentación Morfológica del Guaraní
Con soporte MCP para integración con LLMs y búsqueda semántica RAG
VERSIÓN COMPLETA Y FUNCIONAL PARA GRADIO 6.0
"""
# ==============================================================================
# IMPORTAR RAG
# ==============================================================================
try:
import faiss
from sentence_transformers import SentenceTransformer
RAG_AVAILABLE = True
except ImportError:
RAG_AVAILABLE = False
print("⚠️ FAISS o SentenceTransformers no disponibles. Instalar: pip install faiss-cpu sentence-transformers")
# ==============================================================================
# CARGAR DICCIONARIOS
# ==============================================================================
try:
with open("./diccionario_guarani_espanol_v2.pkl", "rb") as f:
diccionario_guarani_espanol = pickle.load(f)
with open("./diccionario_espanol_guarani_v2.pkl", "rb") as f:
diccionario_espanol_guarani = pickle.load(f)
print(f"✅ Diccionarios Cargados")
except Exception as e:
print(f"No se pudieron cargar diccionarios externos: {e}")
diccionario_guarani_espanol = []
diccionario_espanol_guarani = []
# ==============================================================================
# CLASE RAG PARA BÚSQUEDA SEMÁNTICA
# ==============================================================================
@dataclass
class Entry:
key: str
kind: str
value: Dict[str, Any]
text: str
def flatten_entry(kind: str, key: str, value: Dict[str, Any]) -> str:
"""Convierte cada entrada a texto rico para embedding."""
desc = value.get("descripcion", "")
ejemplos = value.get("ejemplos", [])
ej_txt = " | ".join([f"{a} -> {b}" for a, b in ejemplos]) if ejemplos else ""
keywords = []
desc_lower = desc.lower()
if "pasado" in desc_lower:
keywords += ["tiempo pasado", "pretérito", "pasado"]
if "futuro" in desc_lower:
keywords += ["tiempo futuro", "futuro simple", "futuro"]
if "negación" in desc_lower or "negacion" in desc_lower:
keywords += ["negación", "negativo", "no", "negar"]
if "posesivo" in desc_lower or "posesión" in desc_lower:
keywords += ["posesión", "mi", "tu", "su", "posesivo"]
if "progresivo" in desc_lower or "gerundio" in desc_lower:
keywords += ["continuo", "gerundio", "estar + gerundio", "progresivo"]
if "primera persona" in desc_lower:
keywords += ["yo", "primera persona", "1ra persona"]
if "tercera persona" in desc_lower:
keywords += ["él", "ella", "tercera persona", "3ra persona"]
if "intensificador" in desc_lower:
keywords += ["muy", "sumamente", "intensidad", "enfático"]
return (
f"tipo: {kind}\n"
f"clave: {key}\n"
f"descripcion: {desc}\n"
f"ejemplos: {ej_txt}\n"
f"keywords: {', '.join(keywords)}"
).strip()
class MorphRAG:
def __init__(self, model_path: str = "./all-MiniLM-L6-v2"):
if not RAG_AVAILABLE:
raise RuntimeError("FAISS y SentenceTransformers son necesarios")
# Cargar modelo local (NO descarga de internet)
print(f"🔄 Cargando modelo desde: {model_path}")
self.model = SentenceTransformer(model_path)
print("✅ Modelo cargado")
self.entries = []
self.index = None
self.dim = None
def build(self,
circunfijos: Dict[str, Dict[str, Any]],
prefijos: Dict[str, Dict[str, Any]],
sufijos: Dict[str, Dict[str, Any]]) -> None:
"""Construye el índice FAISS."""
self.entries = []
def add(kind: str, d: Dict[str, Dict[str, Any]]):
for k, v in d.items():
text = flatten_entry(kind, k, v)
self.entries.append(Entry(key=k, kind=kind, value=v, text=text))
add("CIRCUNFIJO", circunfijos)
add("PREFIJO", prefijos)
add("SUFIJO", sufijos)
corpus = [e.text for e in self.entries]
emb = self.model.encode(corpus, convert_to_numpy=True, normalize_embeddings=True)
self.dim = emb.shape[1]
self.index = faiss.IndexFlatIP(self.dim)
self.index.add(emb.astype(np.float32))
def query(self, q: str, topk: int = 5) -> List[Tuple[float, str, str, Dict[str, Any]]]:
"""Busca morfologías relevantes."""
if self.index is None:
raise RuntimeError("Ejecutá build() primero")
q_emb = self.model.encode([q], convert_to_numpy=True, normalize_embeddings=True).astype(np.float32)
scores, idxs = self.index.search(q_emb, topk)
results = []
for score, idx in zip(scores[0], idxs[0]):
if idx == -1:
continue
e = self.entries[idx]
results.append((float(score), e.kind, e.key, e.value))
return results
# ==============================================================================
# INICIALIZAR SEGMENTADOR Y RAG
# ==============================================================================
segmentador = SegmentadorMorfologico(
raices=[],
prefijos=PREFIJOS_GUARANI.keys(),
sufijos=SUFIJOS_GUARANI.keys(),
circunfijos=CIRCUNFIJOS_GUARANI.keys(),
dic_gua_es=diccionario_guarani_espanol,
dic_es_gua=diccionario_espanol_guarani
)
if RAG_AVAILABLE:
rag = MorphRAG()
rag.build(CIRCUNFIJOS_GUARANI, PREFIJOS_GUARANI, SUFIJOS_GUARANI)
print("✅ Sistema RAG inicializado")
# ==============================================================================
# FUNCIONES PRINCIPALES
# ==============================================================================
def formatear_oracion_simple(resultado_oracion: list) -> str:
palabras_segmentadas = []
for item in resultado_oracion:
if item.get("es_puntuacion"):
palabras_segmentadas.append(item["palabra_original"])
continue
mejor = item.get("mejor_segmentacion")
if mejor is None:
palabras_segmentadas.append(item["palabra_original"])
continue
_, segmentacion, _ = mejor
palabra_original = item["palabra_original"]
# Reconstruir morfemas desde la palabra original (con acentos)
partes = []
pos = 0
for _, texto in segmentacion:
partes.append(palabra_original[pos:pos + len(texto)])
pos += len(texto)
palabras_segmentadas.append("-".join(partes))
return " ".join(palabras_segmentadas)
def segmentar_oracion_simple(oracion: str) -> str:
"""Segmenta una oración en guaraní y retorna los morfemas separados por guiones."""
if not oracion or not oracion.strip():
return "⚠️ Por favor, ingrese una oración para segmentar."
resultado = segmentador.segmentar_oracion(oracion.strip(), top_k=3)
return formatear_oracion_simple(resultado)
def segmentar_oracion(oracion: str, top_k: int = 3, mostrar_alternativas: bool = False) -> str:
"""Segmenta cada palabra de una oración en guaraní."""
if not oracion or not oracion.strip():
return "⚠️ Por favor, ingrese una oración para segmentar."
oracion = oracion.strip()
resultado = segmentador.segmentar_oracion(oracion, top_k=top_k)
return segmentador.formatear_oracion(resultado, mostrar_alternativas=mostrar_alternativas)
def buscar_morfologia_rag(consulta: str, top_k: int = 5) -> str:
"""Busca morfologías usando búsqueda semántica (RAG)."""
if not RAG_AVAILABLE:
return "❌ Sistema RAG no disponible. Instalar: pip install faiss-cpu sentence-transformers"
if not consulta or not consulta.strip():
return "⚠️ Por favor, ingrese una consulta para buscar."
try:
consulta = consulta.strip()
resultados = rag.query(consulta, topk=top_k)
if not resultados:
return f"❌ No se encontraron morfologías para: '{consulta}'"
output_lines = [
f"Consulta: {consulta}",
f"Se encontraron {len(resultados)} morfologías relevantes",
]
for i, (score, kind, key, value) in enumerate(resultados, 1):
icon = "🔄" if kind == "CIRCUNFIJO" else ("⬅️" if kind == "PREFIJO" else "➡️")
desc = value.get("descripcion", "Sin descripción")
ejemplos = value.get("ejemplos", [])
output_lines.append(f"{i}. {kind}: {key}")
output_lines.append(f" * {desc}")
return "\n".join(output_lines)
except Exception as e:
return f"❌ Error al buscar: {str(e)}"
def obtener_info_particula(particula: str) -> str:
"""Obtiene información sobre una partícula guaraní."""
if not particula or not particula.strip():
return "⚠️ Por favor, ingrese una partícula para buscar."
particula = particula.strip().lower()
if particula in CIRCUNFIJOS_GUARANI:
info = CIRCUNFIJOS_GUARANI[particula]
ejemplos = "\n".join([f" • {ej[0]}{ej[1]}" for ej in info['ejemplos']])
return f"🔄 CIRCUNFIJO: {particula}\n\n📖 {info['descripcion']}\n\n📚 Ejemplos:\n{ejemplos}"
if particula in PREFIJOS_GUARANI:
info = PREFIJOS_GUARANI[particula]
ejemplos = "\n".join([f" • {ej[0]}{ej[1]}" for ej in info['ejemplos']])
return f"⬅️ PREFIJO: {particula}\n\n📖 {info['descripcion']}\n\n📚 Ejemplos:\n{ejemplos}"
if particula in SUFIJOS_GUARANI:
info = SUFIJOS_GUARANI[particula]
ejemplos = "\n".join([f" • {ej[0]}{ej[1]}" for ej in info['ejemplos']])
return f"➡️ SUFIJO: {particula}\n\n📖 {info['descripcion']}\n\n📚 Ejemplos:\n{ejemplos}"
return f"❌ No se encontró la partícula '{particula}' en el diccionario.\n\nConsejo: Para circunfijos use el formato 'prefijo-sufijo' (ej: 'nd-i')"
def listar_particulas(tipo: str = "todos") -> str:
"""Lista todas las partículas guaraní disponibles."""
output = []
if tipo in ["circunfijos", "todos"]:
output.append("🔄 CIRCUNFIJOS (negación verbal):")
output.append("-" * 40)
for circ, info in CIRCUNFIJOS_GUARANI.items():
output.append(f" {circ}: {info['descripcion'][:60]}...")
output.append("")
if tipo in ["prefijos", "todos"]:
output.append("⬅️ PREFIJOS:")
output.append("-" * 40)
for pref, info in PREFIJOS_GUARANI.items():
output.append(f" {pref}: {info['descripcion'][:60]}...")
output.append("")
if tipo in ["sufijos", "todos"]:
output.append("➡️ SUFIJOS:")
output.append("-" * 40)
for suf, info in SUFIJOS_GUARANI.items():
output.append(f" {suf}: {info['descripcion'][:60]}...")
return "\n".join(output)
# ==============================================================================
# INTERFAZ GRADIO - COMPATIBLE CON GRADIO 6.0
# ==============================================================================
with gr.Blocks(title="Segmentador Morfológico del Guaraní") as demo:
gr.HTML("""
<style>
.main-title {
text-align: center;
color: #2E7D32;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #666;
font-size: 14px;
margin-bottom: 20px;
}
.output-box {
font-family: 'Courier New', monospace;
font-size: 14px;
}
.rag-info {
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
padding: 20px;
border-radius: 12px;
margin-bottom: 20px;
border-left: 4px solid #2E7D32;
}
</style>
<h1 class='main-title'>🌿 Segmentador Morfológico del Guaraní</h1>
<p class='subtitle'>Análisis morfológico con búsqueda semántica inteligente (RAG)</p>
""")
with gr.Tabs():
# Tab 1: Segmentar Oración
with gr.TabItem("📝 Segmentar Oración", id=1):
gr.Markdown("### Ingrese una oración en guaraní para analizar cada palabra")
with gr.Row():
with gr.Column(scale=2):
input_oracion = gr.Textbox(
label="Oración en Guaraní",
placeholder="Ej: Che aguatatahína ko'ẽrõ",
lines=2,
value="Che aguatatahína ko'ẽrõ"
)
with gr.Column(scale=1):
top_k_oracion = gr.Slider(
minimum=1,
maximum=10,
value=3,
step=1,
label="Alternativas por palabra"
)
mostrar_alt = gr.Checkbox(
label="Mostrar alternativas",
value=True
)
btn_oracion = gr.Button("🔍 Analizar Oración", variant="primary", size="lg")
output_oracion = gr.Textbox(
label="Resultado del Análisis",
lines=15,
elem_classes=["output-box"]
)
btn_oracion_simple = gr.Button("✂️ Segmentación Simple", variant="secondary", size="lg")
output_oracion_simple = gr.Textbox(
label="Segmentación Simple",
lines=3,
elem_classes=["output-box"]
)
btn_oracion.click(
fn=segmentar_oracion,
inputs=[input_oracion, top_k_oracion, mostrar_alt],
outputs=output_oracion,
api_name="segmentar_oracion"
)
btn_oracion_simple.click(
fn=segmentar_oracion_simple,
inputs=[input_oracion],
outputs=output_oracion_simple,
api_name="segmentar_oracion_simple" # Disponible como herramienta MCP
)
gr.Examples(
examples=[
["Che aguatatahína ko'ẽrõ", 3, True],
["Ndajapói pe tembiapo", 3, True],
["Oguata hína oú haguã", 3, False],
],
inputs=[input_oracion, top_k_oracion, mostrar_alt]
)
# Tab 2: Buscador RAG
with gr.TabItem("🔍 Buscador de Morfologías", id=2):
gr.Markdown("### Búsqueda Semántica Inteligente de las morfologías que necesitás")
gr.Markdown("""
### 💡 Ejemplos de consultas:
- "quiero expresar el tiempo pasado"
- "cómo negar un verbo"
- "morfemas de posesión primera persona"
- "aspecto progresivo o continuo"
- "futuro simple en guaraní"
""")
with gr.Row():
with gr.Column(scale=3):
input_consulta_rag = gr.Textbox(
label="Consulta en Lenguaje Natural",
placeholder="Ej: quiero expresar el progresivo",
lines=2,
value="quiero expresar el aspecto progresivo"
)
with gr.Column(scale=1):
top_k_rag = gr.Slider(
minimum=1,
maximum=20,
value=5,
step=1,
label="Cantidad de resultados"
)
btn_rag = gr.Button("🔍 Buscar Morfologías", variant="primary", size="lg")
output_rag = gr.Textbox(
label="Resultados de Búsqueda",
lines=20,
elem_classes=["output-box"]
)
btn_rag.click(
fn=buscar_morfologia_rag,
inputs=[input_consulta_rag, top_k_rag],
outputs=output_rag,
api_name="buscar_morfologia_rag"
)
gr.Examples(
examples=[
["quiero expresar el tiempo pasado", 5],
["cómo negar un verbo", 5],
["morfemas de posesión primera persona", 5],
["aspecto progresivo o continuo", 5],
["futuro simple", 5],
],
inputs=[input_consulta_rag, top_k_rag]
)
# Tab 3: Diccionario
with gr.TabItem("📚 Diccionario", id=3):
gr.Markdown("### Busque información sobre partículas guaraní")
with gr.Row():
with gr.Column(scale=2):
input_particula = gr.Textbox(
label="Buscar Partícula",
placeholder="Ej: che, hína, nd-i",
value="che"
)
with gr.Column(scale=1):
btn_particula = gr.Button("🔍 Buscar", variant="primary")
output_particula = gr.Textbox(
label="Información",
lines=8,
elem_classes=["output-box"]
)
btn_particula.click(
fn=obtener_info_particula,
inputs=input_particula,
outputs=output_particula,
api_name="info_particula"
)
gr.Markdown("### Listar todas las partículas")
tipo_lista = gr.Radio(
choices=["todos", "prefijos", "sufijos", "circunfijos"],
value="todos",
label="Tipo de partículas"
)
btn_listar = gr.Button("📋 Listar Partículas", variant="secondary")
output_lista = gr.Textbox(
label="Lista de Partículas",
lines=20,
elem_classes=["output-box"]
)
btn_listar.click(
fn=listar_particulas,
inputs=tipo_lista,
outputs=output_lista,
api_name="listar_particulas"
)
gr.Markdown("""
---
### 📖 Guía de uso
**Tipos de componentes morfológicos:**
- `PRE` - Prefijo (antes de la raíz)
- `RAIZ` - Raíz léxica (núcleo semántico)
- `SUF` - Sufijo (después de la raíz)
- `CIRC_INI` / `CIRC_FIN` - Circunfijo (envuelve la raíz)
**Ejemplos de análisis:**
- `aguatatahína` → a[PRE]-guata[RAIZ]-ta[SUF]-hína[SUF] (yo caminaré + progresivo)
- `ndajapói` → nd[CIRC_INI]-a[PRE]-japo[RAIZ]-i[CIRC_FIN] (no hago)
- `cheróga` → che[PRE]-r[PRE]-óga[RAIZ] (mi casa)
---
*🔌 Esta aplicación funciona como servidor MCP para integración con LLMs*
""")
# ==============================================================================
# LANZAMIENTO
# ==============================================================================
if __name__ == "__main__":
demo.launch(
mcp_server=True,
share=False,
server_name="0.0.0.0",
server_port=7860,
show_error=True
)