Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
| 1 |
"""
|
| 2 |
LocaleNLP Translation Service
|
| 3 |
============================
|
| 4 |
-
|
| 5 |
A multi-language translation application supporting English, Wolof, Hausa, and Darija.
|
| 6 |
Features text, audio, and document translation with automatic chaining for all language pairs.
|
| 7 |
-
|
| 8 |
Author: LocaleNLP
|
| 9 |
"""
|
| 10 |
|
|
@@ -12,6 +10,8 @@ import os
|
|
| 12 |
import re
|
| 13 |
import logging
|
| 14 |
import tempfile
|
|
|
|
|
|
|
| 15 |
from typing import Optional, Dict, Tuple, Any, Union
|
| 16 |
from pathlib import Path
|
| 17 |
from dataclasses import dataclass
|
|
@@ -93,6 +93,9 @@ SUPPORTED_FILE_TYPES = [
|
|
| 93 |
# Audio file extensions
|
| 94 |
AUDIO_EXTENSIONS = [".wav", ".mp3", ".m4a"]
|
| 95 |
|
|
|
|
|
|
|
|
|
|
| 96 |
# ================================
|
| 97 |
# Logging Configuration
|
| 98 |
# ================================
|
|
@@ -429,6 +432,72 @@ class AudioProcessor:
|
|
| 429 |
result = model.transcribe(audio_file_path)
|
| 430 |
return result["text"]
|
| 431 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
# ================================
|
| 433 |
# Main Application
|
| 434 |
# ================================
|
|
@@ -441,6 +510,7 @@ class TranslationApp:
|
|
| 441 |
self.content_processor = ContentProcessor()
|
| 442 |
self.translation_service = TranslationService(self.model_manager)
|
| 443 |
self.audio_processor = AudioProcessor(self.model_manager)
|
|
|
|
| 444 |
|
| 445 |
def process_input(
|
| 446 |
self,
|
|
@@ -480,6 +550,20 @@ class TranslationApp:
|
|
| 480 |
|
| 481 |
return ""
|
| 482 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
def create_interface(self) -> gr.Blocks:
|
| 484 |
"""Create and return the Gradio interface."""
|
| 485 |
|
|
@@ -551,6 +635,27 @@ class TranslationApp:
|
|
| 551 |
interactive=False
|
| 552 |
)
|
| 553 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
# Event handlers
|
| 555 |
def update_visibility(mode: str) -> Dict[str, Any]:
|
| 556 |
"""Update component visibility based on input mode."""
|
|
@@ -601,6 +706,35 @@ class TranslationApp:
|
|
| 601 |
logger.error(f"Translation error: {e}")
|
| 602 |
return f"❌ Translation error: {str(e)}"
|
| 603 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
# Connect events
|
| 605 |
input_mode.change(
|
| 606 |
fn=update_visibility,
|
|
@@ -617,6 +751,23 @@ class TranslationApp:
|
|
| 617 |
inputs=[extracted_text, input_lang, output_lang],
|
| 618 |
outputs=output_text
|
| 619 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
|
| 621 |
return interface
|
| 622 |
|
|
|
|
| 1 |
"""
|
| 2 |
LocaleNLP Translation Service
|
| 3 |
============================
|
|
|
|
| 4 |
A multi-language translation application supporting English, Wolof, Hausa, and Darija.
|
| 5 |
Features text, audio, and document translation with automatic chaining for all language pairs.
|
|
|
|
| 6 |
Author: LocaleNLP
|
| 7 |
"""
|
| 8 |
|
|
|
|
| 10 |
import re
|
| 11 |
import logging
|
| 12 |
import tempfile
|
| 13 |
+
import csv
|
| 14 |
+
import requests
|
| 15 |
from typing import Optional, Dict, Tuple, Any, Union
|
| 16 |
from pathlib import Path
|
| 17 |
from dataclasses import dataclass
|
|
|
|
| 93 |
# Audio file extensions
|
| 94 |
AUDIO_EXTENSIONS = [".wav", ".mp3", ".m4a"]
|
| 95 |
|
| 96 |
+
# Evaluation CSV URL
|
| 97 |
+
EVALUATION_CSV_URL = "https://github.com/mgolomanta/Models_Evaluation/blob/main/evaluation.csv"
|
| 98 |
+
|
| 99 |
# ================================
|
| 100 |
# Logging Configuration
|
| 101 |
# ================================
|
|
|
|
| 432 |
result = model.transcribe(audio_file_path)
|
| 433 |
return result["text"]
|
| 434 |
|
| 435 |
+
# ================================
|
| 436 |
+
# Evaluation Service
|
| 437 |
+
# ================================
|
| 438 |
+
|
| 439 |
+
class EvaluationService:
|
| 440 |
+
"""Handles evaluation submissions and storage."""
|
| 441 |
+
|
| 442 |
+
EVALUATION_CSV_PATH = "evaluation.csv"
|
| 443 |
+
|
| 444 |
+
@staticmethod
|
| 445 |
+
def save_evaluation(
|
| 446 |
+
source_lang: str,
|
| 447 |
+
target_lang: str,
|
| 448 |
+
user_input: str,
|
| 449 |
+
model_output: str,
|
| 450 |
+
notation: Optional[str] = None,
|
| 451 |
+
correct_answer: Optional[str] = None
|
| 452 |
+
) -> str:
|
| 453 |
+
"""
|
| 454 |
+
Save evaluation to CSV file.
|
| 455 |
+
|
| 456 |
+
Args:
|
| 457 |
+
source_lang: Source language name
|
| 458 |
+
target_lang: Target language name
|
| 459 |
+
user_input: User input text
|
| 460 |
+
model_output: Model output text
|
| 461 |
+
notation: Optional notation value
|
| 462 |
+
correct_answer: Optional correct answer
|
| 463 |
+
|
| 464 |
+
Returns:
|
| 465 |
+
Status message
|
| 466 |
+
"""
|
| 467 |
+
try:
|
| 468 |
+
# Check if CSV file exists, create it with headers if not
|
| 469 |
+
file_exists = os.path.exists(EvaluationService.EVALUATION_CSV_PATH)
|
| 470 |
+
|
| 471 |
+
with open(EvaluationService.EVALUATION_CSV_PATH, mode='a', newline='', encoding='utf-8') as file:
|
| 472 |
+
writer = csv.writer(file)
|
| 473 |
+
|
| 474 |
+
# Write headers if file is new
|
| 475 |
+
if not file_exists:
|
| 476 |
+
writer.writerow([
|
| 477 |
+
"source_language_name",
|
| 478 |
+
"target_language_name",
|
| 479 |
+
"user_input",
|
| 480 |
+
"model_output",
|
| 481 |
+
"notation_value",
|
| 482 |
+
"correct_answer"
|
| 483 |
+
])
|
| 484 |
+
|
| 485 |
+
# Write evaluation data
|
| 486 |
+
writer.writerow([
|
| 487 |
+
source_lang,
|
| 488 |
+
target_lang,
|
| 489 |
+
user_input,
|
| 490 |
+
model_output,
|
| 491 |
+
notation if notation else "",
|
| 492 |
+
correct_answer if correct_answer else ""
|
| 493 |
+
])
|
| 494 |
+
|
| 495 |
+
return "✅ Evaluation submitted successfully!"
|
| 496 |
+
|
| 497 |
+
except Exception as e:
|
| 498 |
+
logger.error(f"Failed to save evaluation: {e}")
|
| 499 |
+
return f"❌ Error saving evaluation: {str(e)}"
|
| 500 |
+
|
| 501 |
# ================================
|
| 502 |
# Main Application
|
| 503 |
# ================================
|
|
|
|
| 510 |
self.content_processor = ContentProcessor()
|
| 511 |
self.translation_service = TranslationService(self.model_manager)
|
| 512 |
self.audio_processor = AudioProcessor(self.model_manager)
|
| 513 |
+
self.evaluation_service = EvaluationService()
|
| 514 |
|
| 515 |
def process_input(
|
| 516 |
self,
|
|
|
|
| 550 |
|
| 551 |
return ""
|
| 552 |
|
| 553 |
+
def submit_evaluation(
|
| 554 |
+
self,
|
| 555 |
+
source_lang: str,
|
| 556 |
+
target_lang: str,
|
| 557 |
+
user_input: str,
|
| 558 |
+
model_output: str,
|
| 559 |
+
notation: Optional[str],
|
| 560 |
+
correct_answer: Optional[str]
|
| 561 |
+
) -> str:
|
| 562 |
+
"""Submit evaluation data."""
|
| 563 |
+
return self.evaluation_service.save_evaluation(
|
| 564 |
+
source_lang, target_lang, user_input, model_output, notation, correct_answer
|
| 565 |
+
)
|
| 566 |
+
|
| 567 |
def create_interface(self) -> gr.Blocks:
|
| 568 |
"""Create and return the Gradio interface."""
|
| 569 |
|
|
|
|
| 635 |
interactive=False
|
| 636 |
)
|
| 637 |
|
| 638 |
+
# Evaluation section
|
| 639 |
+
gr.Markdown("### 📝 Model Evaluation")
|
| 640 |
+
with gr.Group():
|
| 641 |
+
with gr.Row():
|
| 642 |
+
notation = gr.Radio(
|
| 643 |
+
choices=["1", "2", "3", "4", "5"],
|
| 644 |
+
label="Notation (1-5 stars)",
|
| 645 |
+
value=None
|
| 646 |
+
)
|
| 647 |
+
correct_translation = gr.Textbox(
|
| 648 |
+
label="Correct Translation (if incorrect)",
|
| 649 |
+
lines=3,
|
| 650 |
+
placeholder="Enter the correct translation if the model output is wrong..."
|
| 651 |
+
)
|
| 652 |
+
|
| 653 |
+
submit_evaluation_btn = gr.Button("Submit Evaluation", variant="primary")
|
| 654 |
+
evaluation_status = gr.Textbox(
|
| 655 |
+
label="Evaluation Status",
|
| 656 |
+
interactive=False
|
| 657 |
+
)
|
| 658 |
+
|
| 659 |
# Event handlers
|
| 660 |
def update_visibility(mode: str) -> Dict[str, Any]:
|
| 661 |
"""Update component visibility based on input mode."""
|
|
|
|
| 706 |
logger.error(f"Translation error: {e}")
|
| 707 |
return f"❌ Translation error: {str(e)}"
|
| 708 |
|
| 709 |
+
def handle_evaluation(
|
| 710 |
+
source_lang: str,
|
| 711 |
+
target_lang: str,
|
| 712 |
+
user_input: str,
|
| 713 |
+
model_output: str,
|
| 714 |
+
notation_value: Optional[str],
|
| 715 |
+
correct_answer: Optional[str]
|
| 716 |
+
) -> str:
|
| 717 |
+
"""Handle evaluation submission."""
|
| 718 |
+
if not user_input.strip() or not model_output.strip():
|
| 719 |
+
return "⚠️ Please translate text before submitting evaluation."
|
| 720 |
+
|
| 721 |
+
return self.submit_evaluation(
|
| 722 |
+
source_lang,
|
| 723 |
+
target_lang,
|
| 724 |
+
user_input,
|
| 725 |
+
model_output,
|
| 726 |
+
notation_value,
|
| 727 |
+
correct_answer
|
| 728 |
+
)
|
| 729 |
+
|
| 730 |
+
def clear_evaluation_fields() -> Dict:
|
| 731 |
+
"""Clear evaluation fields after submission."""
|
| 732 |
+
return {
|
| 733 |
+
notation: gr.update(value=None),
|
| 734 |
+
correct_translation: gr.update(value=""),
|
| 735 |
+
evaluation_status: gr.update(value="Evaluation cleared. Ready for next submission.")
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
# Connect events
|
| 739 |
input_mode.change(
|
| 740 |
fn=update_visibility,
|
|
|
|
| 751 |
inputs=[extracted_text, input_lang, output_lang],
|
| 752 |
outputs=output_text
|
| 753 |
)
|
| 754 |
+
|
| 755 |
+
submit_evaluation_btn.click(
|
| 756 |
+
fn=handle_evaluation,
|
| 757 |
+
inputs=[
|
| 758 |
+
input_lang,
|
| 759 |
+
output_lang,
|
| 760 |
+
extracted_text,
|
| 761 |
+
output_text,
|
| 762 |
+
notation,
|
| 763 |
+
correct_translation
|
| 764 |
+
],
|
| 765 |
+
outputs=evaluation_status
|
| 766 |
+
).then(
|
| 767 |
+
fn=clear_evaluation_fields,
|
| 768 |
+
inputs=[],
|
| 769 |
+
outputs=[notation, correct_translation, evaluation_status]
|
| 770 |
+
)
|
| 771 |
|
| 772 |
return interface
|
| 773 |
|