singhalamaan116 commited on
Commit
9dae807
·
verified ·
1 Parent(s): de2f387

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +291 -0
app.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from transformers import pipeline
3
+
4
+ # -----------------------
5
+ # 1. Language + model config
6
+ # -----------------------
7
+
8
+ LANG_CODES = {
9
+ "English": "en",
10
+ "French": "fr",
11
+ "German": "de",
12
+ "Spanish": "es",
13
+ "Swedish": "sv",
14
+ }
15
+
16
+ # Map (src_lang_code, tgt_lang_code) -> MarianMT model
17
+ MODEL_MAP = {
18
+ ("en", "fr"): "Helsinki-NLP/opus-mt-en-fr",
19
+ ("fr", "en"): "Helsinki-NLP/opus-mt-fr-en",
20
+ ("en", "de"): "Helsinki-NLP/opus-mt-en-de",
21
+ ("de", "en"): "Helsinki-NLP/opus-mt-de-en",
22
+ ("en", "es"): "Helsinki-NLP/opus-mt-en-es",
23
+ ("es", "en"): "Helsinki-NLP/opus-mt-es-en",
24
+ ("en", "sv"): "Helsinki-NLP/opus-mt-en-sv",
25
+ ("sv", "en"): "Helsinki-NLP/opus-mt-sv-en",
26
+ }
27
+
28
+ # Lazy-loaded translation pipelines
29
+ _translation_pipelines = {}
30
+
31
+ # One small LLM for explanations / feedback
32
+ explain_llm = pipeline("text2text-generation", model="google/flan-t5-small")
33
+
34
+
35
+ def get_translation_pipeline(src_code: str, tgt_code: str):
36
+ """
37
+ Returns a transformers pipeline for a given language pair, loading it lazily.
38
+ """
39
+ key = (src_code, tgt_code)
40
+ if key not in MODEL_MAP:
41
+ raise ValueError(f"Language pair {src_code}->{tgt_code} not supported yet.")
42
+ if key not in _translation_pipelines:
43
+ model_name = MODEL_MAP[key]
44
+ task = f"translation_{src_code}_to_{tgt_code}"
45
+ _translation_pipelines[key] = pipeline(task, model=model_name)
46
+ return _translation_pipelines[key]
47
+
48
+
49
+ # -----------------------
50
+ # 2. Core translation logic
51
+ # -----------------------
52
+
53
+ def _apply_style_hints(text: str, tone: str, domain: str, tgt_lang: str) -> str:
54
+ """
55
+ MarianMT isn't instruction-tuned, but we can still stuff a hint into the input.
56
+ It won't be perfect, but conceptually shows tone/domain-aware translation.
57
+ """
58
+ hints = []
59
+ if domain != "General":
60
+ hints.append(f"{domain} context")
61
+ if tone != "Neutral":
62
+ hints.append(f"{tone} tone")
63
+
64
+ if hints:
65
+ hint_str = ", ".join(hints)
66
+ # Just prepend some natural-language hints in English.
67
+ styled = f"[{hint_str} in {tgt_lang}] {text}"
68
+ return styled
69
+ return text
70
+
71
+
72
+ def translate_text(text: str, src_lang: str, tgt_lang: str, tone: str, domain: str):
73
+ """
74
+ Main translation function for the UI.
75
+ """
76
+ text = (text or "").strip()
77
+ if not text:
78
+ return "Please enter some text to translate."
79
+
80
+ if src_lang == tgt_lang:
81
+ return text # trivial case
82
+
83
+ src_code = LANG_CODES[src_lang]
84
+ tgt_code = LANG_CODES[tgt_lang]
85
+
86
+ try:
87
+ translator = get_translation_pipeline(src_code, tgt_code)
88
+ except ValueError as e:
89
+ return str(e)
90
+
91
+ styled_input = _apply_style_hints(text, tone, domain, tgt_lang)
92
+
93
+ out = translator(styled_input, max_length=512)
94
+ translated = out[0]["translation_text"]
95
+ return translated.strip()
96
+
97
+
98
+ def back_translate(text: str, src_lang: str, tgt_lang: str, tone: str, domain: str):
99
+ """
100
+ Translate from src -> tgt, then back tgt -> src to check meaning preservation.
101
+ """
102
+ text = (text or "").strip()
103
+ if not text:
104
+ return "Please enter some text to translate.", ""
105
+
106
+ if src_lang == tgt_lang:
107
+ return text, text
108
+
109
+ # First translation: src -> tgt
110
+ forward = translate_text(text, src_lang, tgt_lang, tone, domain)
111
+ # Back translation: tgt -> src (no style hints on the way back)
112
+ backward = translate_text(forward, tgt_lang, src_lang, "Neutral", "General")
113
+
114
+ return forward, backward
115
+
116
+
117
+ def explain_translation(src_text: str, translated_text: str, src_lang: str, tgt_lang: str):
118
+ """
119
+ Use Flan-T5 to explain the translation in simple terms.
120
+ """
121
+ src_text = (src_text or "").strip()
122
+ translated_text = (translated_text or "").strip()
123
+
124
+ if not src_text or not translated_text:
125
+ return "Provide both the original text and the translation to get an explanation."
126
+
127
+ prompt = (
128
+ "You are a helpful language teacher. "
129
+ "Explain this translation to a learner in simple terms. "
130
+ "Mention important word choices, tone, and any interesting grammar.\n\n"
131
+ f"Source language: {src_lang}\n"
132
+ f"Target language: {tgt_lang}\n\n"
133
+ f"Original text:\n{src_text}\n\n"
134
+ f"Translation:\n{translated_text}\n\n"
135
+ "Explanation (in English, 1–2 short paragraphs):"
136
+ )
137
+
138
+ out = explain_llm(prompt, max_new_tokens=256, temperature=0.4)
139
+ return out[0]["generated_text"].strip()
140
+
141
+
142
+ def learning_mode_feedback(src_text: str, user_translation: str, src_lang: str, tgt_lang: str):
143
+ """
144
+ Compare user's translation to model translation and give feedback.
145
+ """
146
+ src_text = (src_text or "").strip()
147
+ user_translation = (user_translation or "").strip()
148
+
149
+ if not src_text or not user_translation:
150
+ return "Please provide both the original text and your translation."
151
+
152
+ # Model's best guess (neutral, general)
153
+ model_translation = translate_text(src_text, src_lang, tgt_lang, "Neutral", "General")
154
+
155
+ prompt = (
156
+ "You are a friendly language teacher. Compare the student's translation to the model translation. "
157
+ "Explain what is good, what could be improved, and give 2–4 concrete suggestions. "
158
+ "Be encouraging, not harsh.\n\n"
159
+ f"Source language: {src_lang}\n"
160
+ f"Target language: {tgt_lang}\n\n"
161
+ f"Original text:\n{src_text}\n\n"
162
+ f"Student's translation:\n{user_translation}\n\n"
163
+ f"Model's translation:\n{model_translation}\n\n"
164
+ "Feedback (in English, short and structured):"
165
+ )
166
+
167
+ out = explain_llm(prompt, max_new_tokens=320, temperature=0.4)
168
+ feedback = out[0]["generated_text"].strip()
169
+
170
+ return f"**Model translation:**\n\n{model_translation}\n\n---\n\n**Feedback:**\n\n{feedback}"
171
+
172
+
173
+ # -----------------------
174
+ # 3. Gradio UI
175
+ # -----------------------
176
+
177
+ LANG_CHOICES = list(LANG_CODES.keys())
178
+ TONES = ["Neutral", "Formal", "Informal", "Simplified"]
179
+ DOMAINS = ["General", "Business", "Technical", "Casual"]
180
+
181
+ with gr.Blocks(title="PolyglotLab – Smart Translator & Learning Studio") as demo:
182
+ gr.Markdown(
183
+ """
184
+ # 🌈 PolyglotLab – Smart Translator & Learning Studio
185
+
186
+ A translation playground built with Hugging Face + Gradio.
187
+
188
+ - ✨ Multi-language translation (English, French, German, Spanish, Swedish)
189
+ - 🎭 Tone hints (neutral, formal, informal, simplified)
190
+ - 🧩 Domain hints (business, technical, casual)
191
+ - 🔁 Back-translation checks for meaning
192
+ - 📚 Learning mode with feedback on *your* translations
193
+ """
194
+ )
195
+
196
+ with gr.Tab("Smart Translate"):
197
+ with gr.Row():
198
+ src_lang_in = gr.Dropdown(LANG_CHOICES, value="English", label="Source language")
199
+ tgt_lang_in = gr.Dropdown(LANG_CHOICES, value="French", label="Target language")
200
+
201
+ text_in = gr.Textbox(
202
+ label="Text to translate",
203
+ lines=4,
204
+ placeholder="Type or paste text here...",
205
+ )
206
+
207
+ with gr.Row():
208
+ tone_in = gr.Dropdown(TONES, value="Neutral", label="Tone hint")
209
+ domain_in = gr.Dropdown(DOMAINS, value="General", label="Domain / context")
210
+
211
+ explain_checkbox = gr.Checkbox(value=True, label="Explain the translation")
212
+
213
+ translate_btn = gr.Button("Translate ✨")
214
+
215
+ translated_out = gr.Textbox(label="Translation", lines=4)
216
+ explanation_out = gr.Markdown(label="Explanation")
217
+
218
+ def translate_and_explain(text, src, tgt, tone, domain, do_explain):
219
+ translation = translate_text(text, src, tgt, tone, domain)
220
+ if not do_explain:
221
+ return translation, ""
222
+ exp = explain_translation(text, translation, src, tgt)
223
+ return translation, exp
224
+
225
+ translate_btn.click(
226
+ fn=translate_and_explain,
227
+ inputs=[text_in, src_lang_in, tgt_lang_in, tone_in, domain_in, explain_checkbox],
228
+ outputs=[translated_out, explanation_out],
229
+ )
230
+
231
+ with gr.Tab("Back-translation Check"):
232
+ gr.Markdown(
233
+ "Translate from source to target, then back to source to see if the meaning is preserved."
234
+ )
235
+
236
+ bt_src_lang = gr.Dropdown(LANG_CHOICES, value="English", label="Source language")
237
+ bt_tgt_lang = gr.Dropdown(LANG_CHOICES, value="German", label="Target language")
238
+ bt_text_in = gr.Textbox(
239
+ label="Original text",
240
+ lines=4,
241
+ placeholder="Type a sentence to test...",
242
+ )
243
+
244
+ bt_tone_in = gr.Dropdown(TONES, value="Neutral", label="Tone hint")
245
+ bt_domain_in = gr.Dropdown(DOMAINS, value="General", label="Domain / context")
246
+
247
+ bt_btn = gr.Button("Run Back-translation 🔁")
248
+
249
+ bt_forward_out = gr.Textbox(label="Forward translation (src → tgt)", lines=4)
250
+ bt_backward_out = gr.Textbox(label="Back-translation (tgt → src)", lines=4)
251
+
252
+ bt_btn.click(
253
+ fn=back_translate,
254
+ inputs=[bt_text_in, bt_src_lang, bt_tgt_lang, bt_tone_in, bt_domain_in],
255
+ outputs=[bt_forward_out, bt_backward_out],
256
+ )
257
+
258
+ with gr.Tab("Learning Mode"):
259
+ gr.Markdown(
260
+ """
261
+ Paste a sentence and your own translation.
262
+ The model will show its translation and give you friendly feedback.
263
+ """
264
+ )
265
+
266
+ lm_src_lang = gr.Dropdown(LANG_CHOICES, value="English", label="Source language")
267
+ lm_tgt_lang = gr.Dropdown(LANG_CHOICES, value="French", label="Target language")
268
+
269
+ lm_src_text = gr.Textbox(
270
+ label="Original text",
271
+ lines=4,
272
+ placeholder="Enter a sentence in the source language...",
273
+ )
274
+
275
+ lm_user_translation = gr.Textbox(
276
+ label="Your translation",
277
+ lines=4,
278
+ placeholder="Write your translation here...",
279
+ )
280
+
281
+ lm_btn = gr.Button("Get feedback 🧑‍🏫")
282
+ lm_feedback_out = gr.Markdown(label="Feedback")
283
+
284
+ lm_btn.click(
285
+ fn=learning_mode_feedback,
286
+ inputs=[lm_src_text, lm_user_translation, lm_src_lang, lm_tgt_lang],
287
+ outputs=lm_feedback_out,
288
+ )
289
+
290
+ if __name__ == "__main__":
291
+ demo.launch()