| import os |
| import spaces |
| import io |
| import base64 |
| import json |
| import re |
| import random |
| import numpy as np |
| import soundfile as sf |
| import torch |
| from PIL import Image |
|
|
| |
| import transformers.activations |
| if not hasattr(transformers.activations, "PytorchGELUTanh"): |
| if hasattr(transformers.activations, "GELUTanh"): |
| transformers.activations.PytorchGELUTanh = transformers.activations.GELUTanh |
| else: |
| import torch.nn as nn |
| class PytorchGELUTanh(nn.Module): |
| def forward(self, x): |
| return nn.functional.gelu(x, approximate="tanh") |
| transformers.activations.PytorchGELUTanh = PytorchGELUTanh |
|
|
| from transformers import AutoModelForCausalLM, AutoTokenizer |
| from diffusers import SanaSprintPipeline |
| from qwen_tts import Qwen3TTSModel |
| from gradio import Server |
| from fastapi.responses import HTMLResponse |
| from fastapi.staticfiles import StaticFiles |
|
|
| |
| app = Server() |
|
|
| |
| os.makedirs("games", exist_ok=True) |
|
|
| |
| app.mount("/games", StaticFiles(directory="games"), name="games") |
|
|
| |
| try: |
| |
| |
| llm_repo = "bartowski/Qwen2.5-14B-Instruct-GGUF" |
| gguf_filename = "Qwen2.5-14B-Instruct-Q4_0.gguf" |
|
|
| print(f"Loading GGUF LLM model {llm_repo} ({gguf_filename}) on GPU via transformers...") |
| tokenizer = AutoTokenizer.from_pretrained(llm_repo, gguf_file=gguf_filename) |
| llm_model = AutoModelForCausalLM.from_pretrained( |
| llm_repo, |
| gguf_file=gguf_filename, |
| torch_dtype=torch.bfloat16, |
| device_map="auto" |
| ) |
|
|
| print("Loading Image model Sana Sprint 1.6B on GPU...") |
| sana_pipe = SanaSprintPipeline.from_pretrained( |
| "Efficient-Large-Model/Sana_Sprint_1.6B_1024px_diffusers", |
| torch_dtype=torch.bfloat16 |
| ) |
| sana_pipe.to("cuda:0") |
|
|
| print("Loading TTS model Qwen3-TTS 1.7B on GPU...") |
| |
| |
| try: |
| tts_model = Qwen3TTSModel.from_pretrained( |
| "Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice", |
| device_map="cuda:0", |
| dtype=torch.bfloat16, |
| attn_implementation="kernels-community/flash-attn3", |
| ) |
| print("Qwen3-TTS 1.7B loaded successfully with Flash Attention 3.") |
| except Exception as e_fa3: |
| print(f"Could not initialize Flash Attention 3 ({e_fa3}). Attempting SDPA fallback...") |
| try: |
| tts_model = Qwen3TTSModel.from_pretrained( |
| "Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice", |
| device_map="cuda:0", |
| dtype=torch.bfloat16, |
| attn_implementation="sdpa", |
| ) |
| print("Qwen3-TTS 1.7B loaded successfully with SDPA fallback.") |
| except Exception as e_all: |
| |
| tts_model = Qwen3TTSModel.from_pretrained( |
| "Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice", |
| device_map="cuda:0", |
| dtype=torch.bfloat16, |
| ) |
| print("Qwen3-TTS 1.7B loaded successfully with default attention.") |
| |
| except Exception as e: |
| print(f"Error loading models on GPU during startup: {e}") |
|
|
| |
| |
| |
| LOCALIZATION_DATABASE = { |
| "English": { |
| "title": "📘 WordConjure: Multimodal Vocabulary Practice", |
| "subtitle": "An educational system that automatically generates context-rich translations, clean pronunciation guides, and bespoke visual cards to optimize foreign language acquisition.", |
| "tutorial_text": "<strong>First:</strong> Select your target preferences below and click <strong>\"Generate Vocabulary\"</strong> to load your custom multimodal study deck. <strong>Then:</strong> Navigate to the <strong>\"Practice Exercises\"</strong> tab above to interactively test your memory through structured games.", |
| "settings": "⚙️ Session Configuration", |
| "word_count_label": "🔢 Vocabulary size to generate:", |
| "expl_lang_label": "🗣️ Explanation Language", |
| "app_lang_label": "📱 Application Language", |
| "source_lang": "🌍 Source Language (Native)", |
| "target_lang": "🎯 Target Language to Practice", |
| "btn_get_words": "⚡ Generate Vocabulary", |
| "tab_vocab": "📖 Vocabulary Deck", |
| "tab_games": "🎮 Practice Exercises", |
| "original_header": "Target Word", |
| "translation_header": "Translation", |
| "explanation_header": "Contextual Definition", |
| "visual_header": "Visual Card", |
| "audio_header": "Pronunciation", |
| "game_selection_title": "Select Your Practice Exercise", |
| "game_memory_title": "Interactive Memory Association", |
| "game_memory_desc": "Match target terms with their translated counterparts and generated visual cards to reinforce semantic retention.", |
| "game_monster_title": "Target Word Association (Word Monster)", |
| "game_monster_desc": "Select and present the appropriate translation card that accurately matches the requested target concept.", |
| "game_quiz_title": "Acoustic & Visual Assessment", |
| "game_quiz_desc": "Examine the audio pronunciation or visual cue and identify the correct matching term from multiple choices.", |
| "game_scramble_title": "Orthographic Word Reconstruction", |
| "game_scramble_desc": "Reassemble scrambled character sequences into the correct spelling of the translated target term.", |
| "game_linker_title": "Visual Term Correspondence Mapping", |
| "game_linker_desc": "Perform bilateral matching between generated visual cues and target practice words to solidify associations.", |
| "game_monster_feed_me": "PROVIDE THE CARD FOR:", |
| "game_monster_correct": "Correct translation identified! 🎉", |
| "game_monster_incorrect": "Incorrect card selected. 😢", |
| "game_monster_no_words": "Vocabulary list is empty!", |
| "game_monster_no_words_desc": "Please return to the 'Vocabulary Deck' tab, configure your target language, and select 'Generate Vocabulary' first.", |
| "game_quiz_hint_btn": "Hint 💡", |
| "game_quiz_replay_audio": "Play Audio 🔊", |
| "game_quiz_correct": "Correct! 🎉", |
| "game_quiz_incorrect": "Incorrect! Try again. 😢", |
| "game_quiz_question": "Identify this term:", |
| "game_quiz_need_four": "Please generate a minimum of 4 words to initialize the Acoustic & Visual Assessment.", |
| "game_scramble_clue_label": "Translate this term:", |
| "game_scramble_explanation_label": "Definition clue:", |
| "game_scramble_reset_btn": "Reset 🔄", |
| "game_scramble_play_audio": "Pronounce 🔊", |
| "game_scramble_correct": "Perfect Spelling! 🎉", |
| "game_scramble_incorrect": "Incorrect. Try again.", |
| "game_memory_moves": "Moves:", |
| "game_memory_congrats": "Success! All associations matched perfectly. 🎉", |
| "game_memory_need_words": "Please generate a minimum of 4 words to play Interactive Memory Association.", |
| "game_linker_instruction": "Select a visual card on the left, then map it to its corresponding practice word on the right.", |
| "game_linker_hint_btn": "Hint 💡", |
| "game_linker_correct": "Perfect Association! 🎉", |
| "game_linker_incorrect": "Mismatch! Try again. 😢", |
| "game_linker_select_clue": "Select a card on the left first to receive a context hint!", |
| "game_linker_need_words": "Please generate a minimum of 4 words to play Visual Term Correspondence Mapping." |
| }, |
| "Spanish": { |
| "title": "📘 WordConjure: Práctica Multimodal de Vocabulario", |
| "subtitle": "Un sistema educativo que genera traducciones detalladas, guías de pronunciación claras y tarjetas visuales para optimizar el aprendizaje de idiomas.", |
| "tutorial_text": "<strong>Primero:</strong> Seleccione sus preferencias abajo y haga clic en <strong>\"Generar Vocabulario\"</strong> para cargar su mazo de estudio. <strong>Luego:</strong> Vaya a la pestaña <strong>\"Ejercicios de Práctica\"</strong> arriba para poner a prueba su memoria con juegos interactivos.", |
| "settings": "⚙️ Configuración de la sesión", |
| "word_count_label": "🔢 Cantidad de palabras a generar:", |
| "expl_lang_label": "🗣️ Idioma de la explicación", |
| "app_lang_label": "📱 Idioma de la aplicación", |
| "source_lang": "🌍 Idioma nativo (origen)", |
| "target_lang": "🎯 Idioma de práctica (destino)", |
| "btn_get_words": "⚡ Generar Vocabulario", |
| "tab_vocab": "📖 Mazo de Vocabulario", |
| "tab_games": "🎮 Ejercicios de Práctica", |
| "original_header": "Palabra Objetivo", |
| "translation_header": "Traducción", |
| "explanation_header": "Definición Contextual", |
| "visual_header": "Tarjeta Visual", |
| "audio_header": "Pronunciación", |
| "game_selection_title": "Seleccione el ejercicio de práctica", |
| "game_memory_title": "Asociación Interactiva de Memoria", |
| "game_memory_desc": "Asocie los términos con sus traducciones y tarjetas visuales para reforzar la retención semántica.", |
| "game_monster_title": "Asociación de Palabras (Monstruo de Palabras)", |
| "game_monster_desc": "Seleccione y presente la tarjeta de traducción que coincida exactamente con el concepto solicitado.", |
| "game_quiz_title": "Evaluación Acústica y Visual", |
| "game_quiz_desc": "Escuche la pronunciación o examine la pista visual e identifique el término correcto de opción múltiple.", |
| "game_scramble_title": "Reconstrucción Ortográfica de Palabras", |
| "game_scramble_desc": "Ordene la secuencia de caracteres para deletrear correctamente la traducción del término.", |
| "game_linker_title": "Mapeo de Correspondencia Visual", |
| "game_linker_desc": "Establezca correspondencias bilaterales entre imágenes de apoyo y palabras de práctica.", |
| "game_monster_feed_me": "PROPORCIONE LA TARJETA PARA:", |
| "game_monster_correct": "¡Traducción correcta identificada! 🎉", |
| "game_monster_incorrect": "Tarjeta incorrecta seleccionada. 😢", |
| "game_monster_no_words": "¡La lista de vocabulario está vacía!", |
| "game_monster_no_words_desc": "Regrese al 'Mazo de Vocabulario', configure el idioma de destino y presione 'Generar Vocabulario'.", |
| "game_quiz_hint_btn": "Pista 💡", |
| "game_quiz_replay_audio": "Reproducir Audio 🔊", |
| "game_quiz_correct": "¡Correcto! 🎉", |
| "game_quiz_incorrect": "¡Incorrecto! Inténtelo de nuevo. 😢", |
| "game_quiz_question": "Identifique este término:", |
| "game_quiz_need_four": "Genere un mínimo de 4 palabras para iniciar la Evaluación Acústica y Visual.", |
| "game_scramble_clue_label": "Traduzca este término:", |
| "game_scramble_explanation_label": "Pista de definición:", |
| "game_scramble_reset_btn": "Restablecer 🔄", |
| "game_scramble_play_audio": "Pronunciar 🔊", |
| "game_scramble_correct": "¡Ortografía perfecta! 🎉", |
| "game_scramble_incorrect": "Incorrecto. Inténtelo de nuevo.", |
| "game_memory_moves": "Movimientos:", |
| "game_memory_congrats": "¡Éxito! Todas las asociaciones se completaron perfectamente. 🎉", |
| "game_memory_need_words": "Genere un mínimo de 4 palabras para iniciar la Asociación Interactiva de Memoria.", |
| "game_linker_instruction": "Seleccione una tarjeta visual a la izquierda, luego asóciela con su palabra correspondiente a la derecha.", |
| "game_linker_hint_btn": "Pista 💡", |
| "game_linker_correct": "¡Asociación perfecta! 🎉", |
| "game_linker_incorrect": "¡No coincide! Inténtelo de nuevo. 😢", |
| "game_linker_select_clue": "¡Seleccione una tarjeta a la izquierda primero para obtener una pista!", |
| "game_linker_need_words": "Genere un mínimo de 4 palabras para jugar al Mapeo de Correspondencia Visual." |
| }, |
| "French": { |
| "title": "📘 WordConjure : Pratique Multimodale du Vocabulaire", |
| "subtitle": "Une plateforme d'entraînement linguistique générant des définitions contextuelles, des cartes illustrées et des guides de prononciation clairs.", |
| "tutorial_text": "<strong>D'abord :</strong> Sélectionnez vos préférences ci-dessous et cliquez sur <strong>\"Générer le vocabulaire\"</strong> pour charger votre deck. <strong>Ensuite :</strong> Allez dans l'onglet <strong>\"Exercices d'entraînement\"</strong> ci-dessus pour tester votre mémoire avec des jeux interactifs.", |
| "settings": "⚙️ Configuration de la session", |
| "word_count_label": "🔢 Nombre de mots à générer :", |
| "expl_lang_label": "🗣️ Langue d'explication", |
| "app_lang_label": "📱 Langue de l'application", |
| "source_lang": "🌍 Langue maternelle", |
| "target_lang": "🎯 Langue à pratiquer", |
| "btn_get_words": "⚡ Générer le vocabulaire", |
| "tab_vocab": "📖 Deck de vocabulaire", |
| "tab_games": "🎮 Exercices d'entraînement", |
| "original_header": "Mot ciblé", |
| "translation_header": "Traduction", |
| "explanation_header": "Définition contextuelle", |
| "visual_header": "Carte visuelle", |
| "audio_header": "Prononciation", |
| "game_selection_title": "Sélectionnez l'exercice d'entraînement", |
| "game_memory_title": "Association de mémoire interactive", |
| "game_memory_desc": "Associez les termes cibles avec leurs traductions et visuels correspondants pour renforcer la rétention sémantique.", |
| "game_monster_title": "Association conceptuelle (Monstre des mots)", |
| "game_monster_desc": "Sélectionnez et présentez la carte de traduction correspondant précisément au concept ciblé.", |
| "game_quiz_title": "Évaluation acoustique et visuelle", |
| "game_quiz_desc": "Écoutez la prononciation ou examinez l'indice visuel, puis identifiez le terme correspondant correct.", |
| "game_scramble_title": "Reconstruction orthographique", |
| "game_scramble_desc": "Réarrangez les lettres pour épeler correctement la traduction du mot cible.", |
| "game_linker_title": "Cartographie de correspondance visuelle", |
| "game_linker_desc": "Faites correspondre les cartes illustrées de gauche avec les mots d'entraînement à droite.", |
| "game_monster_feed_me": "FOURNIR LA CARTE POUR :", |
| "game_monster_correct": "Traduction correcte identifiée ! 🎉", |
| "game_monster_incorrect": "Carte incorrecte sélectionnée. 😢", |
| "game_monster_no_words": "La liste de vocabulaire est vide !", |
| "game_monster_no_words_desc": "Veuillez d'abord configurer vos préférences et générer des mots dans l'onglet 'Deck de vocabulaire'.", |
| "game_quiz_hint_btn": "Indice 💡", |
| "game_quiz_replay_audio": "Jouer l'audio 🔊", |
| "game_quiz_correct": "Correct ! 🎉", |
| "game_quiz_incorrect": "Incorrect ! Réessayez. 😢", |
| "game_quiz_question": "Identifiez ce terme :", |
| "game_quiz_need_four": "Veuillez générer au moins 4 mots pour initialiser l'Évaluation acoustique et visuelle.", |
| "game_scramble_clue_label": "Traduisez ce terme :", |
| "game_scramble_explanation_label": "Indice de définition :", |
| "game_scramble_reset_btn": "Réinitialiser 🔄", |
| "game_scramble_play_audio": "Prononcer 🔊", |
| "game_scramble_correct": "Orthographe parfaite ! 🎉", |
| "game_scramble_incorrect": "Incorrect. Réessayez.", |
| "game_memory_moves": "Mouvements :", |
| "game_memory_congrats": "Succès ! Toutes les associations ont été trouvées. 🎉", |
| "game_memory_need_words": "Générez au moins 4 mots pour démarrer l'Association de mémoire interactive.", |
| "game_linker_instruction": "Sélectionnez une carte visuelle à gauche, puis associez-la au mot correspondant à droite.", |
| "game_linker_hint_btn": "Indice 💡", |
| "game_linker_correct": "Association parfaite ! 🎉", |
| "game_linker_incorrect": "Incompatibilité ! Réessayez. 😢", |
| "game_linker_select_clue": "Sélectionnez d'abord une carte à gauche pour obtenir un indice.", |
| "game_linker_need_words": "Générez au moins 4 mots pour jouer à la Cartographie de correspondance visuelle." |
| }, |
| "German": { |
| "title": "📘 WordConjure: Multimodales Vokabeltraining", |
| "subtitle": "Eine Plattform zur Vokabelerweiterung mit kontextbezogenen Erklärungen, visuellen Karten und klaren Aussprachebeispielen für ein strukturiertes Lernen.", |
| "tutorial_text": "<strong>Zuerst:</strong> Wählen Sie unten Ihre Einstellungen und klicken Sie auf <strong>\"Vokabeln generieren\"</strong>, um Ihren Lernstapel zu laden. <strong>Danach:</strong> Wechseln Sie oben auf den Reiter <strong>\"Übungsbereich\"</strong>, um Ihr Gedächtnis mit interaktiven Spielen zu testen.", |
| "settings": "⚙️ Sitzungskonfiguration", |
| "word_count_label": "🔢 Anzahl der zu generierenden Wörter:", |
| "expl_lang_label": "🗣️ Erklärungssprache", |
| "app_lang_label": "📱 App-Sprache", |
| "source_lang": "🌍 Ausgangssprache (Muttersprache)", |
| "target_lang": "🎯 Zielsprache zum Üben", |
| "btn_get_words": "⚡ Vokabeln generieren", |
| "tab_vocab": "📖 Vokabel-Stapel", |
| "tab_games": "🎮 Übungsbereich", |
| "original_header": "Zielwort", |
| "translation_header": "Übersetzung", |
| "explanation_header": "Kontextbezogene Definition", |
| "visual_header": "Bildkarte", |
| "audio_header": "Aussprache", |
| "game_selection_title": "Wählen Sie eine Übungseinheit", |
| "game_memory_title": "Interaktive Gedächtnisassoziation", |
| "game_memory_desc": "Verbinden Sie Zielbegriffe mit ihren Übersetzungen und visuellen Karten, um die semantische Merkfähigkeit zu stärken.", |
| "game_monster_title": "Begriffszuordnung (Wortmonster)", |
| "game_monster_desc": "Wählen Sie die Übersetzungskarte aus, die genau zum gesuchten Begriff passt.", |
| "game_quiz_title": "Akustische & Visuelle Bewertung", |
| "game_quiz_desc": "Hören Sie sich die Aussprache an oder prüfen Sie die Bildkarte, um den passenden Begriff auszuwählen.", |
| "game_scramble_title": "Orthographische Rekonstruktion", |
| "game_scramble_desc": "Bringen Sie die durcheinandergewürfelten Buchstaben in die richtige Reihenfolge, um den Begriff korrekt zu schreiben.", |
| "game_linker_title": "Visuelle Begriffsverknüpfung", |
| "game_linker_desc": "Verbinden Sie die Bildkarten auf der linken Seite mit den Übungswörtern auf der rechten Seite.", |
| "game_monster_feed_me": "KARTE PRÄSENTIEREN FÜR:", |
| "game_monster_correct": "Richtige Übersetzung zugeordnet! 🎉", |
| "game_monster_incorrect": "Falsche Karte ausgewählt. 😢", |
| "game_monster_no_words": "Vokabelliste ist leer!", |
| "game_monster_no_words_desc": "Bitte kehren Sie zum Reiter 'Vokabel-Stapel' zurück und wählen Sie 'Vokabeln generieren'.", |
| "game_quiz_hint_btn": "Hinweis 💡", |
| "game_quiz_replay_audio": "Audio abspielen 🔊", |
| "game_quiz_correct": "Richtig! 🎉", |
| "game_quiz_incorrect": "Falsch! Versuchen Sie es noch einmal. 😢", |
| "game_quiz_question": "Identifizieren Sie diesen Begriff:", |
| "game_quiz_need_four": "Bitte generieren Sie mindestens 4 Wörter für die akustische und visuelle Bewertung.", |
| "game_scramble_clue_label": "Übersetzen Sie diesen Begriff:", |
| "game_scramble_explanation_label": "Definitionshinweis:", |
| "game_scramble_reset_btn": "Zurücksetzen 🔄", |
| "game_scramble_play_audio": "Anhören 🔊", |
| "game_scramble_correct": "Perfekte Rechtschreibung! 🎉", |
| "game_scramble_incorrect": "Fehlerhaft. Versuchen Sie es noch einmal.", |
| "game_memory_moves": "Züge:", |
| "game_memory_congrats": "Erfolgreich gelöst! Alle Zuordnungen stimmen. 🎉", |
| "game_memory_need_words": "Bitte generieren Sie mindestens 4 Wörter für die interaktive Gedächtnisassoziation.", |
| "game_linker_instruction": "Wählen Sie links eine Bildkarte aus und ordnen Sie sie dem passenden Übungswort rechts zu.", |
| "game_linker_hint_btn": "Hinweis 💡", |
| "game_linker_correct": "Perfekte Zuordnung! 🎉", |
| "game_linker_incorrect": "Keine Übereinstimmung. Versuchen Sie es noch einmal. 😢", |
| "game_linker_select_clue": "Wählen Sie zuerst links eine Karte aus, um einen Hinweis zu erhalten.", |
| "game_linker_need_words": "Bitte generieren Sie mindestens 4 Wörter für die visuelle Begriffsverknüpfung." |
| }, |
| "Chinese": { |
| "title": "📘 WordConjure: 多模态词汇训练系统", |
| "subtitle": "一个针对多语种学习的词汇训练系统,通过自动生成上下文释义、视觉配图卡片与纯正发音,帮助学习者巩固语言记忆。", |
| "tutorial_text": "<strong>首先:</strong>在下方选择您的设置并点击<strong>“生成训练词汇”</strong>以加载您的多模态词汇卡组。<strong>然后:</strong>切换到上方的<strong>“强化练习”</strong>标签页,通过互动游戏测试您的记忆效果。", |
| "settings": "⚙️ 系统配置面板", |
| "word_count_label": "🔢 词汇生成数量:", |
| "expl_lang_label": "🗣️ 释义语言选项", |
| "app_lang_label": "📱 应用显示语言", |
| "source_lang": "🌍 母语 (源语言)", |
| "target_lang": "🎯 练习目标语言", |
| "btn_get_words": "⚡ 生成训练词汇", |
| "tab_vocab": "📖 词汇卡组", |
| "tab_games": "🎮 强化练习", |
| "original_header": "目标词汇", |
| "translation_header": "词汇翻译", |
| "explanation_header": "上下文释义", |
| "visual_header": "视觉配图", |
| "audio_header": "语音发音", |
| "game_selection_title": "选择强化训练模式", |
| "game_memory_title": "双向记忆关联", |
| "game_memory_desc": "翻转卡片进行目标词汇、翻译词汇和视觉插图的多维度记忆匹配。", |
| "game_monster_title": "概念具象识别 (单词怪兽)", |
| "game_monster_desc": "根据指示的概念要求,准确提交匹配的翻译词汇卡片。", |
| "game_quiz_title": "视听综合测验", |
| "game_quiz_desc": "通过听辨语音发音或观察视觉卡片,从多个备选项中选出正确目标词汇。", |
| "game_scramble_title": "词形拼写重建", |
| "game_scramble_desc": "将打乱的字母重新排列,拼写出目标翻译词汇的正确拼写形式。", |
| "game_linker_title": "双侧视觉连线", |
| "game_linker_desc": "将左侧生成的视觉卡片与右侧相应的目标词汇建立一对一关联。", |
| "game_monster_feed_me": "请提交对应的卡片:", |
| "game_monster_correct": "匹配正确!🎉", |
| "game_monster_incorrect": "匹配错误,请重试。😢", |
| "game_monster_no_words": "训练词汇卡组为空!", |
| "game_monster_no_words_desc": "请先返回“词汇卡组”标签页,选择目标语言并点击“生成训练词汇”。", |
| "game_quiz_hint_btn": "提示 💡", |
| "game_quiz_replay_audio": "重播音频 🔊", |
| "game_quiz_correct": "回答正确!🎉", |
| "game_quiz_incorrect": "回答错误,请重试!😢", |
| "game_quiz_question": "请识别此词汇:", |
| "game_quiz_need_four": "请至少生成 4 个词汇以开启视听综合测验。", |
| "game_scramble_clue_label": "翻译该词汇:", |
| "game_scramble_explanation_label": "释义线索:", |
| "game_scramble_reset_btn": "重置 🔄", |
| "game_scramble_play_audio": "发音 🔊", |
| "game_scramble_correct": "拼写完全正确!🎉", |
| "game_scramble_incorrect": "拼写错误,请重试。", |
| "game_memory_moves": "操作步数:", |
| "game_memory_congrats": "恭喜!全部卡片匹配成功。🎉", |
| "game_memory_need_words": "请至少生成 4 个词汇以开启双向记忆关联模式。", |
| "game_linker_instruction": "先点击左侧的视觉卡片,然后对应右侧的目标词汇进行关联。", |
| "game_linker_hint_btn": "提示 💡", |
| "game_linker_correct": "关联正确!🎉", |
| "game_linker_incorrect": "不匹配,请重试。😢", |
| "game_linker_select_clue": "请先选择左侧的卡片以获取线索提示!", |
| "game_linker_need_words": "请至少生成 4 个词汇以开启双侧视觉连线模式。" |
| }, |
| "Japanese": { |
| "title": "📘 WordConjure:多言語対応語彙トレーニング", |
| "subtitle": "コンテキスト解説、イラストカード、標準音声ガイダンスを自動生成し、体系的な学習体験を提供する言語トレーニングシステムです。", |
| "tutorial_text": "<strong>まず最初に:</strong>以下で設定を選択し、<strong>「単語リストを生成」</strong>をクリックして単語デッキを読み込みます。<strong>次に:</strong>上の**「実践トレーニング」**タブに切り替えて、インタラクティブなゲームで記憶力をテストします。", |
| "settings": "⚙️ セッション設定", |
| "word_count_label": "🔢 生成する単語数:", |
| "expl_lang_label": "🗣️ 解説言語の選択", |
| "app_lang_label": "📱 アプリ表示言語", |
| "source_lang": "🌍 母国語(ソース)", |
| "target_lang": "🎯 練習する対象言語", |
| "btn_get_words": "⚡ 単語リストを生成", |
| "tab_vocab": "📖 語彙カードデッキ", |
| "tab_games": "🎮 実践トレーニング", |
| "original_header": "対象単語", |
| "translation_header": "翻訳", |
| "explanation_header": "コンテキスト解説", |
| "visual_header": "イラストカード", |
| "audio_header": "音声発音", |
| "game_selection_title": "演習メニューの選択", |
| "game_memory_title": "インタラクティブメモリ連想", |
| "game_memory_desc": "対象の言葉と翻訳、対応するイラストカードを神経衰弱方式でマッチングさせ、意味論的な定着を促します。", |
| "game_monster_title": "ターゲット概念マッチング (単語モンスター)", |
| "game_monster_desc": "提示された指示概念に合う適切な翻訳カードを選択して提出します。", |
| "game_quiz_title": "視聴覚総合テスト", |
| "game_quiz_desc": "音声発音やイラストを確認し、複数の選択肢から正しい対象単語を識別します。", |
| "game_scramble_title": "スペル再構成演習", |
| "game_scramble_desc": "ランダムに並べ替えられたアルファベットを並べ替え、正しいスペルを完成させます。", |
| "game_linker_title": "バイラテラル・ビジュアルリンカー", |
| "game_linker_desc": "左側のイラストカードと右側の対応する練習用単語を正しく結びつけます。", |
| "game_monster_feed_me": "該当するカードを選択:", |
| "game_monster_correct": "正確な翻訳が識別されました!🎉", |
| "game_monster_incorrect": "正しくないカードが選択されました。😢", |
| "game_monster_no_words": "語彙カードデッキが空です!", |
| "game_monster_no_words_desc": "「語彙カードデッキ」タブに戻り、設定をしてから「単語リストを生成」を押してください。", |
| "game_quiz_hint_btn": "ヒント 💡", |
| "game_quiz_replay_audio": "音声を再再生 🔊", |
| "game_quiz_correct": "正解です!🎉", |
| "game_quiz_incorrect": "不正解です。もう一度お試しください。😢", |
| "game_quiz_question": "単語を特定してください:", |
| "game_quiz_need_four": "視聴覚テストを開始するには、少なくとも4つの単語を生成してください。", |
| "game_scramble_clue_label": "単語を翻訳してください:", |
| "game_scramble_explanation_label": "解説ヒント:", |
| "game_scramble_reset_btn": "リセット 🔄", |
| "game_scramble_play_audio": "発音する 🔊", |
| "game_scramble_correct": "完璧なスペルです!🎉", |
| "game_scramble_incorrect": "不正確です。もう一度お試しください。", |
| "game_memory_moves": "手数量:", |
| "game_memory_congrats": "お見事!すべてのカードが正しく一致しました。🎉", |
| "game_memory_need_words": "メモリ連想ゲームをプレイするには、少なくとも4つの単語を生成してください。", |
| "game_linker_instruction": "左側のカードを選択し、右側の対応する練習用の単語をペアにしてください。", |
| "game_linker_hint_btn": "ヒント 💡", |
| "game_linker_correct": "完璧なペアリングです!🎉", |
| "game_linker_incorrect": "不一致です。もう一度お試しください。😢", |
| "game_linker_select_clue": "ヒントを得るには、まず左側のカードを選択してください。", |
| "game_linker_need_words": "バイラテラルリンカーをプレイするには、少なくとも4つの単語を生成してください。" |
| }, |
| "Korean": { |
| "title": "📘 WordConjure: 다중 감각 어휘 학습 시스템", |
| "subtitle": "어휘 습득을 극대화하기 위해 맞춤형 상황 맥락 정의, 시각적 카드, 원어민 발음 가이드를 자동 생성하는 다국어 연습 플랫폼입니다.", |
| "tutorial_text": "<strong>먼저:</strong> 아래에서 원하는 설정을 선택하고 <strong>\"어휘 생성하기\"</strong>를 클릭하여 맞춤형 어휘 덱을 불러오십시오. <strong>그 다음:</strong> 상단의 <strong>\"연습 및 학습 모드\"</strong> 탭으로 이동하여 대화형 게임을 통해 암기 상태를 테스트해 보십시오.", |
| "settings": "⚙️ 세션 환경 설정", |
| "word_count_label": "🔢 생성할 단어 수:", |
| "expl_lang_label": "🗣️ 설명 표시 언어", |
| "app_lang_label": "📱 앱 표시 언어", |
| "source_lang": "🌍 모국어 (원래 언어)", |
| "target_lang": "🎯 학습 대상 언어", |
| "btn_get_words": "⚡ 어휘 생성하기", |
| "tab_vocab": "📖 학습 어휘 덱", |
| "tab_games": "🎮 연습 및 학습 모드", |
| "original_header": "학습 단어", |
| "translation_header": "번역", |
| "explanation_header": "맥락 설명", |
| "visual_header": "시각 카드", |
| "audio_header": "원어민 발음", |
| "game_selection_title": "연습 모드 선택", |
| "game_memory_title": "상호작용적 기억 연상", |
| "game_memory_desc": "단어와 번역, 이미지를 쌍으로 맞추어 인지적 어휘 유지력을 높입니다.", |
| "game_monster_title": "맥락 매칭 어휘 연결 (단어 몬스터)", |
| "game_monster_desc": "제시된 뜻에 정확하게 부합하는 번역 카드를 선택하여 제출하십시오.", |
| "game_quiz_title": "시각 및 청각 종합 평가", |
| "game_quiz_desc": "발음을 듣거나 시각 카드를 분석하여 객관식 보기 중 올바른 표제어를 찾으십시오.", |
| "game_scramble_title": "어휘 맞춤 스펠링 재구성", |
| "game_scramble_desc": "무작위로 뒤섞인 철자 배열을 가다듬어 정확한 번역 어휘를 완성하십시오.", |
| "game_linker_title": "시각 및 언어적 1:1 매핑", |
| "game_linker_desc": "좌측의 이미지 카드와 우측의 학습 단어를 선으로 연결하여 연상 작용을 견고히 합니다.", |
| "game_monster_feed_me": "다음 뜻에 해당되는 카드 선택:", |
| "game_monster_correct": "올바른 단어가 일치되었습니다! 🎉", |
| "game_monster_incorrect": "잘못된 카드를 선택했습니다. 😢", |
| "game_monster_no_words": "어휘 덱이 비어 있습니다!", |
| "game_monster_no_words_desc": "'학습 어휘 덱' 탭으로 돌아가 학습 단어를 먼저 생성해 주십시오.", |
| "game_quiz_hint_btn": "힌트 💡", |
| "game_quiz_replay_audio": "오디오 다시 듣기 🔊", |
| "game_quiz_correct": "정답입니다! 🎉", |
| "game_quiz_incorrect": "틀렸습니다. 다시 시도하십시오! 😢", |
| "game_quiz_question": "어휘를 인식하십시오:", |
| "game_quiz_need_four": "평가를 시작하려면 최소 4개 이상의 단어를 생성해 주십시오.", |
| "game_scramble_clue_label": "단어의 번역을 입력하십시오:", |
| "game_scramble_explanation_label": "정의 힌트:", |
| "game_scramble_reset_btn": "초기화 🔄", |
| "game_scramble_play_audio": "발음 듣기 🔊", |
| "game_scramble_correct": "스펠링이 일치합니다! 🎉", |
| "game_scramble_incorrect": "스펠링 오류입니다. 다시 시도해 주십시오.", |
| "game_memory_moves": "이동 횟수:", |
| "game_memory_congrats": "훌륭합니다! 모든 어휘 매칭이 완료되었습니다. 🎉", |
| "game_memory_need_words": "기억 연상 게임을 진행하려면 최소 4개 이상의 단어가 필요합니다.", |
| "game_linker_instruction": "왼쪽 카드를 선택하고 오른쪽의 어휘 중 올바른 단어를 매핑하십시오.", |
| "game_linker_hint_btn": "힌트 💡", |
| "game_linker_correct": "정확하게 매핑되었습니다! 🎉", |
| "game_linker_incorrect": "불일치합니다. 다시 연결하십시오. 😢", |
| "game_linker_select_clue": "힌트를 얻으려면 왼쪽 카드를 먼저 선택하십시오.", |
| "game_linker_need_words": "매핑 연습을 진행하려면 최소 4개 이상의 단어를 소환해야 합니다." |
| }, |
| "Russian": { |
| "title": "📘 WordConjure: Мультимодальное изучение слов", |
| "subtitle": "Инструмент для эффективного освоения лексики, автоматически генерирующий контекстные определения, ассоциативные карточки и точные аудиопроизношения.", |
| "tutorial_text": "<strong>Сначала:</strong> выберите настройки ниже и нажмите <strong>«Сгенерировать слова»</strong>, чтобы загрузить свой набор карточек. <strong>Затем:</strong> перейдите на вкладку <strong>«Практические упражнения»</strong> выше, чтобы проверить память в интерактивных играх.", |
| "settings": "⚙️ Конфигурация сессии", |
| "word_count_label": "🔢 Количество слов для генерации:", |
| "expl_lang_label": "🗣️ Язык определений", |
| "app_lang_label": "📱 Язык интерфейса", |
| "source_lang": "🌍 Родной язык (исходный)", |
| "target_lang": "🎯 Изучаемый язык (целевой)", |
| "btn_get_words": "⚡ Сгенерировать слова", |
| "tab_vocab": "📖 Набор карточек", |
| "tab_games": "🎮 Практические упражнения", |
| "original_header": "Целевое слово", |
| "translation_header": "Перевод", |
| "explanation_header": "Контекстное определение", |
| "visual_header": "Карточка", |
| "audio_header": "Произношение", |
| "game_selection_title": "Выберите практическое упражнение", |
| "game_memory_title": "Ассоциативное сопоставление", |
| "game_memory_desc": "Переворачивайте карточки, сопоставляя термины с их переводами и изображениями для глубокого закрепления.", |
| "game_monster_title": "Концептуальное сопоставление (Слово-монстр)", |
| "game_monster_desc": "Выберите карточку с правильным переводом, точно соответствующую запрашиваемому значению.", |
| "game_quiz_title": "Аудиовизуальная оценка", |
| "game_quiz_desc": "Определите верное слово на основе произношения или предложенной визуальной иллюстрации.", |
| "game_scramble_title": "Орфографическая реконструкция", |
| "game_scramble_desc": "Расположите перемешанные буквы в правильном порядке, чтобы верно записать перевод.", |
| "game_linker_title": "Визуальное сопоставление", |
| "game_linker_desc": "Установите точные соответствия между визуальными карточками слева и терминами справа.", |
| "game_monster_feed_me": "ПРЕДОСТАВЬТЕ КАРТОЧКУ ДЛЯ:", |
| "game_monster_correct": "Правильный перевод найден! 🎉", |
| "game_monster_incorrect": "Выбрана неверная карточка. 😢", |
| "game_monster_no_words": "Список слов пуст!", |
| "game_monster_no_words_desc": "Пожалуйста, вернитесь во вкладку 'Набор карточек', задайте настройки и нажмите 'Сгенерировать слова'.", |
| "game_quiz_hint_btn": "Подсказка 💡", |
| "game_quiz_replay_audio": "Повторить аудио 🔊", |
| "game_quiz_correct": "Верно! 🎉", |
| "game_quiz_incorrect": "Неверно! Попробуйте еще раз. 😢", |
| "game_quiz_question": "Определите этот термин:", |
| "game_quiz_need_four": "Пожалуйста, создайте не менее 4 слов для инициализации аудиовизуальной оценки.", |
| "game_scramble_clue_label": "Переведите этот термин:", |
| "game_scramble_explanation_label": "Определение для подсказки:", |
| "game_scramble_reset_btn": "Сбросить 🔄", |
| "game_scramble_play_audio": "Произнести 🔊", |
| "game_scramble_correct": "Отличное правописание! 🎉", |
| "game_scramble_incorrect": "Неверно. Попробуйте еще раз.", |
| "game_memory_moves": "Ходы:", |
| "game_memory_congrats": "Успех! Все карточки сопоставлены верно. 🎉", |
| "game_memory_need_words": "Необходимо сгенерировать не менее 4 слов, чтобы начать игру.", |
| "game_linker_instruction": "Выберите карточку слева, затем сопоставьте ее с нужным термином справа.", |
| "game_linker_hint_btn": "Подсказка 💡", |
| "game_linker_correct": "Отличное сопоставление! 🎉", |
| "game_linker_incorrect": "Не совпадает! Попробуйте еще раз. 😢", |
| "game_linker_select_clue": "Сначала выберите карточку слева, чтобы получить текстовую подсказку.", |
| "game_linker_need_words": "Пожалуйста, сгенерируйте минимум 4 слова для практического сопоставления." |
| }, |
| "Portuguese": { |
| "title": "📘 WordConjure: Prática Multimodal de Vocabulário", |
| "subtitle": "Uma plataforma de treino de vocabulário que gera definições de contexto, cartões visuais e pronúncias de áudio claras para apoiar a aquisição de qualquer idioma.", |
| "tutorial_text": "<strong>Primeiro:</strong> selecione suas preferências abaixo e clique em <strong>\"Gerar Vocabulário\"</strong> para carregar seu deck de estudo. <strong>Depois:</strong> acesse a aba <strong>\"Exercícios Práticos\"</strong> acima para testar sua memória com jogos interativos.", |
| "settings": "⚙️ Configurações da Sessão", |
| "word_count_label": "🔢 Quantidade de palavras a gerar:", |
| "expl_lang_label": "🗣️ Idioma das Explicações", |
| "app_lang_label": "📱 Idioma do Aplicativo", |
| "source_lang": "🌍 Idioma Nativo (origem)", |
| "target_lang": "🎯 Idioma para Praticar (destino)", |
| "btn_get_words": "⚡ Gerar Vocabulário", |
| "tab_vocab": "📖 Deck de Vocabulário", |
| "tab_games": "🎮 Exercícios Práticos", |
| "original_header": "Palavra Alvo", |
| "translation_header": "Tradução", |
| "explanation_header": "Definição de Contexto", |
| "visual_header": "Cartão Visual", |
| "audio_header": "Pronúncia", |
| "game_selection_title": "Selecione o seu Exercício de Treino", |
| "game_memory_title": "Associação de Memória Interativa", |
| "game_memory_desc": "Combine os termos originais com as suas traduções e imagens para consolidar a fixação mental.", |
| "game_monster_title": "Associação Conceitual de Palavras (Monstro)", |
| "game_monster_desc": "Identifique e selecione o cartão de tradução que se adapta com precisão à definição solicitada.", |
| "game_quiz_title": "Avaliação Acústica e Visual", |
| "game_quiz_desc": "Analise a pronúncia ou a imagem e escolha o termo original correspondente a partir das escolhas fornecidas.", |
| "game_scramble_title": "Reconstrução Ortográfica", |
| "game_scramble_desc": "Reorganize a sequência de letras para soletrar de forma correta a tradução do termo.", |
| "game_linker_title": "Mapeamento Visual de Correspondência", |
| "game_linker_desc": "Associe diretamente cada cartão ilustrado na esquerda com a palavra de treino correspondente na direita.", |
| "game_monster_feed_me": "FORNEÇA A CARTA PARA:", |
| "game_monster_correct": "Tradução correta identificada! 🎉", |
| "game_monster_incorrect": "Cartão incorreto selecionado. 😢", |
| "game_monster_no_words": "O seu deck de vocabulário está vazio!", |
| "game_monster_no_words_desc": "Por favor, configure as preferências no 'Deck de Vocabulário' e selecione 'Gerar Vocabulário' primeiro.", |
| "game_quiz_hint_btn": "Dica 💡", |
| "game_quiz_replay_audio": "Tocar Áudio 🔊", |
| "game_quiz_correct": "Correto! 🎉", |
| "game_quiz_incorrect": "Incorreto! Tente de novo. 😢", |
| "game_quiz_question": "Identifique este termo:", |
| "game_quiz_need_four": "Invoque ou gere ao menos 4 palavras para iniciar a Avaliação Acústica e Visual.", |
| "game_scramble_clue_label": "Traduza este termo:", |
| "game_scramble_explanation_label": "Dica de definição:", |
| "game_scramble_reset_btn": "Redefinir 🔄", |
| "game_scramble_play_audio": "Pronunciar 🔊", |
| "game_scramble_correct": "Ortografia Perfeita! 🎉", |
| "game_scramble_incorrect": "Incorreto. Tente novamente.", |
| "game_memory_moves": "Jogadas:", |
| "game_memory_congrats": "Sucesso! Todas as combinações foram concluídas perfeitamente. 🎉", |
| "game_memory_need_words": "Crie ao menos 4 palavras no vocabulário para jogar a Associação de Memória.", |
| "game_linker_instruction": "Selecione o cartão visual na esquerda, depois associe-o com a palavra equivalente na direita.", |
| "game_linker_hint_btn": "Dica 💡", |
| "game_linker_correct": "Associação Perfeita! 🎉", |
| "game_linker_incorrect": "Incompatível! Tente de novo. 😢", |
| "game_linker_select_clue": "Selecione primeiro um cartão na esquerda para obter uma dica de contexto.", |
| "game_linker_need_words": "Gere ao menos 4 palavras para praticar o Mapeamento de Correspondência." |
| }, |
| "Italian": { |
| "title": "📘 WordConjure: Pratica Multimodale del Vocabolario", |
| "subtitle": "Una piattaforma avanzata per lo studio dei vocaboli che genera definizioni contestuali, carte visive e guide di pronuncia audio per facilitare l'apprendimento delle lingue.", |
| "tutorial_text": "<strong>Prima:</strong> seleziona le tue preferenze qui sotto e clicca su <strong>\"Genera Vocabolario\"</strong> per caricare il tuo mazzo di studio. <strong>Poi:</strong> vai alla scheda <strong>\"Esercizi di Pratica\"</strong> in alto per testare la tua memoria con i giochi interattivi.", |
| "settings": "⚙️ Configurazione Sessione", |
| "word_count_label": "🔢 Numero di parole da generare:", |
| "expl_lang_label": "🗣️ Lingua delle Spiegazioni", |
| "app_lang_label": "📱 Lingua dell'Applicazione", |
| "source_lang": "🌍 Lingua Madre (origine)", |
| "target_lang": "🎯 Lingua da Praticare (destinazione)", |
| "btn_get_words": "⚡ Genera Vocabolario", |
| "tab_vocab": "📖 Mazzo di Vocaboli", |
| "tab_games": "🎮 Esercizi di Pratica", |
| "original_header": "Parola Obiettivo", |
| "translation_header": "Traduzione", |
| "explanation_header": "Definizione Contestuale", |
| "visual_header": "Carta Visiva", |
| "audio_header": "Pronuncia", |
| "game_selection_title": "Scegli il tuo Esercizio di Studio", |
| "game_memory_title": "Associazione di Memoria Interattiva", |
| "game_memory_desc": "Abbina i termini target con le corrispondenti traduzioni e carte visive per massimizzare la memorizzazione.", |
| "game_monster_title": "Associazione Concettuale (Mostro dei Vocaboli)", |
| "game_monster_desc": "Seleziona e presenta la carta di traduzione esatta corrispondente al concetto indicato.", |
| "game_quiz_title": "Valutazione Acustica e Visiva", |
| "game_quiz_desc": "Analizza il file audio o l'immagine e identifica il termine corretto tra le risposte multiple.", |
| "game_scramble_title": "Ricostruzione Ortografica", |
| "game_scramble_desc": "Ordina i caratteri disordinati per comporre l'esatta traduzione della parola obiettivo.", |
| "game_linker_title": "Mappe di Corrispondenza Visiva", |
| "game_linker_desc": "Fai corrispondere bilateralmente le carte e i vocaboli sul lato destro.", |
| "game_monster_feed_me": "FORNISCI LA CARTA PER:", |
| "game_monster_correct": "Traduzione corretta identificata! 🎉", |
| "game_monster_incorrect": "Carta errata selezionata. 😢", |
| "game_monster_no_words": "Il mazzo di vocaboli è vuoto!", |
| "game_monster_no_words_desc": "Ritorna alla scheda 'Mazzo di Vocaboli', definisci le opzioni e clicca su 'Genera Vocabolario' per iniziare.", |
| "game_quiz_hint_btn": "Suggerimento 💡", |
| "game_quiz_replay_audio": "Riproduci Audio 🔊", |
| "game_quiz_correct": "Corretto! 🎉", |
| "game_quiz_incorrect": "Incorretto! Riprova. 😢", |
| "game_quiz_question": "Identifica questo termine:", |
| "game_quiz_need_four": "Genera almeno 4 parole per avviare l'esercizio di Valutazione Acustica e Visiva.", |
| "game_scramble_clue_label": "Traduci questo termine:", |
| "game_scramble_explanation_label": "Suggerimento di definizione:", |
| "game_scramble_reset_btn": "Ripristina 🔄", |
| "game_scramble_play_audio": "Pronuncia 🔊", |
| "game_scramble_correct": "Ortografia Perfetta! 🎉", |
| "game_scramble_incorrect": "Incorretto. Riprova.", |
| "game_memory_moves": "Mosse:", |
| "game_memory_congrats": "Successo! Tutte le associazioni corrispondono perfettamente. 🎉", |
| "game_memory_need_words": "Genera almeno 4 parole per giocare con l'Associazione di Memoria.", |
| "game_linker_instruction": "Seleziona una carta visiva a sinistra, poi collegala alla parola di pratica corrispondente a destra.", |
| "game_linker_hint_btn": "Suggerimento 💡", |
| "game_linker_correct": "Associazione Perfetta! 🎉", |
| "game_linker_incorrect": "Incompatibile! Riprova. 😢", |
| "game_linker_select_clue": "Seleziona prima una carta a sinistra per ottenere una pista sul contesto.", |
| "game_linker_need_words": "Genera almeno 4 parole per giocare con le Mappe di Corrispondenza Visiva." |
| } |
| } |
|
|
| |
| TTS_SPEAKER_MAPPING = { |
| "English": "Aiden", |
| "Spanish": "Ryan", |
| "French": "Serena", |
| "German": "Aiden", |
| "Chinese": "Serena", |
| "Japanese": "Ono_anna", |
| "Korean": "Sohee", |
| "Russian": "Aiden", |
| "Portuguese": "Ryan", |
| "Italian": "Ryan" |
| } |
|
|
| VOCAB_THEMES = [ |
| "nature and environment", "travel and sightseeing", "cooking and ingredients", |
| "occupations and careers", "hobbies and creative pursuits", "emotions and personalities", |
| "household items and architecture", "animals and biology", "urban life and transportation", |
| "weather, seasons and environment", "shopping and daily routines", "sports, health and human body", |
| "science, space and technology", "art, music and performances", "academic studies and school items" |
| ] |
|
|
| VOCAB_TYPES = [ |
| "a mix of parts of speech", "action verbs", "descriptive adjectives", "useful nouns" |
| ] |
|
|
| @app.api(name="get_localization") |
| def get_localization(user_native_lang: str) -> dict: |
| return LOCALIZATION_DATABASE.get(user_native_lang, LOCALIZATION_DATABASE["English"]) |
|
|
| def query_llm(prompt: str, max_new_tokens: int = 512) -> str: |
| messages = [ |
| {"role": "user", "content": prompt} |
| ] |
| text = tokenizer.apply_chat_template( |
| messages, tokenize=False, add_generation_prompt=True |
| ) |
| model_inputs = tokenizer([text], return_tensors="pt").to("cuda:0") |
| generated_ids = llm_model.generate( |
| **model_inputs, |
| max_new_tokens=max_new_tokens, |
| temperature=0.8, |
| top_p=0.9 |
| ) |
| input_len = model_inputs.input_ids.shape[1] |
| response_tokens = generated_ids[0][input_len:] |
| return tokenizer.decode(response_tokens, skip_special_tokens=True).strip() |
|
|
| def extract_json_array(text: str) -> list: |
| cleaned = text.strip() |
| if cleaned.startswith("```json"): |
| cleaned = cleaned[7:] |
| if cleaned.endswith("```"): |
| cleaned = cleaned[:-3] |
| cleaned = cleaned.strip() |
|
|
| match = re.search(r'\[\s*\[.*\]\s*\]', cleaned, re.DOTALL) |
| if match: |
| try: |
| return json.loads(match.group(0)) |
| except Exception: |
| pass |
| try: |
| return json.loads(cleaned) |
| except Exception as e: |
| print(f"Failed to parse JSON array: {e}") |
| return [] |
|
|
| def generate_visual_base64(image_prompt: str) -> str: |
| prompt = f"A simple, clean, minimalist flat icon style illustration of {image_prompt}, high quality educational flashcard illustration, isolated on white background" |
| with torch.inference_mode(): |
| image = sana_pipe( |
| prompt=prompt, |
| height=768, |
| width=768, |
| num_inference_steps=2, |
| guidance_scale=4.5 |
| ).images[0] |
| buffered = io.BytesIO() |
| image.save(buffered, format="PNG") |
| return base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
| def generate_audio_base64(word: str, language: str) -> str: |
| speaker = TTS_SPEAKER_MAPPING.get(language, "Aiden") |
| with torch.inference_mode(): |
| wavs, sr = tts_model.generate_custom_voice( |
| text=word, |
| language=language, |
| speaker=speaker, |
| instruct="A clear, natural, and direct voice with a calm and stable tone. Moderate speed, no emotion, and neutral inflection.", |
| non_streaming_mode=True, |
| max_new_tokens=50, |
| ) |
| audio_data = wavs[0] |
| buffered = io.BytesIO() |
| sf.write(buffered, audio_data, sr, format="WAV") |
| return base64.b64encode(buffered.getvalue()).decode("utf-8") |
|
|
| @app.api(name="get_translations") |
| @spaces.GPU(duration=30) |
| def get_translations(source_lang: str, target_lang: str, word_count: int, explanation_lang: str) -> list[list[str]]: |
| explanation_lang_target = source_lang if explanation_lang == "source" else target_lang |
| selected_category = random.choice(VOCAB_THEMES) |
| selected_type = random.choice(VOCAB_TYPES) |
| random_seed = random.randint(100000, 999999) |
|
|
| prompt = f"""You are a professional multilingual translator. |
| Generate a vocabulary list of exactly {word_count} words or phrases for language learning. |
| Source Language: {source_lang} |
| Practice/Target Language: {target_lang} |
| |
| To ensure high variety and prevent repeating standard words across sessions, apply the following randomized criteria to select your words: |
| - Focus Topic/Theme: {selected_category} |
| - Grammar/Category: {selected_type} |
| - Generation Session Key: {random_seed} |
| |
| Ensure you select unique and engaging vocabulary. Avoid simple introductory words like "dog", "hello", "goodbye", or "cat" unless they directly fit the requested focus topic. |
| |
| For each item, generate: |
| 1. The source word or phrase. |
| 2. The target translation. |
| 3. A short, simple, clear, and friendly explanation (maximum 2 sentences) written in the {explanation_lang_target} language. |
| 4. An explicit, highly-descriptive illustration prompt in English, designed specifically for a text-to-image generator. |
| |
| You must return ONLY a raw JSON list of lists of strings, where each sublist contains exactly: |
| [source_word, target_translation, explanation, english_image_prompt] |
| |
| Do not include any chat commentary, introduction, or explanations outside the JSON array.""" |
|
|
| response = query_llm(prompt, 1024) |
| print(response) |
| raw_pairs = extract_json_array(response) |
| |
| validated_pairs = [] |
| for item in raw_pairs: |
| if isinstance(item, list) and len(item) >= 4: |
| validated_pairs.append([str(item[0]), str(item[1]), str(item[2]), str(item[3])]) |
| elif isinstance(item, list) and len(item) == 3: |
| validated_pairs.append([str(item[0]), str(item[1]), str(item[2]), f"a minimalist illustration representing {item[1]}"]) |
| elif isinstance(item, list) and len(item) == 2: |
| validated_pairs.append([str(item[0]), str(item[1]), "", f"a minimalist illustration representing {item[1]}"]) |
| |
| selected_words = validated_pairs[:word_count] |
| |
| visuals = [] |
| for item in selected_words: |
| image_prompt = item[3] |
| try: |
| visual_b64 = generate_visual_base64(image_prompt) |
| except Exception as e: |
| print(f"Error generating visual card with prompt '{image_prompt}': {e}") |
| visual_b64 = "" |
| visuals.append(visual_b64) |
| |
| audios = [] |
| for item in selected_words: |
| target_word = item[1] |
| try: |
| audio_b64 = generate_audio_base64(target_word, target_lang) |
| except Exception as e: |
| print(f"Error generating audio track for '{target_word}': {e}") |
| audio_b64 = "" |
| audios.append(audio_b64) |
| |
| results = [] |
| for idx, (original, translated, explanation, _) in enumerate(selected_words): |
| results.append([ |
| original, |
| translated, |
| explanation, |
| visuals[idx], |
| audios[idx] |
| ]) |
| |
| return results |
|
|
| @app.get("/", response_class=HTMLResponse) |
| def homepage(): |
| html_path = "index.html" |
| with open(html_path, "r", encoding="utf-8") as f: |
| return f.read() |
|
|
| if __name__ == "__main__": |
| app.launch(debug=True, show_error=True) |