jamalinu commited on
Commit
16ae430
·
verified ·
1 Parent(s): 5c8da34

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -33
app.py CHANGED
@@ -3,43 +3,180 @@ from berber_nlp import BerberNLPPipeline
3
 
4
  pipeline = BerberNLPPipeline()
5
 
6
- def analyze(text, mode):
7
- if mode == "Analizar Berber":
8
- result = pipeline.analyze(text, lang="ber")
9
- output = ""
10
- for tok in result["tokens"]:
11
- output += f"**{tok['form']}** → género: {tok.get('gender') or '—'}, estado: {tok.get('state') or '—'}\n"
12
- output += f"\nOrden VSO: {result['vso_check']['order']}"
13
- return output
14
- else:
15
- result = pipeline.analyze(text, lang="ca")
16
- errors = result.get("learner_errors", [])
17
- if not errors:
18
- return "No se detectaron errores típicos."
19
- return "\n".join([f"⚠️ [{e['id']}] {e['description']}\n Corrección: *{e['correction']}*" for e in errors])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  def translate(word, direction):
 
 
22
  src = "ca" if direction == "Catalán → Berber" else "ber"
23
- results = pipeline.translate(word, src=src)
 
 
 
24
  if not results:
25
- return "No encontrado en el diccionario."
26
- return "\n".join([f"**{r['form_ber'] if src=='ca' else r['form_ca']}** ({r['pos']}) — {r['notes']}" for r in results])
 
 
 
 
 
27
 
28
- with gr.Blocks(title="Berber NLP") as demo:
29
- gr.Markdown("# 🌍 Berber / Amazigh NLP Toolkit\nBasado en Lamuela (2005), Universitat de Girona")
30
-
31
- with gr.Tab("Análisis morfosintáctico"):
32
- mode = gr.Radio(["Analizar Berber", "Detectar errores (catalán de berberófonos)"], value="Analizar Berber")
33
- text_in = gr.Textbox(label="Texto", placeholder="ikerz argaz akal")
34
- btn = gr.Button("Analizar")
35
- output = gr.Markdown()
36
- btn.click(analyze, inputs=[text_in, mode], outputs=output)
37
-
38
- with gr.Tab("Diccionario"):
39
- direction = gr.Radio(["Catalán → Berber", "Berber → Catalán"], value="Catalán → Berber")
40
- word_in = gr.Textbox(label="Palabra", placeholder="home")
41
- btn2 = gr.Button("Buscar")
42
- output2 = gr.Markdown()
43
- btn2.click(translate, inputs=[word_in, direction], outputs=output2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  demo.launch()
 
3
 
4
  pipeline = BerberNLPPipeline()
5
 
6
+ # ── TAB 1: Análisis morfosintáctico ──────────────────────────────────────────
7
+
8
+ def analyze_berber(text):
9
+ if not text.strip():
10
+ return "✏️ Introduce una frase en berber. Ejemplo: *ikerz argaz akal*"
11
+ result = pipeline.analyze(text, lang="ber")
12
+
13
+ lines = ["### Tokens\n"]
14
+ lines.append("| Palabra | POS | Género | Estado | Aspecto |")
15
+ lines.append("|---------|-----|--------|--------|---------|")
16
+ for tok, morph in zip(result["tokens"], result["morphology"]):
17
+ lines.append(
18
+ f"| **{tok['form']}** "
19
+ f"| {morph.get('pos') or '—'} "
20
+ f"| {tok.get('gender') or '—'} "
21
+ f"| {tok.get('state') or '—'} "
22
+ f"| {morph.get('aspect') or '—'} |"
23
+ )
24
+
25
+ vso = result["vso_check"]
26
+ lines.append(f"\n### Sintaxis")
27
+ lines.append(f"**Orden detectado:** {vso['order']} ")
28
+ lines.append(f"**¿Orden canónico VSO?** {'✅ Sí' if vso['is_canonical'] else '⚠️ No'} ")
29
+ lines.append(f"_{vso['note']}_")
30
+
31
+ return "\n".join(lines)
32
+
33
+
34
+ def detect_errors(text):
35
+ if not text.strip():
36
+ return "✏️ Introduce una frase en catalán escrita por un hablante berber. Ejemplo: *té una cotxe*"
37
+ result = pipeline.analyze(text, lang="ca")
38
+ errors = result.get("learner_errors", [])
39
+ if not errors:
40
+ return "✅ No se detectaron errores típicos de transferencia berber→catalán."
41
+ lines = [f"### {len(errors)} error(es) detectado(s)\n"]
42
+ for e in errors:
43
+ lines.append(f"**[{e['id']}] {e['category']}**")
44
+ lines.append(f"- 📝 {e['description']}")
45
+ lines.append(f"- ❌ Error: *{e['example_error']}*")
46
+ lines.append(f"- ✅ Corrección: *{e['correction']}*")
47
+ lines.append(f"- 🔍 Causa berber: {e['berber_cause']}")
48
+ lines.append(f"- 📖 Ref: {e['reference']}\n")
49
+ return "\n".join(lines)
50
+
51
+
52
+ # ── TAB 2: Fonología ─────────────────────────────────────────────────────────
53
+
54
+ def analyze_phonology(text):
55
+ if not text.strip():
56
+ return "✏️ Introduce una palabra berber. Ejemplo: *ṭafruxt*"
57
+ words = text.strip().split()
58
+ lines = []
59
+ for word in words[:6]: # max 6 words
60
+ phon = pipeline.phonology.analyze_word_phonology(word)
61
+ lines.append(f"### `{word}`")
62
+ lines.append(f"| Campo | Valor |")
63
+ lines.append(f"|-------|-------|")
64
+ lines.append(f"| **IPA** | /{phon['ipa']}/ |")
65
+ lines.append(f"| **Sílabas** | {' · '.join(phon['syllables'])} ({phon['n_syllables']}) |")
66
+ lines.append(f"| **Vocales** | {phon['vowel_count']} |")
67
+ lines.append(f"| **Grupos consonánticos** | {', '.join(phon['consonant_clusters']) or '—'} |")
68
+ lines.append(f"| **¿Consonantes enfáticas?** | {'⚠️ Sí — ' + phon['notes'] if phon['has_emphatics'] else '✅ No'} |")
69
+ lines.append("")
70
+ return "\n".join(lines)
71
+
72
+
73
+ # ── TAB 3: Diccionario ───────────────────────────────────────────────────────
74
 
75
  def translate(word, direction):
76
+ if not word.strip():
77
+ return "✏️ Introduce una palabra."
78
  src = "ca" if direction == "Catalán → Berber" else "ber"
79
+ results = pipeline.translate(word.strip().lower(), src=src)
80
+ if not results:
81
+ # Try search
82
+ results = pipeline.dictionary.search(word.strip().lower(), lang=src)
83
  if not results:
84
+ return f"❌ **{word}** no encontrado en el diccionario."
85
+ lines = [f"### Resultados para **{word}**\n"]
86
+ lines.append("| Catalán | Berber | POS | Notas |")
87
+ lines.append("|---------|--------|-----|-------|")
88
+ for r in results:
89
+ lines.append(f"| {r['form_ca']} | **{r['form_ber']}** | {r['pos']} | {r['notes'] or '—'} |")
90
+ return "\n".join(lines)
91
 
92
+
93
+ # ── TAB 4: Errores de aprendizaje (todos) ────────────────────────────────────
94
+
95
+ def show_all_errors():
96
+ ea = pipeline.error_analyzer
97
+ lines = ["### Catálogo completo de errores (§3 Lamuela 2005)\n"]
98
+ lines.append("Errores típicos de hablantes berbers aprendiendo catalán, con explicación lingüística.\n")
99
+ for e in ea.ERROR_PATTERNS:
100
+ lines.append(f"---\n**[{e['id']}] {e['category']}**")
101
+ lines.append(f"- {e['description']}")
102
+ lines.append(f"- ❌ *{e['example_error']}* → ✅ *{e['correction']}*")
103
+ lines.append(f"- 🔍 {e['berber_cause']}")
104
+ lines.append(f"- 📖 {e['reference']}")
105
+ return "\n".join(lines)
106
+
107
+
108
+ # ── INTERFAZ ─────────────────────────────────────────────────────────────────
109
+
110
+ with gr.Blocks(title="Berber / Amazigh NLP Toolkit", theme=gr.themes.Soft()) as demo:
111
+ gr.Markdown("""
112
+ # 🌍 Berber / Amazigh NLP Toolkit
113
+ **Fantasmas en la Fuente: Resucitando una Lengua Muerta para la IA**
114
+ Basado en: Lamuela, X. (2005). *El Berber*. Universitat de Girona.
115
+ Familia lingüística: Afroasiática · ~15-20M hablantes · Escritura: Tifinagh / Latino
116
+ """)
117
+
118
+ with gr.Tab("🔬 Morfosintaxis"):
119
+ gr.Markdown("Analiza tokens, género, estado libre/anex, aspecto verbal y orden VSO.")
120
+ with gr.Row():
121
+ with gr.Column():
122
+ text_ber = gr.Textbox(label="Frase en berber", placeholder="ikerz argaz akal")
123
+ btn_ber = gr.Button("Analizar", variant="primary")
124
+ out_ber = gr.Markdown()
125
+ btn_ber.click(analyze_berber, inputs=text_ber, outputs=out_ber)
126
+ gr.Examples(
127
+ [["ikerz argaz akal"], ["ur ikerz ara argaz"], ["ttuzzel tafruxt deg taddart"]],
128
+ inputs=text_ber
129
+ )
130
+
131
+ with gr.Tab("🔊 Fonología"):
132
+ gr.Markdown("Transcripción IPA, silabificación y detección de consonantes faringalizadas.")
133
+ with gr.Row():
134
+ with gr.Column():
135
+ text_phon = gr.Textbox(label="Palabras berbers (hasta 6)", placeholder="ṭafruxt argaz akal")
136
+ btn_phon = gr.Button("Analizar fonología", variant="primary")
137
+ out_phon = gr.Markdown()
138
+ btn_phon.click(analyze_phonology, inputs=text_phon, outputs=out_phon)
139
+ gr.Examples(
140
+ [["ṭafruxt"], ["argaz akal tiṭ"], ["tanemmirt azul"]],
141
+ inputs=text_phon
142
+ )
143
+
144
+ with gr.Tab("📖 Diccionario"):
145
+ gr.Markdown("Diccionario bilingüe catalán↔berber basado en el vocabulario del libro.")
146
+ with gr.Row():
147
+ with gr.Column():
148
+ word_in = gr.Textbox(label="Palabra", placeholder="home")
149
+ direction = gr.Radio(["Catalán → Berber", "Berber → Catalán"], value="Catalán → Berber")
150
+ btn_dict = gr.Button("Buscar", variant="primary")
151
+ out_dict = gr.Markdown()
152
+ btn_dict.click(translate, inputs=[word_in, direction], outputs=out_dict)
153
+ gr.Examples(
154
+ [["home"], ["dona"], ["negre"], ["gràcies"], ["un"]],
155
+ inputs=word_in
156
+ )
157
+
158
+ with gr.Tab("⚠️ Errores de aprendizaje"):
159
+ gr.Markdown("Detecta errores de transferencia en catalán escrito por berberófonos.")
160
+ with gr.Row():
161
+ with gr.Column():
162
+ text_err = gr.Textbox(label="Frase en catalán", placeholder="té una cotxe")
163
+ btn_err = gr.Button("Detectar errores", variant="primary")
164
+ out_err = gr.Markdown()
165
+ btn_err.click(detect_errors, inputs=text_err, outputs=out_err)
166
+ gr.Examples(
167
+ [["té una cotxe"], ["vaig a mercat ahir"], ["no vinc no"]],
168
+ inputs=text_err
169
+ )
170
+
171
+ gr.Markdown("---")
172
+ btn_catalog = gr.Button("Ver catálogo completo de errores documentados")
173
+ out_catalog = gr.Markdown()
174
+ btn_catalog.click(show_all_errors, outputs=out_catalog)
175
+
176
+ gr.Markdown("""
177
+ ---
178
+ *Proyecto de NLP para lenguas de bajos recursos · Familia Afroasiática · Dialecto Tarifit/Rifeno*
179
+ *Código extraído y estructurado a partir del libro mediante decodificación de fuente propietaria (+29 ASCII shift)*
180
+ """)
181
 
182
  demo.launch()