Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -163,25 +163,51 @@ def transliterate_to_hk(text, lang_choice):
|
|
163 |
print(f"Transliteration error: {e}")
|
164 |
return text
|
165 |
|
166 |
-
def
|
167 |
-
"""Transliterate to
|
168 |
if not text or not text.strip():
|
169 |
return ""
|
170 |
|
171 |
-
|
172 |
-
"Tamil": sanscript.TAMIL,
|
173 |
-
"Malayalam": sanscript.MALAYALAM,
|
174 |
-
"English": None
|
175 |
-
}
|
176 |
-
|
177 |
-
if mapping[lang_choice] is None:
|
178 |
return text # Return as-is for English
|
179 |
|
180 |
try:
|
181 |
-
#
|
182 |
-
|
183 |
-
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
except Exception as e:
|
186 |
print(f"Transliteration error: {e}")
|
187 |
return text
|
@@ -222,11 +248,11 @@ def transcribe_once(audio_path, language_choice, beam_size, temperature):
|
|
222 |
return transcription.strip()
|
223 |
|
224 |
def create_tabular_feedback(intended, actual, lang_choice):
|
225 |
-
"""Create
|
226 |
|
227 |
-
# Get transliterations
|
228 |
-
intended_roman =
|
229 |
-
actual_roman =
|
230 |
intended_hk = transliterate_to_hk(intended, lang_choice)
|
231 |
actual_hk = transliterate_to_hk(actual, lang_choice)
|
232 |
|
@@ -242,49 +268,49 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
242 |
|
243 |
# Create word-by-word comparison table
|
244 |
feedback_html = """
|
245 |
-
<div style='font-family: Arial, sans-serif; padding: 20px;
|
246 |
<h3 style='color: #2c3e50; margin-bottom: 20px; text-align: center;'>📊 Pronunciation Analysis</h3>
|
247 |
"""
|
248 |
|
249 |
-
# Overview table
|
250 |
feedback_html += """
|
251 |
<div style='margin-bottom: 25px;'>
|
252 |
<h4 style='color: #34495e; margin-bottom: 15px;'>📝 Text Comparison</h4>
|
253 |
-
<table style='width: 100%; border-collapse: collapse;
|
254 |
<thead>
|
255 |
-
<tr style='
|
256 |
-
<th style='padding:
|
257 |
-
<th style='padding:
|
258 |
-
<th style='padding:
|
259 |
</tr>
|
260 |
</thead>
|
261 |
<tbody>
|
262 |
-
<tr style='
|
263 |
-
<td style='padding:
|
264 |
-
<td style='padding:
|
265 |
-
<td style='padding:
|
266 |
</tr>
|
267 |
-
<tr
|
268 |
-
<td style='padding:
|
269 |
-
<td style='padding:
|
270 |
-
<td style='padding:
|
271 |
</tr>
|
272 |
</tbody>
|
273 |
</table>
|
274 |
</div>
|
275 |
""".format(intended, intended_roman, actual, actual_roman)
|
276 |
|
277 |
-
# Word-by-word analysis
|
278 |
feedback_html += """
|
279 |
<div style='margin-bottom: 25px;'>
|
280 |
-
<h4 style='color: #34495e; margin-bottom: 15px;'>🔍 Word-by-Word
|
281 |
-
<table style='width: 100%; border-collapse: collapse;
|
282 |
<thead>
|
283 |
-
<tr style='
|
284 |
-
<th style='padding: 12px; text-align: center; font-weight: bold;'>#</th>
|
285 |
-
<th style='padding: 12px; text-align: left; font-weight: bold;'>Expected</th>
|
286 |
-
<th style='padding: 12px; text-align: left; font-weight: bold;'>You Said</th>
|
287 |
-
<th style='padding: 12px; text-align: center; font-weight: bold;'>
|
288 |
</tr>
|
289 |
</thead>
|
290 |
<tbody>
|
@@ -296,7 +322,7 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
296 |
|
297 |
for tag, i1, i2, j1, j2 in sm.get_opcodes():
|
298 |
if tag == 'equal':
|
299 |
-
# Correct words
|
300 |
for idx, word in enumerate(intended_words[i1:i2]):
|
301 |
word_index += 1
|
302 |
correct_words += 1
|
@@ -305,24 +331,25 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
305 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
306 |
|
307 |
feedback_html += f"""
|
308 |
-
<tr style='
|
309 |
-
<td style='padding:
|
310 |
-
<td style='padding:
|
311 |
-
<div style='font-family: monospace; font-size: 16px;'>{word}</div>
|
312 |
-
<div style='font-size:
|
313 |
</td>
|
314 |
-
<td style='padding:
|
315 |
-
<div style='font-family: monospace; font-size: 16px; color: #27ae60;'>{actual_word}</div>
|
316 |
-
<div style='font-size:
|
317 |
</td>
|
318 |
-
<td style='padding:
|
319 |
-
<span style='
|
|
|
320 |
</td>
|
321 |
</tr>
|
322 |
"""
|
323 |
|
324 |
elif tag == 'replace':
|
325 |
-
# Incorrect words
|
326 |
max_words = max(i2-i1, j2-j1)
|
327 |
for idx in range(max_words):
|
328 |
word_index += 1
|
@@ -332,18 +359,19 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
332 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
333 |
|
334 |
feedback_html += f"""
|
335 |
-
<tr style='
|
336 |
-
<td style='padding:
|
337 |
-
<td style='padding:
|
338 |
-
<div style='font-family: monospace; font-size: 16px;'>{expected_word}</div>
|
339 |
-
<div style='font-size:
|
340 |
</td>
|
341 |
-
<td style='padding:
|
342 |
-
<div style='font-family: monospace; font-size: 16px; color: #e74c3c;'>{actual_word}</div>
|
343 |
-
<div style='font-size:
|
344 |
</td>
|
345 |
-
<td style='padding:
|
346 |
-
<span style='
|
|
|
347 |
</td>
|
348 |
</tr>
|
349 |
"""
|
@@ -354,17 +382,18 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
354 |
word_index += 1
|
355 |
roman_word = intended_roman_words[i1 + idx] if (i1 + idx) < len(intended_roman_words) else ""
|
356 |
feedback_html += f"""
|
357 |
-
<tr style='
|
358 |
-
<td style='padding:
|
359 |
-
<td style='padding:
|
360 |
-
<div style='font-family: monospace; font-size: 16px;'>{word}</div>
|
361 |
-
<div style='font-size:
|
362 |
</td>
|
363 |
-
<td style='padding:
|
364 |
<em>Not spoken</em>
|
365 |
</td>
|
366 |
-
<td style='padding:
|
367 |
-
<span style='
|
|
|
368 |
</td>
|
369 |
</tr>
|
370 |
"""
|
@@ -374,17 +403,18 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
374 |
for idx, word in enumerate(actual_words[j1:j2]):
|
375 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
376 |
feedback_html += f"""
|
377 |
-
<tr style='
|
378 |
-
<td style='padding:
|
379 |
-
<td style='padding:
|
380 |
<em>Not expected</em>
|
381 |
</td>
|
382 |
-
<td style='padding:
|
383 |
-
<div style='font-family: monospace; font-size: 16px; color: #
|
384 |
-
<div style='font-size:
|
385 |
</td>
|
386 |
-
<td style='padding:
|
387 |
-
<span style='
|
|
|
388 |
</td>
|
389 |
</tr>
|
390 |
"""
|
@@ -398,32 +428,32 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
398 |
# Calculate accuracy
|
399 |
accuracy = (correct_words / total_words * 100) if total_words > 0 else 0
|
400 |
|
401 |
-
#
|
402 |
feedback_html += f"""
|
403 |
-
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding:
|
404 |
-
<h4 style='margin: 0 0
|
405 |
-
<div style='display: flex; justify-content: space-around; flex-wrap: wrap; gap:
|
406 |
-
<div style='background: rgba(255,255,255,0.
|
407 |
-
<div style='font-size:
|
408 |
-
<div style='font-size:
|
409 |
</div>
|
410 |
-
<div style='background: rgba(255,255,255,0.
|
411 |
-
<div style='font-size:
|
412 |
-
<div style='font-size:
|
413 |
</div>
|
414 |
</div>
|
415 |
-
<div style='margin-top:
|
416 |
"""
|
417 |
|
418 |
-
#
|
419 |
if accuracy >= 95:
|
420 |
-
feedback_html += "<span>🎉
|
421 |
elif accuracy >= 85:
|
422 |
-
feedback_html += "<span>🌟 Excellent
|
423 |
elif accuracy >= 70:
|
424 |
-
feedback_html += "<span>👍 Good job! Keep practicing
|
425 |
elif accuracy >= 50:
|
426 |
-
feedback_html += "<span>📚
|
427 |
else:
|
428 |
feedback_html += "<span>💪 Keep going! Practice makes perfect!</span>"
|
429 |
|
@@ -432,22 +462,22 @@ def create_tabular_feedback(intended, actual, lang_choice):
|
|
432 |
</div>
|
433 |
"""
|
434 |
|
435 |
-
#
|
436 |
if lang_choice in ["Tamil", "Malayalam"]:
|
437 |
feedback_html += f"""
|
438 |
-
<
|
439 |
-
<
|
440 |
-
<div style='display: grid; grid-template-columns: 1fr 1fr; gap: 15px;'>
|
441 |
<div>
|
442 |
-
<strong>Expected:</strong><br>
|
443 |
-
<span style='font-family: monospace; background:
|
444 |
</div>
|
445 |
<div>
|
446 |
-
<strong>You said:</strong><br>
|
447 |
-
<span style='font-family: monospace; background:
|
448 |
</div>
|
449 |
</div>
|
450 |
-
</
|
451 |
"""
|
452 |
|
453 |
feedback_html += "</div>"
|
@@ -474,8 +504,8 @@ def compare_pronunciation(audio, lang_choice, intended_sentence, pass1_beam, pas
|
|
474 |
cer_val = jiwer.cer(intended_sentence, actual_text)
|
475 |
|
476 |
# Get transliterations for both texts
|
477 |
-
intended_roman =
|
478 |
-
actual_roman =
|
479 |
|
480 |
# Create comprehensive tabular feedback
|
481 |
feedback_html, accuracy = create_tabular_feedback(intended_sentence, actual_text, lang_choice)
|
@@ -539,7 +569,7 @@ with gr.Blocks(title="Pronunciation Comparator", theme=gr.themes.Soft()) as demo
|
|
539 |
with gr.Row():
|
540 |
with gr.Column():
|
541 |
pass1_out = gr.Textbox(label="🗣️ What You Said", interactive=False)
|
542 |
-
actual_roman_out = gr.Textbox(label="🔤 Your Pronunciation (
|
543 |
with gr.Column():
|
544 |
wer_out = gr.Textbox(label="📊 Word Error Rate", interactive=False)
|
545 |
cer_out = gr.Textbox(label="📈 Character Error Rate", interactive=False)
|
|
|
163 |
print(f"Transliteration error: {e}")
|
164 |
return text
|
165 |
|
166 |
+
def transliterate_to_simple_roman(text, lang_choice):
|
167 |
+
"""Transliterate to very simple, easy-to-read Roman letters"""
|
168 |
if not text or not text.strip():
|
169 |
return ""
|
170 |
|
171 |
+
if lang_choice == "English":
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
return text # Return as-is for English
|
173 |
|
174 |
try:
|
175 |
+
# Direct character mapping to simple Roman letters
|
176 |
+
if lang_choice == "Tamil":
|
177 |
+
# Tamil to simple Roman mapping
|
178 |
+
tamil_map = {
|
179 |
+
'அ': 'a', 'ஆ': 'aa', 'இ': 'i', 'ஈ': 'ee', 'உ': 'u', 'ஊ': 'oo',
|
180 |
+
'எ': 'e', 'ஏ': 'e', 'ஐ': 'ai', 'ஒ': 'o', 'ஓ': 'o', 'ஔ': 'au',
|
181 |
+
'க': 'ka', 'ங': 'nga', 'ச': 'cha', 'ஞ': 'nya', 'ட': 'ta', 'ண': 'na',
|
182 |
+
'த': 'tha', 'ந': 'na', 'ப': 'pa', 'ம': 'ma', 'ய': 'ya', 'ர': 'ra',
|
183 |
+
'ல': 'la', 'வ': 'va', 'ழ': 'zha', 'ள': 'la', 'ற': 'ra', 'ன': 'na',
|
184 |
+
'்': '', 'ா': 'aa', 'ி': 'i', 'ீ': 'ee', 'ு': 'u', 'ூ': 'oo',
|
185 |
+
'ெ': 'e', 'ே': 'e', 'ை': 'ai', 'ொ': 'o', 'ோ': 'o', 'ௌ': 'au'
|
186 |
+
}
|
187 |
+
simple_text = ""
|
188 |
+
for char in text:
|
189 |
+
simple_text += tamil_map.get(char, char)
|
190 |
+
return simple_text
|
191 |
+
|
192 |
+
elif lang_choice == "Malayalam":
|
193 |
+
# Malayalam to simple Roman mapping
|
194 |
+
malayalam_map = {
|
195 |
+
'അ': 'a', 'ആ': 'aa', 'ഇ': 'i', 'ഈ': 'ee', 'ഉ': 'u', 'ഊ': 'oo',
|
196 |
+
'എ': 'e', 'ഏ': 'e', 'ഐ': 'ai', 'ഒ': 'o', 'ഓ': 'o', 'ഔ': 'au',
|
197 |
+
'ക': 'ka', 'ഗ': 'ga', 'ങ': 'nga', 'ച': 'cha', 'ജ': 'ja', 'ഞ': 'nya',
|
198 |
+
'ട': 'ta', 'ഡ': 'da', 'ണ': 'na', 'ത': 'tha', 'ദ': 'da', 'ന': 'na',
|
199 |
+
'പ': 'pa', 'ബ': 'ba', 'മ': 'ma', 'യ': 'ya', 'ര': 'ra', 'ല': 'la',
|
200 |
+
'വ': 'va', 'ശ': 'sha', 'ഷ': 'sha', 'സ': 'sa', 'ഹ': 'ha', 'ള': 'la',
|
201 |
+
'്': '', 'ാ': 'aa', 'ി': 'i', 'ീ': 'ee', 'ു': 'u', 'ൂ': 'oo',
|
202 |
+
'െ': 'e', 'േ': 'e', 'ൈ': 'ai', 'ൊ': 'o', 'ോ': 'o', 'ൌ': 'au'
|
203 |
+
}
|
204 |
+
simple_text = ""
|
205 |
+
for char in text:
|
206 |
+
simple_text += malayalam_map.get(char, char)
|
207 |
+
return simple_text
|
208 |
+
|
209 |
+
return text
|
210 |
+
|
211 |
except Exception as e:
|
212 |
print(f"Transliteration error: {e}")
|
213 |
return text
|
|
|
248 |
return transcription.strip()
|
249 |
|
250 |
def create_tabular_feedback(intended, actual, lang_choice):
|
251 |
+
"""Create clean, readable tabular feedback without background colors"""
|
252 |
|
253 |
+
# Get simple transliterations
|
254 |
+
intended_roman = transliterate_to_simple_roman(intended, lang_choice)
|
255 |
+
actual_roman = transliterate_to_simple_roman(actual, lang_choice)
|
256 |
intended_hk = transliterate_to_hk(intended, lang_choice)
|
257 |
actual_hk = transliterate_to_hk(actual, lang_choice)
|
258 |
|
|
|
268 |
|
269 |
# Create word-by-word comparison table
|
270 |
feedback_html = """
|
271 |
+
<div style='font-family: Arial, sans-serif; padding: 20px; margin: 10px 0;'>
|
272 |
<h3 style='color: #2c3e50; margin-bottom: 20px; text-align: center;'>📊 Pronunciation Analysis</h3>
|
273 |
"""
|
274 |
|
275 |
+
# Overview table - completely clean
|
276 |
feedback_html += """
|
277 |
<div style='margin-bottom: 25px;'>
|
278 |
<h4 style='color: #34495e; margin-bottom: 15px;'>📝 Text Comparison</h4>
|
279 |
+
<table style='width: 100%; border-collapse: collapse; border: 2px solid #ddd;'>
|
280 |
<thead>
|
281 |
+
<tr style='border-bottom: 2px solid #ddd;'>
|
282 |
+
<th style='padding: 15px; text-align: left; font-weight: bold; color: #2c3e50; border-right: 1px solid #ddd;'>Type</th>
|
283 |
+
<th style='padding: 15px; text-align: left; font-weight: bold; color: #2c3e50; border-right: 1px solid #ddd;'>Original Text</th>
|
284 |
+
<th style='padding: 15px; text-align: left; font-weight: bold; color: #2c3e50;'>Simple English Sounds</th>
|
285 |
</tr>
|
286 |
</thead>
|
287 |
<tbody>
|
288 |
+
<tr style='border-bottom: 1px solid #ddd;'>
|
289 |
+
<td style='padding: 15px; font-weight: bold; color: #27ae60; border-right: 1px solid #ddd;'>🎯 Target</td>
|
290 |
+
<td style='padding: 15px; font-family: monospace; font-size: 18px; border-right: 1px solid #ddd;'>{}</td>
|
291 |
+
<td style='padding: 15px; font-family: monospace; font-size: 16px; color: #555;'>{}</td>
|
292 |
</tr>
|
293 |
+
<tr>
|
294 |
+
<td style='padding: 15px; font-weight: bold; color: #e67e22; border-right: 1px solid #ddd;'>🗣️ You Said</td>
|
295 |
+
<td style='padding: 15px; font-family: monospace; font-size: 18px; border-right: 1px solid #ddd;'>{}</td>
|
296 |
+
<td style='padding: 15px; font-family: monospace; font-size: 16px; color: #555;'>{}</td>
|
297 |
</tr>
|
298 |
</tbody>
|
299 |
</table>
|
300 |
</div>
|
301 |
""".format(intended, intended_roman, actual, actual_roman)
|
302 |
|
303 |
+
# Word-by-word analysis - clean table
|
304 |
feedback_html += """
|
305 |
<div style='margin-bottom: 25px;'>
|
306 |
+
<h4 style='color: #34495e; margin-bottom: 15px;'>🔍 Word-by-Word Check</h4>
|
307 |
+
<table style='width: 100%; border-collapse: collapse; border: 2px solid #ddd;'>
|
308 |
<thead>
|
309 |
+
<tr style='border-bottom: 2px solid #ddd;'>
|
310 |
+
<th style='padding: 12px; text-align: center; font-weight: bold; color: #2c3e50; border-right: 1px solid #ddd;'>#</th>
|
311 |
+
<th style='padding: 12px; text-align: left; font-weight: bold; color: #2c3e50; border-right: 1px solid #ddd;'>Expected Word</th>
|
312 |
+
<th style='padding: 12px; text-align: left; font-weight: bold; color: #2c3e50; border-right: 1px solid #ddd;'>What You Said</th>
|
313 |
+
<th style='padding: 12px; text-align: center; font-weight: bold; color: #2c3e50;'>Result</th>
|
314 |
</tr>
|
315 |
</thead>
|
316 |
<tbody>
|
|
|
322 |
|
323 |
for tag, i1, i2, j1, j2 in sm.get_opcodes():
|
324 |
if tag == 'equal':
|
325 |
+
# Correct words - clean white background
|
326 |
for idx, word in enumerate(intended_words[i1:i2]):
|
327 |
word_index += 1
|
328 |
correct_words += 1
|
|
|
331 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
332 |
|
333 |
feedback_html += f"""
|
334 |
+
<tr style='border-bottom: 1px solid #eee;'>
|
335 |
+
<td style='padding: 12px; text-align: center; font-weight: bold; color: #666; border-right: 1px solid #ddd;'>{word_index}</td>
|
336 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
337 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px;'>{word}</div>
|
338 |
+
<div style='font-size: 13px; color: #888;'>({roman_word})</div>
|
339 |
</td>
|
340 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
341 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px; color: #27ae60;'>{actual_word}</div>
|
342 |
+
<div style='font-size: 13px; color: #888;'>({actual_roman_word})</div>
|
343 |
</td>
|
344 |
+
<td style='padding: 12px; text-align: center;'>
|
345 |
+
<span style='color: #27ae60; font-weight: bold; font-size: 20px;'>✓</span>
|
346 |
+
<div style='font-size: 12px; color: #27ae60; margin-top: 2px;'>Correct</div>
|
347 |
</td>
|
348 |
</tr>
|
349 |
"""
|
350 |
|
351 |
elif tag == 'replace':
|
352 |
+
# Incorrect words - clean white with colored text only
|
353 |
max_words = max(i2-i1, j2-j1)
|
354 |
for idx in range(max_words):
|
355 |
word_index += 1
|
|
|
359 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
360 |
|
361 |
feedback_html += f"""
|
362 |
+
<tr style='border-bottom: 1px solid #eee;'>
|
363 |
+
<td style='padding: 12px; text-align: center; font-weight: bold; color: #666; border-right: 1px solid #ddd;'>{word_index}</td>
|
364 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
365 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px;'>{expected_word}</div>
|
366 |
+
<div style='font-size: 13px; color: #888;'>({expected_roman})</div>
|
367 |
</td>
|
368 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
369 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px; color: #e74c3c;'>{actual_word}</div>
|
370 |
+
<div style='font-size: 13px; color: #888;'>({actual_roman_word})</div>
|
371 |
</td>
|
372 |
+
<td style='padding: 12px; text-align: center;'>
|
373 |
+
<span style='color: #e74c3c; font-weight: bold; font-size: 20px;'>✗</span>
|
374 |
+
<div style='font-size: 12px; color: #e74c3c; margin-top: 2px;'>Different</div>
|
375 |
</td>
|
376 |
</tr>
|
377 |
"""
|
|
|
382 |
word_index += 1
|
383 |
roman_word = intended_roman_words[i1 + idx] if (i1 + idx) < len(intended_roman_words) else ""
|
384 |
feedback_html += f"""
|
385 |
+
<tr style='border-bottom: 1px solid #eee;'>
|
386 |
+
<td style='padding: 12px; text-align: center; font-weight: bold; color: #666; border-right: 1px solid #ddd;'>{word_index}</td>
|
387 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
388 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px;'>{word}</div>
|
389 |
+
<div style='font-size: 13px; color: #888;'>({roman_word})</div>
|
390 |
</td>
|
391 |
+
<td style='padding: 12px; color: #f39c12; font-style: italic; border-right: 1px solid #ddd;'>
|
392 |
<em>Not spoken</em>
|
393 |
</td>
|
394 |
+
<td style='padding: 12px; text-align: center;'>
|
395 |
+
<span style='color: #f39c12; font-weight: bold; font-size: 20px;'>⚠</span>
|
396 |
+
<div style='font-size: 12px; color: #f39c12; margin-top: 2px;'>Missing</div>
|
397 |
</td>
|
398 |
</tr>
|
399 |
"""
|
|
|
403 |
for idx, word in enumerate(actual_words[j1:j2]):
|
404 |
actual_roman_word = actual_roman_words[j1 + idx] if (j1 + idx) < len(actual_roman_words) else ""
|
405 |
feedback_html += f"""
|
406 |
+
<tr style='border-bottom: 1px solid #eee;'>
|
407 |
+
<td style='padding: 12px; text-align: center; font-weight: bold; color: #666; border-right: 1px solid #ddd;'>+</td>
|
408 |
+
<td style='padding: 12px; color: #9b59b6; font-style: italic; border-right: 1px solid #ddd;'>
|
409 |
<em>Not expected</em>
|
410 |
</td>
|
411 |
+
<td style='padding: 12px; border-right: 1px solid #ddd;'>
|
412 |
+
<div style='font-family: monospace; font-size: 16px; margin-bottom: 4px; color: #9b59b6;'>{word}</div>
|
413 |
+
<div style='font-size: 13px; color: #888;'>({actual_roman_word})</div>
|
414 |
</td>
|
415 |
+
<td style='padding: 12px; text-align: center;'>
|
416 |
+
<span style='color: #9b59b6; font-weight: bold; font-size: 20px;'>+</span>
|
417 |
+
<div style='font-size: 12px; color: #9b59b6; margin-top: 2px;'>Extra</div>
|
418 |
</td>
|
419 |
</tr>
|
420 |
"""
|
|
|
428 |
# Calculate accuracy
|
429 |
accuracy = (correct_words / total_words * 100) if total_words > 0 else 0
|
430 |
|
431 |
+
# Clean summary section
|
432 |
feedback_html += f"""
|
433 |
+
<div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 25px; border-radius: 12px; text-align: center; margin-top: 20px;'>
|
434 |
+
<h4 style='margin: 0 0 20px 0; font-size: 24px;'>🎯 Your Score</h4>
|
435 |
+
<div style='display: flex; justify-content: space-around; flex-wrap: wrap; gap: 20px;'>
|
436 |
+
<div style='background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px; min-width: 160px;'>
|
437 |
+
<div style='font-size: 40px; font-weight: bold; margin-bottom: 8px;'>{accuracy:.0f}%</div>
|
438 |
+
<div style='font-size: 16px; opacity: 0.9;'>Accuracy</div>
|
439 |
</div>
|
440 |
+
<div style='background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px; min-width: 160px;'>
|
441 |
+
<div style='font-size: 40px; font-weight: bold; margin-bottom: 8px;'>{correct_words}/{total_words}</div>
|
442 |
+
<div style='font-size: 16px; opacity: 0.9;'>Words Correct</div>
|
443 |
</div>
|
444 |
</div>
|
445 |
+
<div style='margin-top: 20px; font-size: 18px;'>
|
446 |
"""
|
447 |
|
448 |
+
# Simple motivational message
|
449 |
if accuracy >= 95:
|
450 |
+
feedback_html += "<span>🎉 Perfect! Outstanding pronunciation!</span>"
|
451 |
elif accuracy >= 85:
|
452 |
+
feedback_html += "<span>🌟 Excellent! Very clear speaking!</span>"
|
453 |
elif accuracy >= 70:
|
454 |
+
feedback_html += "<span>👍 Good job! Keep practicing!</span>"
|
455 |
elif accuracy >= 50:
|
456 |
+
feedback_html += "<span>📚 Getting better! Focus on the red words!</span>"
|
457 |
else:
|
458 |
feedback_html += "<span>💪 Keep going! Practice makes perfect!</span>"
|
459 |
|
|
|
462 |
</div>
|
463 |
"""
|
464 |
|
465 |
+
# Optional technical section (collapsed)
|
466 |
if lang_choice in ["Tamil", "Malayalam"]:
|
467 |
feedback_html += f"""
|
468 |
+
<details style='margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 8px;'>
|
469 |
+
<summary style='cursor: pointer; font-weight: bold; color: #2c3e50; padding: 5px;'>🔧 Technical Details (for experts)</summary>
|
470 |
+
<div style='margin-top: 15px; display: grid; grid-template-columns: 1fr 1fr; gap: 15px;'>
|
471 |
<div>
|
472 |
+
<strong>Expected (Harvard-Kyoto):</strong><br>
|
473 |
+
<span style='font-family: monospace; background: #f5f5f5; padding: 8px; border-radius: 4px; display: block; margin-top: 5px;'>{intended_hk}</span>
|
474 |
</div>
|
475 |
<div>
|
476 |
+
<strong>You said (Harvard-Kyoto):</strong><br>
|
477 |
+
<span style='font-family: monospace; background: #f5f5f5; padding: 8px; border-radius: 4px; display: block; margin-top: 5px;'>{actual_hk}</span>
|
478 |
</div>
|
479 |
</div>
|
480 |
+
</details>
|
481 |
"""
|
482 |
|
483 |
feedback_html += "</div>"
|
|
|
504 |
cer_val = jiwer.cer(intended_sentence, actual_text)
|
505 |
|
506 |
# Get transliterations for both texts
|
507 |
+
intended_roman = transliterate_to_simple_roman(intended_sentence, lang_choice)
|
508 |
+
actual_roman = transliterate_to_simple_roman(actual_text, lang_choice)
|
509 |
|
510 |
# Create comprehensive tabular feedback
|
511 |
feedback_html, accuracy = create_tabular_feedback(intended_sentence, actual_text, lang_choice)
|
|
|
569 |
with gr.Row():
|
570 |
with gr.Column():
|
571 |
pass1_out = gr.Textbox(label="🗣️ What You Said", interactive=False)
|
572 |
+
actual_roman_out = gr.Textbox(label="🔤 Your Pronunciation (Simple Sounds)", interactive=False)
|
573 |
with gr.Column():
|
574 |
wer_out = gr.Textbox(label="📊 Word Error Rate", interactive=False)
|
575 |
cer_out = gr.Textbox(label="📈 Character Error Rate", interactive=False)
|