| import gradio as gr |
| import google.generativeai as genai |
| import random |
| from datasets import load_dataset |
| import difflib |
|
|
| |
| topics = [ |
| "Information Technology & Artificial Intelligence", |
| "Travel & Cultural Heritage", |
| "Economics & Finance", |
| "Smart Agriculture", |
| "Daily Communication", |
| "Scientific Research", |
| "Environment & Climate Change" |
| ] + [ |
| "My New School", |
| "My House", |
| "My Friends", |
| "My Neighbourhood", |
| "Natural Wonders of the Viet Nam", |
| "Our Tet Holiday", |
| "Television", |
| "Sports and Games", |
| "Cities around the World", |
| "Our Houses in the Future", |
| "Our Greener World", |
| "Robots" |
| ] + [ |
| "Hobbies", |
| "Healthy Living", |
| "Community Service", |
| "Music and Arts", |
| "Food and Drink", |
| "A Visit to a School", |
| "Traffic", |
| "Films", |
| "Festivals around the World", |
| "Energy Sources", |
| "Travelling in the Future", |
| "English-speaking Countries" |
| ] + [ |
| "Leisure time", |
| "Life in the countryside", |
| "Teenagers", |
| "Ethnic groups of Viet Nam", |
| "Our customs and traditions", |
| "Lifestyles", |
| "Environmental protection", |
| "Shopping", |
| "Natural disasters", |
| "Communication in the future", |
| "Science and technology", |
| "Life on other planets" |
| ] + [ |
| "Local community", |
| "City life", |
| "Teen stress and pressure", |
| "Life in the past", |
| "Our experiences", |
| "Vietnamese lifestyle: then and now", |
| "Natural wonders of the world", |
| "English speaking countries", |
| "World Englishes", |
| "Planet Earth", |
| "Electronic devices", |
| "Career choices" |
| ] + [ |
| "Family Life", |
| "Humans and the Environment", |
| "Music", |
| "For a Better Community", |
| "Inventions", |
| "Gender Equality", |
| "Viet Nam and International Organisations", |
| "New Ways to Learn", |
| "Protecting the Environment", |
| "Ecotorism" |
| ] + [ |
| "A long and healthy life", |
| "The generation gap", |
| "Cities of the future", |
| "ASEAN and Viet Nam", |
| "Global warming", |
| "Preserving our heritage", |
| "Education options for school-leavers", |
| "Becoming independent", |
| "Social issues", |
| "The ecosystem" |
| ] + [ |
| "Life stories", |
| "A multicultural world", |
| "Green living", |
| "Urbanisation", |
| "The world of work", |
| "Artificial intelligence", |
| "The world of advertising", |
| "Cultural identity", |
| "Choosing a career", |
| "Lifelong learning" |
| ] |
|
|
| tenses = [ |
| "Present Simple", |
| "Present Continuous", |
| "Present Perfect", |
| "Present Perfect Continuous", |
| "Past Simple", |
| "Past Continuous", |
| "Past Perfect", |
| "Past Perfect Continuous", |
| "Future Simple", |
| "Future Continuous", |
| "Future Perfect", |
| "Future Perfect Continuous" |
| ] |
|
|
| grammar_focus_areas = [ |
| "Sentence Structure & Clauses", |
| "Modal Verbs", |
| "Passive Voice & Causatives", |
| "Articles & Prepositions", |
| "Gerunds vs Infinitives", |
| "Determiners & Quantifiers", |
| "Conjunctions", |
| "Adverbial Phrases", |
| "Subject-Verb Agreement" |
| ] |
|
|
| |
| languages = [ |
| "English", |
| "Vietnamese", |
| "Japanese", |
| "Korean", |
| "Chinese", |
| "French", |
| "Spanish", |
| "German" |
| ] |
| conjunction_types = [ |
| "Concession (Although, Despite)", |
| "Reason (Because, Since, Due to)", |
| "Purpose (So that, In order to)", |
| "Result (So...that, Such...that)", |
| "Contrast (While, Whereas)", |
| "Condition (If, Unless, Provided that)" |
| ] |
|
|
| def generate_source_text(api_key, source_lang, target_lang): |
| topic = random.choice(topics) |
| tense = random.choice(tenses) |
| grammar = random.choice(grammar_focus_areas) |
| conjunction_type = random.choice(conjunction_types) |
| if not api_key.strip(): |
| return "⚠️ Please enter your Gemini API Key." |
| |
| try: |
| genai.configure(api_key=api_key) |
| model = genai.GenerativeModel('gemini-3.1-flash-lite-preview') |
| |
| |
| prompt = f""" |
| Act as a professional language teacher. |
| Generate a long sentence in {source_lang} about '{topic}', incorporating {grammar}, {tense} and {conjunction_type} naturally. |
| This text is intended for a student to practice translating from {source_lang} into {target_lang}. |
| Return ONLY the {source_lang} text. Do NOT include any translations, introductions, or explanations. |
| """ |
| |
| response = model.generate_content(prompt) |
| return response.text.strip() |
| except Exception as e: |
| return f"API Error: {str(e)}" |
|
|
| def check_translation(api_key, source_text, user_translation, source_lang, target_lang): |
| if not api_key.strip(): |
| return "⚠️ Please enter your Gemini API Key." |
| if not source_text.strip(): |
| return "⚠️ Please generate source text first." |
| if not user_translation.strip(): |
| return "⚠️ Please enter your translation." |
|
|
| try: |
| genai.configure(api_key=api_key) |
| model = genai.GenerativeModel('gemini-3.1-flash-lite-preview') |
|
|
| |
| prompt = f""" |
| Act as an expert linguist and strict language evaluator. Evaluate the following translation: |
| |
| - Source text ({source_lang}): "{source_text}" |
| - User's translation ({target_lang}): "{user_translation}" |
| |
| Provide detailed feedback formatted in Markdown. |
| IMPORTANT: You MUST write the entire feedback and explanation in {source_lang}. And |
| |
| Strictly follow this structure: |
| 1. **CEFR Level:** Evaluate the vocabulary and sentence structure used in the user's translation and assign an estimated CEFR level (A1, A2, B1, B2, C1, or C2). |
| 2. **Scores:** |
| - Grammar Score: [Score]/10 |
| - Vocabulary Usage Score: [Score]/10 |
| 3. **Detailed Feedback & Corrections:** - Point out specific errors in grammar, word choice, or unnatural phrasing. |
| - Explain clearly why they are incorrect. |
| - Provide step-by-step guidance on how to fix them. |
| 4. **Reference Translations:** Provide 1-2 highly accurate, natural, and native-like alternative translations in {target_lang}. |
| MANDATORY: NO explanation, NO introductory sentences. ONLY return the correctly translated content and formatting unrelated to these points. |
| """ |
| response = model.generate_content(prompt) |
| return response.text.strip() |
| except Exception as e: |
| return f"API Error: {str(e)}" |
|
|
|
|
| |
| |
| |
| print("Đang kết nối với dataset libriheavy...") |
| dataset = load_dataset("mythicinfinity/libriheavy", "large", split="train", streaming=True) |
|
|
| def get_new_sample(): |
| shuffled_dataset = dataset.shuffle(buffer_size=1000, seed=random.randint(0, 10000)) |
| sample = next(iter(shuffled_dataset)) |
| audio_data = sample['audio']['array'] |
| sr = sample['audio']['sampling_rate'] |
| truth_text = sample['text_transcription'] |
| return (sr, audio_data), truth_text, "", "" |
|
|
| def evaluate_listen(user_text, truth_text): |
| if not truth_text: |
| return "<span style='color:red'>Vui lòng nhấn 'Tải Audio Mới' trước khi chấm điểm!</span>" |
| |
| user_words = user_text.strip().lower().split() |
| truth_words = truth_text.strip().lower().split() |
| |
| matcher = difflib.SequenceMatcher(None, truth_words, user_words) |
| correct_words = sum([match.size for match in matcher.get_matching_blocks()]) |
| total_words = len(truth_words) |
| |
| score = (correct_words / total_words) * 100 if total_words > 0 else 0 |
| result_html = f"<h3>Kết quả: {correct_words}/{total_words} từ đúng ({score:.1f}%)</h3>" |
| result_html += f"<p><b>Văn bản gốc:</b> {truth_text}</p>" |
| result_html += f"<p><b>Văn bản của bạn:</b> {user_text}</p>" |
| return result_html |
|
|
| |
| |
| |
| |
| languages = ["English", "Vietnamese", "French", "Japanese", "Korean", "Chinese"] |
|
|
| |
| def generate_source_text(api_key, source_lang, target_lang): |
| if not api_key: |
| return "Vui lòng nhập API Key!" |
| return f"Đây là một câu mẫu tiếng {source_lang} để bạn dịch sang {target_lang}." |
|
|
| def check_translation(api_key, source_text, user_translation, source_lang, target_lang): |
| if not api_key: |
| return "*Vui lòng nhập API Key!*" |
| return f"**Nhận xét từ AI:** Bản dịch '{user_translation}' của bạn khá tốt. (Đang sử dụng Placeholder)" |
|
|
| |
| |
| |
| with gr.Blocks(theme=gr.themes.Soft(), title="ReWrite") as demo: |
|
|
| with gr.Tab("🎧 Listen & Write"): |
| truth_state = gr.State("") |
| with gr.Row(): |
| with gr.Column(): |
| audio_player = gr.Audio(label="Listen the audio", interactive=False) |
| btn_new = gr.Button("🔄 Load new audio", variant="secondary") |
| |
| user_input = gr.Textbox(label="Type your text you listen here...", lines=5, placeholder="Type what you hear...") |
| btn_submit_listen = gr.Button("✅ Evaluate", variant="primary") |
| |
| with gr.Column(): |
| result_output_listen = gr.HTML(label="Kết quả Đánh giá") |
| |
| btn_new.click( |
| fn=get_new_sample, |
| inputs=[], |
| outputs=[audio_player, truth_state, user_input, result_output_listen] |
| ) |
| |
| btn_submit_listen.click( |
| fn=evaluate_listen, |
| inputs=[user_input, truth_state], |
| outputs=[result_output_listen] |
| ) |
|
|
| |
| with gr.Tab("🌍 Translate"): |
| with gr.Row(): |
| api_key_input = gr.Textbox(label="Gemini API Key", type="password", placeholder="Enter your API key here...") |
| source_lang_dropdown = gr.Dropdown(choices=languages, value="English", label="Source Language") |
| target_lang_dropdown = gr.Dropdown(choices=languages, value="Vietnamese", label="Target Language") |
| |
| generate_btn = gr.Button("Generate Source Text", variant="secondary") |
| source_textbox = gr.Textbox(label="Source Text", interactive=False) |
| user_translation_box = gr.Textbox(label="Your Translation", placeholder="Type your translation here...") |
| |
| check_btn = gr.Button("✅ Evaluate", variant="primary") |
| feedback_output = gr.Markdown(value="*AI feedback will appear here.*") |
|
|
| generate_btn.click( |
| fn=generate_source_text, |
| inputs=[api_key_input, source_lang_dropdown, target_lang_dropdown], |
| outputs=source_textbox |
| ) |
| |
| check_btn.click( |
| fn=check_translation, |
| inputs=[api_key_input, source_textbox, user_translation_box, source_lang_dropdown, target_lang_dropdown], |
| outputs=feedback_output |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |