Spaces:
Running
Running
| 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 | |
| # ============================================================================== | |
| 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 | |
| ) |