cstr commited on
Commit
c28366b
·
verified ·
1 Parent(s): 1348295

attempt direct install grc model on script load

Browse files
Files changed (1) hide show
  1. app.py +119 -340
app.py CHANGED
@@ -3,11 +3,11 @@ import spacy
3
  from spacy import displacy
4
  import base64
5
  import traceback
 
6
  import sys
7
  import os
8
- import subprocess
9
- import importlib
10
- from typing import Dict, Optional, Tuple, List
11
 
12
  # ============================================================================
13
  # CONFIGURATION
@@ -77,44 +77,31 @@ UI_TEXT = {
77
  }
78
  }
79
 
 
 
80
  # ============================================================================
81
- # MODEL MANAGEMENT
82
  # ============================================================================
83
 
84
- MODELS: Dict[str, Optional[spacy.Language]] = {}
85
-
86
- def install_spacy_model(model_name: str) -> bool:
87
- """Install a standard spaCy model."""
88
- try:
89
- print(f"Installing spaCy model: {model_name}")
90
- subprocess.check_call(
91
- [sys.executable, "-m", "spacy", "download", model_name],
92
- stdout=subprocess.PIPE,
93
- stderr=subprocess.PIPE
94
- )
95
- print(f"✓ Successfully installed {model_name}")
96
  return True
97
- except subprocess.CalledProcessError as e:
98
- print(f" Failed to install {model_name}: {e}")
99
- return False
100
-
101
- def install_grecy_model(model_name: str) -> bool:
102
- """Install a grecy model for Ancient Greek."""
103
  try:
104
- # First ensure grecy package is installed
105
- print(f"Ensuring grecy package is installed...")
106
- subprocess.check_call(
107
- [sys.executable, "-m", "pip", "install", "-U", "grecy"],
108
- stdout=subprocess.PIPE,
109
- stderr=subprocess.PIPE
110
- )
111
-
112
- print(f"Installing grecy model: {model_name}")
113
  result = subprocess.run(
114
  [sys.executable, "-m", "grecy", "install", model_name],
115
  capture_output=True,
116
  text=True,
117
- timeout=600 # 10 minute timeout for large models
118
  )
119
 
120
  print(result.stdout)
@@ -122,395 +109,195 @@ def install_grecy_model(model_name: str) -> bool:
122
  print(f"stderr: {result.stderr}")
123
 
124
  if result.returncode == 0:
125
- print(f"✓ Successfully installed grecy model {model_name}")
 
 
126
  return True
127
  else:
128
- print(f"✗ Failed to install {model_name}, return code: {result.returncode}")
129
  return False
130
 
131
  except subprocess.TimeoutExpired:
132
- print(f"✗ Installation of {model_name} timed out")
133
  return False
134
  except Exception as e:
135
- print(f"✗ Error installing {model_name}: {e}")
136
  traceback.print_exc()
137
  return False
138
 
139
- def load_grecy_model_directly(model_name: str) -> Optional[spacy.Language]:
140
- """
141
- Load grecy model by finding it in site-packages.
142
- grecy models install differently than standard spaCy models.
143
- """
 
144
  try:
145
- import site
146
- import glob
147
-
148
- # Find the model in site-packages
149
- site_packages = site.getsitepackages()
150
-
151
- for sp in site_packages:
152
- # Look for the model directory
153
- model_pattern = os.path.join(sp, model_name.replace('_', '-') + '*')
154
- matches = glob.glob(model_pattern)
155
-
156
- if matches:
157
- model_path = matches[0]
158
- print(f"Found grecy model at: {model_path}")
159
-
160
- # Try to load from the path
161
- nlp = spacy.load(model_path)
162
- print(f"✓ Successfully loaded grecy model from {model_path}")
163
- return nlp
164
-
165
- # If not found in site-packages, try standard load
166
- print(f"Model not found in site-packages, trying standard load...")
167
  nlp = spacy.load(model_name)
168
  return nlp
169
-
170
- except Exception as e:
171
- print(f"✗ Failed to load grecy model directly: {e}")
172
- traceback.print_exc()
173
- return None
174
-
175
- def load_model_with_retry(lang_code: str, model_name: str, model_type: str, max_retries: int = 2) -> Optional[spacy.Language]:
176
- """
177
- Load a spaCy model with installation retry logic.
178
-
179
- Args:
180
- lang_code: Language code (e.g., 'de', 'en', 'grc')
181
- model_name: Name of the model to load
182
- model_type: Type of model ('spacy' or 'grecy')
183
- max_retries: Maximum number of installation attempts
184
-
185
- Returns:
186
- Loaded spaCy model or None if loading fails
187
- """
188
- for attempt in range(max_retries):
189
  try:
190
- print(f"Attempt {attempt + 1}/{max_retries}: Loading model '{model_name}' for language '{lang_code}'")
191
-
192
- # For grecy models, use special loading method
193
- if model_type == "grecy":
194
- nlp = load_grecy_model_directly(model_name)
195
- if nlp is not None:
196
- print(f"✓ Successfully loaded {model_name}")
197
- return nlp
198
- raise OSError(f"Could not load grecy model {model_name}")
199
- else:
200
- # Standard spaCy model loading
201
- nlp = spacy.load(model_name)
202
- print(f"✓ Successfully loaded {model_name}")
203
- return nlp
204
-
205
- except OSError as e:
206
- print(f"✗ Model '{model_name}' not found: {e}")
207
-
208
- if attempt < max_retries - 1:
209
- # Try to install the model
210
- print(f"Attempting to install {model_name}...")
211
-
212
- if model_type == "spacy":
213
- success = install_spacy_model(model_name)
214
- elif model_type == "grecy":
215
- success = install_grecy_model(model_name)
216
- else:
217
- print(f"Unknown model type: {model_type}")
218
- return None
219
-
220
- if not success:
221
- print(f"Installation failed for {model_name}")
222
- if attempt == max_retries - 2:
223
- return None
224
- else:
225
- # Give the system a moment to register the new model
226
- import time
227
- time.sleep(2)
228
- # Refresh Python's module cache
229
- importlib.invalidate_caches()
230
- else:
231
- print(f"✗ All attempts to load {model_name} failed")
232
- return None
233
-
234
  except Exception as e:
235
- print(f"✗ Unexpected error loading {model_name}: {e}")
236
- traceback.print_exc()
237
  return None
 
 
 
 
 
238
 
239
- return None
 
 
 
 
 
 
 
 
 
240
 
241
  def initialize_models():
242
- """Initialize all models at startup."""
243
  print("\n" + "="*70)
244
  print("INITIALIZING MODELS")
245
- print("="*70)
246
 
247
  for lang_code, (lang_name, model_name, model_type) in MODEL_INFO.items():
248
- print(f"\n--- Loading {lang_name} ({model_name}) ---")
 
 
 
 
 
249
 
250
- nlp = load_model_with_retry(lang_code, model_name, model_type)
251
 
252
- if nlp is not None:
253
- MODELS[lang_code] = nlp
254
- print(f"✓ {lang_name} model ready")
255
  else:
256
- MODELS[lang_code] = None
257
- print(f"✗ {lang_name} model FAILED - analysis will be unavailable")
258
 
259
- print("\n" + "="*70)
260
- print("MODEL INITIALIZATION COMPLETE")
261
- print("="*70)
262
-
263
- # Print summary
264
- loaded = sum(1 for model in MODELS.values() if model is not None)
265
- total = len(MODELS)
266
- print(f"\nLoaded {loaded}/{total} models successfully")
267
-
268
- if loaded < total:
269
- print("\n⚠ WARNING: Some models failed to load")
270
- for lang_code, model in MODELS.items():
271
- if model is None:
272
- lang_name = MODEL_INFO[lang_code][0]
273
- print(f" - {lang_name} ({lang_code}): UNAVAILABLE")
274
-
275
- print("\n")
276
 
277
  # ============================================================================
278
- # TEXT ANALYSIS
279
  # ============================================================================
280
 
281
  def get_analysis(ui_lang: str, model_lang: str, text: str):
282
- """
283
- Perform morpho-syntactic analysis on the input text.
284
-
285
- Returns tuple of outputs for Gradio.
286
- """
287
- current_ui_lang_code = ui_lang.lower()
288
- current_ui_config = UI_TEXT.get(current_ui_lang_code, UI_TEXT["en"])
289
- error_prefix = current_ui_config["error_message"]
290
 
291
  try:
292
- # Validate input
293
- if not text or not text.strip():
294
- return (
295
- [],
296
- [],
297
- "<p style='color: orange;'>No text provided for analysis.</p>",
298
- gr.Button(value=current_ui_config["button_text"], interactive=True)
299
- )
300
-
301
- # Extract language code from selection like 'GRC (grc_proiel_trf)'
302
- lang_code = model_lang.split(" ")[0].lower()
303
 
304
- # Check if model is available
305
- if lang_code not in MODELS:
306
- raise ValueError(f"Unknown language code: '{lang_code}'")
307
 
308
- if MODELS[lang_code] is None:
309
- lang_name = MODEL_INFO[lang_code][0]
310
- model_name = MODEL_INFO[lang_code][1]
311
- raise ValueError(
312
- f"Model for {lang_name} ('{model_name}') failed to load during startup. "
313
- f"Please check the logs or try restarting the Space."
314
- )
315
 
316
- # Get the model and process text
317
  nlp = MODELS[lang_code]
318
  doc = nlp(text)
319
 
320
- # Prepare outputs
321
  dataframe_output = []
322
  json_output = []
323
 
324
- # Extract linguistic information for each token
325
  for token in doc:
326
- # Safely extract attributes
327
  morph_str = str(token.morph) if hasattr(token, 'morph') else ''
328
  dep_str = token.dep_ if doc.has_annotation("DEP") else ''
329
  tag_str = token.tag_ if hasattr(token, 'tag_') else ''
330
  pos_str = token.pos_ if hasattr(token, 'pos_') else ''
331
  lemma_str = token.lemma_ if token.lemma != 0 else token.text
332
 
333
- # Add to JSON output
334
  json_output.append({
335
- "word": token.text,
336
- "lemma": lemma_str,
337
- "pos": pos_str,
338
- "tag": tag_str,
339
- "morphology": morph_str,
340
- "dependency": dep_str,
341
  "is_stopword": token.is_stop
342
  })
343
 
344
- # Add to dataframe output
345
- dataframe_output.append([
346
- token.text,
347
- lemma_str,
348
- pos_str,
349
- tag_str,
350
- morph_str,
351
- dep_str
352
- ])
353
 
354
- # Generate dependency visualization if available
355
- html_out_content = ""
356
  if doc.has_annotation("DEP"):
357
  try:
358
- options = {
359
- "compact": True,
360
- "bg": "#ffffff",
361
- "color": "#000000",
362
- "font": "Source Sans Pro"
363
- }
364
  html_svg = displacy.render(doc, style="dep", jupyter=False, options=options)
365
  svg_b64 = base64.b64encode(html_svg.encode("utf-8")).decode("utf-8")
366
- html_out_content = f"""
367
- <div style="background-color: #ffffff; overflow-x: auto; border: 1px solid #e6e9ef;
368
- border-radius: 0.25rem; padding: 1rem; line-height: 2.5;">
369
- <img src="data:image/svg+xml;base64,{svg_b64}" alt="Dependency Parse" />
370
- </div>
371
- """
372
- except Exception as viz_error:
373
- print(f"Warning: Could not generate visualization: {viz_error}")
374
- html_out_content = f"<p style='color: orange;'>Dependency visualization could not be generated: {viz_error}</p>"
375
  else:
376
- model_name = MODEL_INFO[lang_code][1]
377
- html_out_content = f"""
378
- <p style='color: orange;'>
379
- Dependency parse visualization is not available for the selected model ('{model_name}').
380
- The model may not include a parser component.
381
- </p>
382
- """
383
 
384
- # Return tuple of outputs
385
- return (
386
- dataframe_output,
387
- json_output,
388
- html_out_content,
389
- gr.Button(value=current_ui_config["button_text"], interactive=True)
390
- )
391
 
392
  except Exception as e:
393
- print(f"--- ERROR during get_analysis ---")
394
  traceback.print_exc()
395
-
396
- error_details = str(e)
397
- error_html = f"""
398
- <div style='color: red; border: 1px solid red; padding: 10px; border-radius: 5px;
399
- background-color: #fff5f5;'>
400
- <strong>{error_prefix}</strong> {error_details}
401
- </div>
402
- """
403
-
404
- return (
405
- [[f"{error_prefix}{error_details}"]],
406
- {"error": error_details},
407
- error_html,
408
- gr.Button(value=current_ui_config["button_text"], interactive=True)
409
- )
410
 
411
  # ============================================================================
412
- # UI UPDATE
413
  # ============================================================================
414
 
415
  def update_ui(ui_lang: str):
416
- """Update all UI components when the interface language is changed."""
417
- lang_code = ui_lang.lower()
418
- ui_config = UI_TEXT.get(lang_code, UI_TEXT["en"])
419
-
420
  return [
421
  gr.Markdown(value=ui_config["title"]),
422
  gr.Markdown(value=ui_config["subtitle"]),
423
  gr.Radio(label=ui_config["ui_lang_label"]),
424
  gr.Radio(label=ui_config["model_lang_label"]),
425
- gr.Textbox(
426
- label=ui_config["input_label"],
427
- placeholder=ui_config["input_placeholder"]
428
- ),
429
  gr.Button(value=ui_config["button_text"]),
430
  gr.Tab(label=ui_config["tab_graphic"]),
431
  gr.Tab(label=ui_config["tab_table"]),
432
  gr.Tab(label=ui_config["tab_json"]),
433
  gr.HTML(label=ui_config["html_label"]),
434
- gr.DataFrame(
435
- label=ui_config["table_label"],
436
- headers=ui_config["table_headers"],
437
- interactive=False
438
- ),
439
  gr.JSON(label=ui_config["json_label"])
440
  ]
441
 
442
- # ============================================================================
443
- # GRADIO INTERFACE
444
- # ============================================================================
445
-
446
  def create_interface():
447
- """Create and configure the Gradio interface."""
448
- default_config = UI_TEXT["en"]
449
-
450
- # Generate model choices dynamically
451
- model_lang_choices = [
452
- f"{k.upper()} ({v[1]})"
453
- for k, v in MODEL_INFO.items()
454
- ]
455
 
456
  with gr.Blocks(title="Multilingual Morpho-Syntactic Analyzer") as demo:
457
- # Header
458
  with gr.Row():
459
- ui_lang_radio = gr.Radio(
460
- ["DE", "EN", "ES"],
461
- label=default_config["ui_lang_label"],
462
- value="EN"
463
- )
464
- model_lang_radio = gr.Radio(
465
- model_lang_choices,
466
- label=default_config["model_lang_label"],
467
- value=model_lang_choices[0]
468
- )
469
 
470
- markdown_title = gr.Markdown(default_config["title"])
471
- markdown_subtitle = gr.Markdown(default_config["subtitle"])
 
 
472
 
473
- # Input section
474
- text_input = gr.Textbox(
475
- label=default_config["input_label"],
476
- placeholder=default_config["input_placeholder"],
477
- lines=5
478
- )
479
- analyze_button = gr.Button(default_config["button_text"], variant="primary")
480
 
481
- # Output tabs
482
- with gr.Tabs() as tabs:
483
- with gr.Tab(default_config["tab_graphic"]) as tab_graphic:
484
- html_out = gr.HTML(label=default_config["html_label"])
485
-
486
- with gr.Tab(default_config["tab_table"]) as tab_table:
487
- df_out = gr.DataFrame(
488
- label=default_config["table_label"],
489
- headers=default_config["table_headers"],
490
- interactive=False
491
- )
492
-
493
- with gr.Tab(default_config["tab_json"]) as tab_json:
494
- json_out = gr.JSON(label=default_config["json_label"])
495
 
496
- # Event handlers - FIXED: Use list outputs instead of dict
497
- analyze_button.click(
498
- fn=get_analysis,
499
- inputs=[ui_lang_radio, model_lang_radio, text_input],
500
- outputs=[df_out, json_out, html_out, analyze_button],
501
- api_name="get_morphology"
502
- )
503
-
504
- ui_lang_radio.change(
505
- fn=update_ui,
506
- inputs=ui_lang_radio,
507
- outputs=[
508
- markdown_title, markdown_subtitle, ui_lang_radio, model_lang_radio,
509
- text_input, analyze_button, tab_graphic, tab_table, tab_json,
510
- html_out, df_out, json_out
511
- ]
512
- )
513
-
514
  return demo
515
 
516
  # ============================================================================
@@ -520,16 +307,8 @@ def create_interface():
520
  if __name__ == "__main__":
521
  print("\n" + "="*70)
522
  print("MULTILINGUAL MORPHO-SYNTACTIC ANALYZER")
523
- print("Starting application...")
524
  print("="*70 + "\n")
525
 
526
- # Initialize all models
527
  initialize_models()
528
-
529
- # Create and launch the interface
530
  demo = create_interface()
531
- demo.launch(
532
- server_name="0.0.0.0",
533
- server_port=7860,
534
- show_error=True
535
- )
 
3
  from spacy import displacy
4
  import base64
5
  import traceback
6
+ import subprocess
7
  import sys
8
  import os
9
+ from pathlib import Path
10
+ from typing import Dict, Optional
 
11
 
12
  # ============================================================================
13
  # CONFIGURATION
 
77
  }
78
  }
79
 
80
+ MODELS: Dict[str, Optional[spacy.Language]] = {}
81
+
82
  # ============================================================================
83
+ # GRECY MODEL INSTALLATION
84
  # ============================================================================
85
 
86
+ def install_grecy_once(model_name: str) -> bool:
87
+ """
88
+ Install grecy model only if not already installed.
89
+ Uses a marker file to track installation.
90
+ """
91
+ marker_file = Path(f".{model_name}_installed")
92
+
93
+ if marker_file.exists():
94
+ print(f"✓ {model_name} already installed (marker found)")
 
 
 
95
  return True
96
+
97
+ print(f"Installing grecy model: {model_name} (this will take several minutes)...")
 
 
 
 
98
  try:
99
+ # Run the grecy install command
 
 
 
 
 
 
 
 
100
  result = subprocess.run(
101
  [sys.executable, "-m", "grecy", "install", model_name],
102
  capture_output=True,
103
  text=True,
104
+ timeout=900 # 15 minute timeout
105
  )
106
 
107
  print(result.stdout)
 
109
  print(f"stderr: {result.stderr}")
110
 
111
  if result.returncode == 0:
112
+ # Create marker file
113
+ marker_file.touch()
114
+ print(f"✓ Successfully installed {model_name}")
115
  return True
116
  else:
117
+ print(f"✗ Installation failed with return code {result.returncode}")
118
  return False
119
 
120
  except subprocess.TimeoutExpired:
121
+ print(f"✗ Installation timed out")
122
  return False
123
  except Exception as e:
124
+ print(f"✗ Installation error: {e}")
125
  traceback.print_exc()
126
  return False
127
 
128
+ # ============================================================================
129
+ # MODEL LOADING
130
+ # ============================================================================
131
+
132
+ def load_spacy_model(model_name: str) -> Optional[spacy.Language]:
133
+ """Load or install a standard spaCy model."""
134
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  nlp = spacy.load(model_name)
136
  return nlp
137
+ except OSError:
138
+ print(f"Installing {model_name}...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  try:
140
+ subprocess.check_call([sys.executable, "-m", "spacy", "download", model_name])
141
+ return spacy.load(model_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  except Exception as e:
143
+ print(f"✗ Failed to install {model_name}: {e}")
 
144
  return None
145
+
146
+ def load_grecy_model(model_name: str) -> Optional[spacy.Language]:
147
+ """Load a grecy model, installing if necessary."""
148
+ # First, ensure it's installed
149
+ install_grecy_once(model_name)
150
 
151
+ # Try to load it
152
+ try:
153
+ nlp = spacy.load(model_name)
154
+ print(f"✓ Loaded {model_name}")
155
+ return nlp
156
+ except Exception as e:
157
+ print(f"✗ Failed to load {model_name}: {e}")
158
+ print(f" Try: python -m grecy install {model_name}")
159
+ traceback.print_exc()
160
+ return None
161
 
162
  def initialize_models():
163
+ """Load all models at startup."""
164
  print("\n" + "="*70)
165
  print("INITIALIZING MODELS")
166
+ print("="*70 + "\n")
167
 
168
  for lang_code, (lang_name, model_name, model_type) in MODEL_INFO.items():
169
+ print(f"Loading {lang_name} ({model_name})...")
170
+
171
+ if model_type == "grecy":
172
+ nlp = load_grecy_model(model_name)
173
+ else:
174
+ nlp = load_spacy_model(model_name)
175
 
176
+ MODELS[lang_code] = nlp
177
 
178
+ if nlp:
179
+ print(f"✓ {lang_name} ready\n")
 
180
  else:
181
+ print(f"✗ {lang_name} FAILED\n")
 
182
 
183
+ loaded = sum(1 for m in MODELS.values() if m is not None)
184
+ print(f"Loaded {loaded}/{len(MODELS)} models successfully")
185
+ print("="*70 + "\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
  # ============================================================================
188
+ # ANALYSIS
189
  # ============================================================================
190
 
191
  def get_analysis(ui_lang: str, model_lang: str, text: str):
192
+ """Analyze text and return results."""
193
+ ui_config = UI_TEXT.get(ui_lang.lower(), UI_TEXT["en"])
194
+ error_prefix = ui_config["error_message"]
 
 
 
 
 
195
 
196
  try:
197
+ if not text.strip():
198
+ return ([], [], "<p style='color: orange;'>No text provided.</p>",
199
+ gr.Button(value=ui_config["button_text"], interactive=True))
 
 
 
 
 
 
 
 
200
 
201
+ lang_code = model_lang.split()[0].lower()
 
 
202
 
203
+ if lang_code not in MODELS or MODELS[lang_code] is None:
204
+ raise ValueError(f"Model for {lang_code} is not available. Please check logs.")
 
 
 
 
 
205
 
 
206
  nlp = MODELS[lang_code]
207
  doc = nlp(text)
208
 
 
209
  dataframe_output = []
210
  json_output = []
211
 
 
212
  for token in doc:
 
213
  morph_str = str(token.morph) if hasattr(token, 'morph') else ''
214
  dep_str = token.dep_ if doc.has_annotation("DEP") else ''
215
  tag_str = token.tag_ if hasattr(token, 'tag_') else ''
216
  pos_str = token.pos_ if hasattr(token, 'pos_') else ''
217
  lemma_str = token.lemma_ if token.lemma != 0 else token.text
218
 
 
219
  json_output.append({
220
+ "word": token.text, "lemma": lemma_str, "pos": pos_str,
221
+ "tag": tag_str, "morphology": morph_str, "dependency": dep_str,
 
 
 
 
222
  "is_stopword": token.is_stop
223
  })
224
 
225
+ dataframe_output.append([token.text, lemma_str, pos_str, tag_str, morph_str, dep_str])
 
 
 
 
 
 
 
 
226
 
227
+ # Generate visualization
228
+ html_out = ""
229
  if doc.has_annotation("DEP"):
230
  try:
231
+ options = {"compact": True, "bg": "#ffffff", "color": "#000000", "font": "Source Sans Pro"}
 
 
 
 
 
232
  html_svg = displacy.render(doc, style="dep", jupyter=False, options=options)
233
  svg_b64 = base64.b64encode(html_svg.encode("utf-8")).decode("utf-8")
234
+ html_out = f'<div style="background-color: #ffffff; overflow-x: auto; border: 1px solid #e6e9ef; border-radius: 0.25rem; padding: 1rem; line-height: 2.5;"><img src="data:image/svg+xml;base64,{svg_b64}" /></div>'
235
+ except Exception as e:
236
+ html_out = f"<p style='color: orange;'>Visualization error: {e}</p>"
 
 
 
 
 
 
237
  else:
238
+ html_out = "<p style='color: orange;'>Dependency parsing not available for this model.</p>"
 
 
 
 
 
 
239
 
240
+ return (dataframe_output, json_output, html_out,
241
+ gr.Button(value=ui_config["button_text"], interactive=True))
 
 
 
 
 
242
 
243
  except Exception as e:
 
244
  traceback.print_exc()
245
+ error_html = f"<div style='color: red; border: 1px solid red; padding: 10px; border-radius: 5px; background-color: #fff5f5;'><strong>{error_prefix}</strong> {str(e)}</div>"
246
+ return ([[f"{error_prefix}{str(e)}"]], {"error": str(e)}, error_html,
247
+ gr.Button(value=ui_config["button_text"], interactive=True))
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  # ============================================================================
250
+ # UI
251
  # ============================================================================
252
 
253
  def update_ui(ui_lang: str):
254
+ """Update UI language."""
255
+ ui_config = UI_TEXT.get(ui_lang.lower(), UI_TEXT["en"])
 
 
256
  return [
257
  gr.Markdown(value=ui_config["title"]),
258
  gr.Markdown(value=ui_config["subtitle"]),
259
  gr.Radio(label=ui_config["ui_lang_label"]),
260
  gr.Radio(label=ui_config["model_lang_label"]),
261
+ gr.Textbox(label=ui_config["input_label"], placeholder=ui_config["input_placeholder"]),
 
 
 
262
  gr.Button(value=ui_config["button_text"]),
263
  gr.Tab(label=ui_config["tab_graphic"]),
264
  gr.Tab(label=ui_config["tab_table"]),
265
  gr.Tab(label=ui_config["tab_json"]),
266
  gr.HTML(label=ui_config["html_label"]),
267
+ gr.DataFrame(label=ui_config["table_label"], headers=ui_config["table_headers"], interactive=False),
 
 
 
 
268
  gr.JSON(label=ui_config["json_label"])
269
  ]
270
 
 
 
 
 
271
  def create_interface():
272
+ """Create Gradio interface."""
273
+ config = UI_TEXT["en"]
274
+ model_choices = [f"{k.upper()} ({v[1]})" for k, v in MODEL_INFO.items()]
 
 
 
 
 
275
 
276
  with gr.Blocks(title="Multilingual Morpho-Syntactic Analyzer") as demo:
 
277
  with gr.Row():
278
+ ui_lang_radio = gr.Radio(["DE", "EN", "ES"], label=config["ui_lang_label"], value="EN")
279
+ model_lang_radio = gr.Radio(model_choices, label=config["model_lang_label"], value=model_choices[0])
 
 
 
 
 
 
 
 
280
 
281
+ markdown_title = gr.Markdown(config["title"])
282
+ markdown_subtitle = gr.Markdown(config["subtitle"])
283
+ text_input = gr.Textbox(label=config["input_label"], placeholder=config["input_placeholder"], lines=5)
284
+ analyze_button = gr.Button(config["button_text"], variant="primary")
285
 
286
+ with gr.Tabs():
287
+ with gr.Tab(config["tab_graphic"]) as tab_graphic:
288
+ html_out = gr.HTML(label=config["html_label"])
289
+ with gr.Tab(config["tab_table"]) as tab_table:
290
+ df_out = gr.DataFrame(label=config["table_label"], headers=config["table_headers"], interactive=False)
291
+ with gr.Tab(config["tab_json"]) as tab_json:
292
+ json_out = gr.JSON(label=config["json_label"])
293
 
294
+ analyze_button.click(fn=get_analysis, inputs=[ui_lang_radio, model_lang_radio, text_input],
295
+ outputs=[df_out, json_out, html_out, analyze_button], api_name="get_morphology")
 
 
 
 
 
 
 
 
 
 
 
 
296
 
297
+ ui_lang_radio.change(fn=update_ui, inputs=ui_lang_radio,
298
+ outputs=[markdown_title, markdown_subtitle, ui_lang_radio, model_lang_radio,
299
+ text_input, analyze_button, tab_graphic, tab_table, tab_json,
300
+ html_out, df_out, json_out])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  return demo
302
 
303
  # ============================================================================
 
307
  if __name__ == "__main__":
308
  print("\n" + "="*70)
309
  print("MULTILINGUAL MORPHO-SYNTACTIC ANALYZER")
 
310
  print("="*70 + "\n")
311
 
 
312
  initialize_models()
 
 
313
  demo = create_interface()
314
+ demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)