File size: 36,522 Bytes
d724578
 
f95bfeb
 
d724578
 
 
 
 
f95bfeb
d724578
 
 
 
 
 
830cad7
 
 
 
 
 
 
 
 
 
f95bfeb
 
 
 
 
 
 
 
 
 
d724578
f57f681
d3bd428
d724578
 
 
f57f681
 
d3bd428
 
 
d724578
 
 
f57f681
 
d3bd428
 
 
d724578
 
 
2efdf8c
f57f681
d3bd428
 
 
d724578
f57f681
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
830cad7
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
d3bd428
 
 
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
5189e28
d3bd428
 
f57f681
 
 
 
 
5189e28
d3bd428
 
f57f681
 
 
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
483a7e2
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
2efdf8c
 
5189e28
2efdf8c
5189e28
d3bd428
 
2efdf8c
f57f681
 
 
 
d3bd428
 
 
f57f681
 
 
 
 
d3bd428
 
 
f57f681
d724578
 
 
19aade1
d724578
 
 
0261d12
d724578
 
 
ab23395
19aade1
d724578
 
 
ab23395
19aade1
d724578
0261d12
 
ab23395
0261d12
 
d724578
 
 
 
 
 
 
19aade1
 
d724578
 
 
19aade1
 
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830cad7
 
d724578
 
 
483a7e2
d724578
 
 
483a7e2
 
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f95bfeb
 
 
 
 
 
 
 
 
 
 
483a7e2
 
 
 
 
 
 
f95bfeb
 
483a7e2
f95bfeb
 
 
 
 
 
d724578
 
830cad7
 
f95bfeb
d724578
f95bfeb
 
 
2efdf8c
f95bfeb
 
 
d724578
830cad7
f95bfeb
 
 
830cad7
 
 
f95bfeb
830cad7
 
 
 
 
 
 
 
f95bfeb
 
830cad7
f95bfeb
830cad7
f95bfeb
830cad7
f95bfeb
830cad7
 
f95bfeb
 
 
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2efdf8c
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2efdf8c
 
5d04209
2efdf8c
 
 
 
 
 
d724578
 
 
 
 
19aade1
d724578
 
 
19aade1
 
d724578
 
 
830cad7
d724578
 
 
19aade1
 
d724578
 
 
 
f57f681
19aade1
 
d724578
 
 
 
 
 
 
 
08dc7dd
d724578
 
 
 
 
 
 
 
 
 
 
 
 
f57f681
d724578
 
 
 
 
 
 
 
 
 
 
 
 
19aade1
 
d724578
 
 
 
 
 
 
 
 
f95bfeb
 
 
 
 
 
 
d724578
 
 
 
19aade1
d724578
 
 
19aade1
d724578
 
 
 
 
 
19aade1
d724578
 
7fa7122
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f57f681
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f95bfeb
19aade1
d724578
19aade1
d724578
19aade1
d724578
 
 
 
 
 
 
f95bfeb
d724578
 
 
 
 
 
 
 
 
f95bfeb
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f95bfeb
d724578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
import gradio as gr
import os
from transformers import pipeline # Import for ASR (Speech-to-Text) and TTS (Text-to-Speech)
import torchaudio # Required by some TTS models for audio handling

# Define base paths for assets - IMPORTANT: You need to create these folders and place your files here
# For Hugging Face Spaces, these paths are relative to your app.py file
ASSETS_DIR = "./assets"
IMAGE_DIR = os.path.join(ASSETS_DIR, "images")
AUDIO_DIR = os.path.join(ASSETS_DIR, "audio") # This will also be used for dynamically generated audio

# Create asset directories if they don't exist (for local testing, Hugging Face handles this with git lfs)
# On Hugging Face Spaces, you'll upload these folders with your files.
os.makedirs(IMAGE_DIR, exist_ok=True)
os.makedirs(AUDIO_DIR, exist_ok=True)

# Initialize ASR pipeline for pronunciation check
# Using a small, multilingual Whisper model for demonstration.
# For better Arabic-specific performance, consider a model fine-tuned on Arabic speech.
# device=-1 will try to use GPU if available, otherwise CPU.
try:
    asr_pipeline = pipeline("automatic-speech-recognition", model="openai/whisper-small", device=-1)
except Exception as e:
    print(f"Warning: Could not load ASR model. Pronunciation check will be a placeholder. Error: {e}")
    asr_pipeline = None # Set to None if model loading fails

# Initialize TTS pipeline for audio feedback
# Using a specific Arabic TTS model.
try:
    # Ensure this model is suitable for your Hugging Face Space's resources.
    # facebook/mms-tts-ara is a good general Arabic TTS model.
    tts_pipeline = pipeline("text-to-speech", model="facebook/mms-tts-ara", device=-1)
except Exception as e:
    print(f"Warning: Could not load TTS model. Audio feedback will not be generated. Error: {e}")
    tts_pipeline = None # Set to None if model loading fails


# Data for Arabic Letters
# Updated paths for word_image and word_audio based on the provided "alphabets pictures names.JPG"
arabic_letters_data = [
    {
        "letter": "أ",
        "image": os.path.join(IMAGE_DIR, "alif.jpg"),
        "audio": os.path.join(AUDIO_DIR, "alif.wav"),
        "word_example": "أرنب (Arnab - Rabbit)",
        "word_image": os.path.join(IMAGE_DIR, "arnab.jpg"),
        "word_audio": os.path.join(AUDIO_DIR, "arnab.wav"),
    },
    {
        "letter": "ب",
        "image": os.path.join(IMAGE_DIR, "ba.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ba.wav"),
        "word_example": "بطة (Batta - Duck)",
        "word_image": os.path.join(IMAGE_DIR, "batta.jpg"),
        "word_audio": os.path.join(AUDIO_DIR, "batta.wav"),
    },
    {
        "letter": "ت",
        "image": os.path.join(IMAGE_DIR, "taa.jpg"),
        "audio": os.path.join(AUDIO_DIR, "taa.wav"),
        "word_example": "تفاح (Tuffah - Apple)",
        "word_image": os.path.join(IMAGE_DIR, "tuffaha.jpg"), # Corrected from 'placeholder_word_taa.jpg'
        "word_audio": os.path.join(AUDIO_DIR, "tuffaha.wav"), # Corrected from 'placeholder_word_taa.wav'
    },
    {
        "letter": "ث",
        "image": os.path.join(IMAGE_DIR, "tha.jpg"),
        "audio": os.path.join(AUDIO_DIR, "tha.wav"),
        "word_example": "ثعلب (Tha'lab - Fox)",
        "word_image": os.path.join(IMAGE_DIR, "thalab.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "thalab.wav"), # Corrected
    },
    {
        "letter": "ج",
        "image": os.path.join(IMAGE_DIR, "jim.jpg"),
        "audio": os.path.join(AUDIO_DIR, "jim.wav"),
        "word_example": "جمل (Jamal - Camel)",
        "word_image": os.path.join(IMAGE_DIR, "jamal.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "jamal.wav"), # Corrected
    },
    {
        "letter": "ح",
        "image": os.path.join(IMAGE_DIR, "ha.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ha.wav"),
        "word_example": "حصان (Hisan - Horse)",
        "word_image": os.path.join(IMAGE_DIR, "hisan.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "hisan.wav"), # Corrected
    },
    {
        "letter": "خ",
        "image": os.path.join(IMAGE_DIR, "kha.jpg"),
        "audio": os.path.join(AUDIO_DIR, "kha.wav"),
        "word_example": "خروف (Kharouf - Sheep)",
        "word_image": os.path.join(IMAGE_DIR, "kharouf.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "kharouf.wav"), # Corrected
    },
    {
        "letter": "د",
        "image": os.path.join(IMAGE_DIR, "dal.jpg"),
        "audio": os.path.join(AUDIO_DIR, "dal.wav"),
        "word_example": "دجاجة (Dajaja - Chicken)",
        "word_image": os.path.join(IMAGE_DIR, "dajaja.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "dajaja.wav"), # Corrected
    },
    {
        "letter": "ذ",
        "image": os.path.join(IMAGE_DIR, "dhal.jpg"),
        "audio": os.path.join(AUDIO_DIR, "dhal.wav"),
        "word_example": "ذرة (Dhurah - Corn)",
        "word_image": os.path.join(IMAGE_DIR, "dhurah.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "dhurah.wav"), # Corrected
    },
    {
        "letter": "ر",
        "image": os.path.join(IMAGE_DIR, "ra.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ra.wav"),
        "word_example": "رمان (Rumman - Pomegranate)",
        "word_image": os.path.join(IMAGE_DIR, "rumman.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "rumman.wav"), # Corrected
    },
    {
        "letter": "ز",
        "image": os.path.join(IMAGE_DIR, "za.jpg"),
        "audio": os.path.join(AUDIO_DIR, "za.wav"),
        "word_example": "زرافة (Zarafa - Giraffe)",
        "word_image": os.path.join(IMAGE_DIR, "zarafa.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "zarafa.wav"), # Corrected
    },
    {
        "letter": "س",
        "image": os.path.join(IMAGE_DIR, "sin.jpg"),
        "audio": os.path.join(AUDIO_DIR, "sin.wav"),
        "word_example": "سمكة (Samaka - Fish)",
        "word_image": os.path.join(IMAGE_DIR, "samaka.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "samaka.wav"), # Corrected
    },
    {
        "letter": "ش",
        "image": os.path.join(IMAGE_DIR, "shin.jpg"),
        "audio": os.path.join(AUDIO_DIR, "shin.wav"),
        "word_example": "شجرة (Shajara - Tree)",
        "word_image": os.path.join(IMAGE_DIR, "shajara.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "shajara.wav"), # Corrected
    },
    {
        "letter": "ص",
        "image": os.path.join(IMAGE_DIR, "sad.jpg"),
        "audio": os.path.join(AUDIO_DIR, "sad.wav"),
        "word_example": "صابون (Saboon - Soap)",
        "word_image": os.path.join(IMAGE_DIR, "saboon.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "saboon.wav"), # Corrected
    },
    {
        "letter": "ض",
        "image": os.path.join(IMAGE_DIR, "dad.jpg"),
        "audio": os.path.join(AUDIO_DIR, "dad.wav"),
        "word_example": "ضفدع (Difda - Frog)",
        "word_image": os.path.join(IMAGE_DIR, "difda.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "difda.wav"), # Corrected
    },
    {
        "letter": "ط",
        "image": os.path.join(IMAGE_DIR, "ta.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ta.wav"),
        "word_example": "طائرة (Ta'ira - Airplane)",
        "word_image": os.path.join(IMAGE_DIR, "tairah.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "tairah.wav"), # Corrected
    },
    {
        "letter": "ظ",
        "image": os.path.join(IMAGE_DIR, "zay.jpg"), # Using zay.jpg for ظ based on previous mapping, ensure this image is correct for ظ
        "audio": os.path.join(AUDIO_DIR, "zay.wav"), # Using zay.wav for ظ, ensure this audio is correct for ظ
        "word_example": "ظرف (Zarf - Envelope)",
        "word_image": os.path.join(IMAGE_DIR, "zarf.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "zarf.wav"), # Corrected
    },
    {
        "letter": "ع",
        "image": os.path.join(IMAGE_DIR, "ayn.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ayn.wav"),
        "word_example": "عين (Ayn - Eye)",
        "word_image": os.path.join(IMAGE_DIR, "ain.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "ain.wav"), # Corrected
    },
    {
        "letter": "غ",
        "image": os.path.join(IMAGE_DIR, "ghayn.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ghayn.wav"),
        "word_example": "غواصة (Ghawwasa - Submarine)",
        "word_image": os.path.join(IMAGE_DIR, "ghawwasa.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "ghawwasa.wav"), # Corrected
    },   
    {
        "letter": "ف",
        "image": os.path.join(IMAGE_DIR, "fa.jpg"),
        "audio": os.path.join(AUDIO_DIR, "fa.wav"),
        "word_example": "فراشة (Farasha - Butterfly)",
        "word_image": os.path.join(IMAGE_DIR, "farasha.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "farasha.wav"), # Corrected
    },
    {
        "letter": "ق",
        "image": os.path.join(IMAGE_DIR, "qaf.jpg"),
        "audio": os.path.join(AUDIO_DIR, "qaf.wav"),
        "word_example": "قرد (Qird - Monkey)",
        "word_image": os.path.join(IMAGE_DIR, "qird.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "qird.wav"), # Corrected
    },
    {
        "letter": "ك",
        "image": os.path.join(IMAGE_DIR, "kaf.jpg"),
        "audio": os.path.join(AUDIO_DIR, "kaf.wav"),
        "word_example": "كلب (Kalb - Dog)",
        "word_image": os.path.join(IMAGE_DIR, "kalb.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "kalb.wav"), # Corrected
    },
   
    {
        "letter": "ل",
        "image": os.path.join(IMAGE_DIR, "lam.jpg"),
        "audio": os.path.join(AUDIO_DIR, "lam.wav"),
        "word_example": "ليمونة (Laymuna - Lemon)",
        "word_image": os.path.join(IMAGE_DIR, "laymuna.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "laymuna.wav"), # Corrected
    },
    {
        "letter": "م",
        "image": os.path.join(IMAGE_DIR, "mim.jpg"),
        "audio": os.path.join(AUDIO_DIR, "mim.wav"),
        "word_example": "موزة (Mawzah - Banana)",
        "word_image": os.path.join(IMAGE_DIR, "mawzah.jpg"), # Corrected from 'mauzah.jpg'
        "word_audio": os.path.join(AUDIO_DIR, "mawzah.wav"), # Corrected from 'mauzah.wav'
    },
    {
        "letter": "ن",
        "image": os.path.join(IMAGE_DIR, "nun.jpg"),
        "audio": os.path.join(AUDIO_DIR, "nun.wav"),
        "word_example": "نمر (Namir - Tiger)",
        "word_image": os.path.join(IMAGE_DIR, "namir.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "namir.wav"), # Corrected
    },
    {
        "letter": "ه",
        "image": os.path.join(IMAGE_DIR, "ha.jpg"), 
        "audio": os.path.join(AUDIO_DIR, "ha.wav"),
        "word_example": "هاتف (Hatif - Telephone)", 
        "word_image": os.path.join(IMAGE_DIR, "hatif.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "hatif.wav"), # Corrected
    },
    {
        "letter": "و",
        "image": os.path.join(IMAGE_DIR, "waw.jpg"),
        "audio": os.path.join(AUDIO_DIR, "waw.wav"),
        "word_example": "وردة (Warda - Rose)",
        "word_image": os.path.join(IMAGE_DIR, "warda.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "warda.wav"), # Corrected
    },
    {
        "letter": "ي",
        "image": os.path.join(IMAGE_DIR, "ya.jpg"),
        "audio": os.path.join(AUDIO_DIR, "ya.wav"),
        "word_example": "يد (Yad - Hand)",
        "word_image": os.path.join(IMAGE_DIR, "yad.jpg"), # Corrected
        "word_audio": os.path.join(AUDIO_DIR, "yad.wav"), # Corrected
    }
]

# Placeholder data for Arabic Stories
# YOU MUST REPLACE 'placeholder_story_image_pageX.jpg' and 'placeholder_story_audio.wav'
# with actual paths to your story images and audio files within the 'assets/' directory.
arabic_stories_data = [
    {
        "title": "The Gingerbread Man: رجل خبز الزنجبيل (Rajul Khubz Al-Zanjabeel)",
        "pages": [
            {
                "text": "في يوم من الأيام، خرج أرنب صغير يلعب في الحديقة الخضراء. كان الجو جميلاً والشمس مشرقة.",
                "image": os.path.join(IMAGE_DIR, "story1_page1.JPG"), # e.g., 'assets/images/story1_page1.jpg'
                "audio": os.path.join(AUDIO_DIR, "story1_page1.wav"), # e.g., 'assets/audio/story1_page1.wav'
            },
            {
                "text": "فجأة، رأى الأرنب زهرة حمراء جميلة. 'ما أجمل هذه الزهرة!' قال الأرنب بسعادة.",
                "image": os.path.join(IMAGE_DIR, "story1_page2.JPG"), # e.g., 'assets/images/story1_page2.jpg'
                "audio": os.path.join(AUDIO_DIR, "story1_page2.wav"), # e.g., 'assets/audio/story1_page2.wav'
            },
            {
                "text": "فجأة، رأى الأرنب زهرة حمراء جميلة. 'ما أجمل هذه الزهرة!' قال الأرنب بسعادة.",
                "image": os.path.join(IMAGE_DIR, "story1_page3.JPG"), # e.g., 'assets/images/story1_page3.jpg'
                "audio": os.path.join(AUDIO_DIR, "story1_page3.wav"), # e.g., 'assets/audio/story1_page3.wav'
            }, # Add more pages for this story. Each page needs text, an image, and corresponding audio.
        ]
    },
    {
        "title": "الأسد والفأر (The Lion and the Mouse)",
        "pages": [
            {
                "text": "كان أسد نائماً تحت شجرة كبيرة في الغابة. جاء فأر صغير وركض فوق الأسد.",
                "image": os.path.join(IMAGE_DIR, "story2_page1.jpg"), # e.g., 'assets/images/story2_page1.jpg'
                "audio": os.path.join(AUDIO_DIR, "story2_page1.wav"), # e.g., 'assets/audio/story2_page1.wav'
            },
            {
                "text": "استيقظ الأسد غاضباً وأمسك بالفأر. توسل الفأر إليه ليتركه، ووعده بمساعدته يوماً ما.",
                "image": os.path.join(IMAGE_DIR, "story2_page2.jpg"), # e.g., 'assets/images/story2_page2.jpg'
                "audio": os.path.join(AUDIO_DIR, "story2_page2.wav"), # e.g., 'assets/audio/story2_page2.wav'
            },
            # Add more pages for this story.
        ]
    }
]

# Global state variables for navigation (do not modify directly outside functions)
current_letter_idx = 0
current_story_idx = 0
current_story_page_idx = 0

# --- Functions for Learning Arabic Letters Section ---

def get_current_letter_content():
    """
    Retrieves the current letter's data (image, audio, word example, word image, word audio)
    based on the global `current_letter_idx`. The letter text is no longer returned directly.
    """
    if not arabic_letters_data:
        # Handle case where no letter data is available
        return None, None, None, None # Adjusted return for consistency
    
    data = arabic_letters_data[current_letter_idx]
    
    # Return (letter_image, letter_audio, word_image, word_audio)
    # word_example is no longer returned as an output to Gradio components
    return (
        data["image"],
        data["audio"], # This audio is for the letter sound itself
        data["word_image"],
        data["word_audio"] # This audio is for the word example sound
    )

def next_letter_func():
    """
    Advances to the next Arabic letter in the `arabic_letters_data` list.
    If at the end, it loops back to the first letter.
    """
    global current_letter_idx
    if current_letter_idx < len(arabic_letters_data) - 1:
        current_letter_idx += 1
    else:
        current_letter_idx = 0 # Loop back to the beginning
    return get_current_letter_content()

def prev_letter_func():
    """
    Goes back to the previous Arabic letter in the `arabic_letters_data` list.
    If at the beginning, it loops to the last letter.
    """
    global current_letter_idx
    if current_letter_idx > 0:
        current_letter_idx -= 1
    else:
        current_letter_idx = len(arabic_letters_data) - 1 # Loop to the end
    return get_current_letter_content()

def play_audio(audio_path):
    """
    Plays an audio file. This function is called by Gradio's Audio component.
    It checks if the file exists before returning the path.
    """
    if os.path.exists(audio_path):
        return audio_path
    print(f"Error: Audio file not found at {audio_path}")
    # Returning None for audio will result in an error message in Gradio's console
    return None

def generate_tts_audio(text_to_speak, filename="temp_feedback_audio.wav"):
    """
    Generates audio from text using the TTS pipeline and saves it to a file.
    Returns the file path.
    """
    if tts_pipeline is None:
        print("TTS pipeline not loaded, cannot generate audio.")
        return None

    try:
        # Generate speech
        # For 'facebook/mms-tts-ara', the audio output might need specific handling.
        # This is a common pattern for Hugging Face TTS pipelines.
        output = tts_pipeline(text_to_speak)
        # Assuming output is a dictionary like {'audio': numpy_array, 'sampling_rate': int}
        audio_array = output['audio']
        sampling_rate = output['sampling_rate']

        # Save the audio to a temporary file
        output_path = os.path.join(AUDIO_DIR, filename)
        torchaudio.save(output_path, audio_array.unsqueeze(0), sampling_rate)
        return output_path
    except Exception as e:
        print(f"Error generating TTS audio for '{text_to_speak}': {e}")
        return None


def check_pronunciation(audio_input):
    """
    Performs pronunciation check using ASR.
    Compares transcribed text to the expected Arabic letter.
    Returns text feedback and an audio file for the feedback.
    """
    feedback_text = ""
    feedback_audio_path = None

    if audio_input is None: 
        feedback_text = "من فضلك سجل صوتك أولاً. (Please record your voice first.)"
        feedback_audio_path = generate_tts_audio("من فضلك سجل صوتك أولاً.")
        return feedback_text, feedback_audio_path

    if asr_pipeline is None:
        feedback_text = "وظيفة التحقق من النطق غير متوفرة. (Pronunciation check not available. ASR model failed to load.)"
        feedback_audio_path = generate_tts_audio("وظيفة التحقق من النطق غير متوفرة.")
        return feedback_text, feedback_audio_path

    try:
        # Transcribe the audio input
        # Ensure the language is explicitly set to Arabic for better results with Whisper
        transcription_result = asr_pipeline(audio_input, generate_kwargs={"language": "ar"})
        transcribed_text = transcription_result["text"].strip().lower()

        # Get the expected Arabic letter for comparison
        expected_letter = arabic_letters_data[current_letter_idx]["letter"].lower()

        # Simple check: does the transcription contain the expected letter?
        if expected_letter in transcribed_text:
            feedback_text = f"أحسنت! (Excellent!) لقد قلت: '{transcribed_text}'"
            feedback_audio_path = generate_tts_audio("أحسنت!")
        else:
            feedback_text = f"حاول مرة أخرى. (Try again.) لقد قلت: '{transcribed_text}'" \
                               f" كان المتوقع: '{arabic_letters_data[current_letter_idx]['letter']}'"
            feedback_audio_path = generate_tts_audio("حاول مرة أخرى.")
        
        return feedback_text, feedback_audio_path

    except Exception as e:
        feedback_text = f"حدث خطأ أثناء التحقق من النطق: {e}. (An error occurred during pronunciation check.)"
        feedback_audio_path = generate_tts_audio("حدث خطأ أثناء التحقق من النطق.") # Generic error audio
        return feedback_text, feedback_audio_path


# --- Functions for Arabic Storytelling Section ---

def get_story_titles():
    """
    Returns a list of story titles to populate the dropdown menu.
    """
    return [story["title"] for story in arabic_stories_data]

def select_story_func(title):
    """
    Selects a story based on its title from the dropdown.
    Resets the page index to 0 for the newly selected story.
    """
    global current_story_idx, current_story_page_idx
    for i, story in enumerate(arabic_stories_data):
        if story["title"] == title:
            current_story_idx = i
            current_story_page_idx = 0 # Reset to the first page of the new story
            break
    # After selecting, return the content of the first page of the chosen story
    return get_current_story_page_content()

def get_current_story_page_content():
    """
    Retrieves the content (title, text, image, audio) for the current page
    of the currently selected story.
    """
    if not arabic_stories_data:
        # Handle case where no story data is available
        return "لا توجد قصص متاحة", None, None, None
    
    story = arabic_stories_data[current_story_idx]
    
    if current_story_page_idx < len(story["pages"]):
        # Return content for the current page
        page = story["pages"][current_story_page_idx]
        return story["title"], page["text"], page["image"], page["audio"]
    else:
        # If past the last page, indicate the end of the story
        return story["title"], "انتهت القصة! (End of story!)", None, None # No image/audio at end

def next_story_page_func():
    """
    Advances to the next page of the current story.
    If at the end of the story, it stays on the last page.
    """
    global current_story_page_idx
    story = arabic_stories_data[current_story_idx]
    if current_story_page_idx < len(story["pages"]) - 1:
        current_story_page_idx += 1
    # If at the last page, do nothing (stay on the last page)
    return get_current_story_page_content()

def prev_story_page_func():
    """
    Goes back to the previous page of the current story.
    If at the beginning of the story, it loops to the last letter.
    """
    global current_story_page_idx
    if current_story_page_idx > 0:
        current_story_page_idx -= 1
    # If at the first page, do nothing (stay on the first page)
    return get_current_story_page_content()


# --- Gradio UI Definition using gr.Blocks for advanced layout and styling ---

with gr.Blocks(
    theme=gr.themes.Soft(), # A soft, pleasant theme
    # Custom CSS for better aesthetics and responsiveness
    css="""
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
    body {
        font-family: 'Inter', sans-serif;
    }
    .gradio-container {
        font-family: 'Inter', sans-serif;
        background-color: #f0f8ff; /* Light blue background for the entire app */
        border-radius: 15px;
        box-shadow: 0 8px 16px rgba(0,0,0,0.2); /* Enhanced shadow */
        padding: 25px;
        max-width: 950px; /* Slightly wider max-width */
        margin: 30px auto;
        border: 2px solid #aaddff; /* Light blue border */
    }
    h1, h2, h3 {
        color: #2c3e50; /* Darker blue-grey for headings */
        text-align: center;
        margin-bottom: 25px;
        font-weight: 700; /* Bold headings */
    }
    .gr-tab-item {
        border-radius: 12px 12px 0 0 !important; /* Rounded top corners for tabs */
        background-color: #e6f7ff; /* Lighter tab background */
        font-size: 1.15em; /* Larger tab text */
        padding: 12px 20px;
        transition: background-color 0.3s ease;
    }
    .gr-tab-item.selected {
        background-color: #ffffff !important;
        border-bottom: none !important;
        color: #007bff !important; /* Vibrant blue for selected tab */
        font-weight: bold;
        box-shadow: 0 -3px 8px rgba(0,0,0,0.1); /* Shadow for selected tab */
    }
    .gr-button {
        background-color: #007bff; /* Primary blue button */
        color: white;
        border-radius: 12px; /* More rounded buttons */
        padding: 12px 25px;
        font-size: 1.15em; /* Larger button text */
        margin: 8px;
        box-shadow: 0 4px 8px rgba(0,0,0,0.25); /* More prominent shadow */
        transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
        border: none; /* No default border */
        cursor: pointer;
    }
    .gr-button:hover {
        background-color: #0056b3; /* Darker blue on hover */
        transform: translateY(-3px); /* Lift effect on hover */
        box-shadow: 0 6px 12px rgba(0,0,0,0.3); /* Larger shadow on hover */
    }
    .gr-image {
        border-radius: 18px; /* More rounded images */
        overflow: hidden;
        border: 3px solid #aaddff; /* Thicker light blue border */
        box-shadow: 0 4px 10px rgba(0,0,0,0.15);
        background-color: #ffffff;
        display: block; /* Ensure image is a block element for centering */
        margin: 15px auto; /* Center images */
    }
    .gr-audio {
        border-radius: 12px;
        border: 2px solid #cceeff;
        background-color: #ffffff;
        padding: 10px;
        margin: 10px 0;
    }
    .gr-markdown {
        background-color: #ffffff;
        border-radius: 12px;
        padding: 20px;
        margin-top: 15px;
        border: 2px solid #cceeff;
        text-align: center;
        font-size: 1.3em; /* Larger text for readability for kids */
        color: #333;
        line-height: 1.6; /* Improve line spacing */
        box-shadow: 0 2px 6px rgba(0,0,0,0.08);
    }
    .gr-dropdown {
        border-radius: 12px;
        padding: 8px;
        font-size: 1.1em;
        border: 1px solid #cceeff;
        box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);
    }
    .feedback-message {
        color: #28a745; /* Green for success/positive feedback */
        font-weight: bold;
        text-align: center;
        margin-top: 20px;
        font-size: 1.2em;
    }
    .error-message {
        color: #dc3545; /* Red for error messages */
        font-weight: bold;
        text-align: center;
        margin-top: 20px;
        font-size: 1.2em;
    }
    hr {
        border: 0;
        height: 1px;
        background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 123, 255, 0.75), rgba(0, 0, 0, 0));
        margin: 30px 0;
    }
    [dir="rtl"] .gr-button, [dir="rtl"] .gr-markdown, [dir="rtl"] .gr-dropdown {
        text-align: right; /* Ensure RTL alignment for text within components */
    }
    """
) as demo:
    # Main application title and welcoming message
    gr.Markdown("# <span style='color:#007bff;'>تطبيق تعلم العربية للأطفال</span>", rtl=True)
    # Add logo image
    gr.Image(
        value=os.path.join(IMAGE_DIR, "Applogo.png"), # Path to your logo image
        label="شعار التطبيق (App Logo)",
        width=300,
        height=150,
        interactive=False,
        elem_classes=["gr-image"]
    )
    gr.Markdown("## <span style='color:#34495e;'>مرحباً يا أبطالنا الصغار! (Welcome, Little Heroes!)</span>", rtl=True)

    # Tabs for different learning modes
    with gr.Tabs():
        # --- Arabic Letters Learning Tab ---
        with gr.TabItem("تعلم الحروف العربية (Learn Arabic Letters)"): 
            with gr.Column(
                scale=1,
                min_width=400,
                elem_id="letter-learning-section", 
                variant="panel" 
            ):
                gr.Markdown("### <span style='color:#28a745;'>تعلم حرفاً جديداً كل يوم! (Learn a new letter every day!)</span>", rtl=True)
                
                # The letter image will now be the primary display for the letter.
                letter_image = gr.Image(
                    label="صورة الحرف (Letter Image)",
                    width=250, height=250,
                    interactive=False, 
                    elem_classes=["gr-image"] 
                )
                # Hidden audio component to play the letter sound
                letter_audio_output = gr.Audio(
                    label="صوت الحرف (Letter Sound)",
                    autoplay=True, 
                    type="filepath", 
                    visible=False 
                )

                # Navigation buttons for letters
                with gr.Row():
                    prev_letter_btn = gr.Button("الحرف السابق (Previous Letter)", elem_classes=["gr-button"])
                    play_letter_btn = gr.Button("استمع للحرف (Listen to Letter)", elem_classes=["gr-button"])
                    next_letter_btn = gr.Button("الحرف التالي (Next Letter)", elem_classes=["gr-button"])

                #gr.Markdown("<hr>", elem_classes=["gr-markdown"]) 

                # --- Word Example Section for the current letter ---
                gr.Markdown("### <span style='color:#ffc107;'>كلمات تبدأ بهذا الحرف (Words starting with this letter)</span>", rtl=True)
                # Display image for the example word
                word_image = gr.Image(
                    label="صورة الكلمة (Word Image)",
                    width=250, height=250,
                    interactive=False,
                    elem_classes=["gr-image"]
                )
                # Hidden audio component to play the word sound
                word_audio_output = gr.Audio(
                    label="صوت الكلمة (Word Sound)",
                    autoplay=True, 
                    type="filepath",
                    visible=False
                )

                # Button to play the word audio
                play_word_btn = gr.Button("استمع للكلمة (Listen to Word)", elem_classes=["gr-button"])

                gr.Markdown("<hr>", elem_classes=["gr-markdown"])

                # --- Pronunciation Practice Section ---
                gr.Markdown("### <span style='color:#17a2b8;'>تدرب على النطق (Practice Pronunciation)</span>", rtl=True)
                # Microphone input for user to record pronunciation
                pronunciation_input = gr.Audio(
                    sources=["microphone"], 
                    type="filepath", 
                    label="سجل صوتك وأنت تنطق الحرف/الكلمة (Record your voice saying the letter/word)",
                    elem_classes=["gr-audio"]
                )
                # Markdown to display feedback on pronunciation
                pronunciation_feedback = gr.Markdown(
                    label="التقييم (Feedback)",
                    rtl=True,
                    elem_classes=["gr-markdown"]
                )
                # New Audio component to play pronunciation feedback
                pronunciation_feedback_audio = gr.Audio(
                    label="صوت التقييم (Feedback Audio)",
                    autoplay=True,
                    type="filepath",
                    visible=False # Keep it hidden, as we only trigger playback
                )
                # Button to trigger the pronunciation check
                check_pronunciation_btn = gr.Button("تحقق من النطق (Check Pronunciation)", elem_classes=["gr-button"])

        # --- Arabic Storytelling Tab ---
        with gr.TabItem("قصص عربية (Arabic Storytelling)"): 
            with gr.Column(
                scale=1,
                min_width=400,
                elem_id="storytelling-section", 
                variant="panel"
            ):
                gr.Markdown("### <span style='color:#fd7e14;'>استمتع بقصصنا الشيقة! (Enjoy our exciting stories!)</span>", rtl=True)

                # Dropdown to select a story
                story_selection_dropdown = gr.Dropdown(
                    choices=get_story_titles(), 
                    label="اختر قصة (Choose a Story)",
                    value=get_story_titles()[0] if get_story_titles() else None,
                    elem_classes=["gr-dropdown"] 
                )

                # Display area for story title
                story_title_display = gr.Markdown(
                    value="",
                    label="عنوان القصة (Story Title)",
                    rtl=True,
                    elem_classes=["gr-markdown"]
                )
                # Display area for story text
                story_text_display = gr.Markdown(
                    value="",
                    label="نص القصة (Story Text)",
                    rtl=True,
                    elem_classes=["gr-markdown"]
                )
                # Display image for the current story page
                story_image_display = gr.Image(
                    label="صورة القصة (Story Image)",
                    width=450, height=350,
                    interactive=False,
                    elem_classes=["gr-image"]
                )
                # Hidden audio component to play story page audio
                story_audio_output = gr.Audio(
                    label="صوت القصة (Story Audio)",
                    autoplay=True, 
                    type="filepath",
                    visible=False
                )

                # Navigation buttons for story pages
                with gr.Row():
                    prev_story_page_btn = gr.Button("الصفحة السابقة (Previous Page)", elem_classes=["gr-button"])
                    play_story_btn = gr.Button("استمع للقصة (Listen to Story)", elem_classes=["gr-button"])
                    next_story_page_btn = gr.Button("الصفحة التالية (Next Page)", elem_classes=["gr-button"])

    # --- Event Handlers (Logic for button clicks and component changes) ---

    # --- Event Handlers for Learning Arabic Letters Tab ---
    # When the demo loads, display the content of the first letter
    demo.load(
        get_current_letter_content,
        inputs=None,
        outputs=[
            letter_image, 
            letter_audio_output, 
            word_image,
            word_audio_output 
        ],
        queue=False 
    )

    # Connect navigation buttons to their respective functions
    next_letter_btn.click(
        next_letter_func,
        inputs=None,
        outputs=[
            letter_image, 
            letter_audio_output,
            word_image,
            word_audio_output
        ]
    )
    prev_letter_btn.click(
        prev_letter_func,
        inputs=None,
        outputs=[
            letter_image, 
            letter_audio_output,
            word_image,
            word_audio_output
        ]
    )

    # Connect play audio buttons. Using lambda to pass the current audio path dynamically.
    play_letter_btn.click(
        lambda: play_audio(arabic_letters_data[current_letter_idx]["audio"]),
        inputs=None,
        outputs=letter_audio_output
    )
    play_word_btn.click(
        lambda: play_audio(arabic_letters_data[current_letter_idx]["word_audio"]),
        inputs=None,
        outputs=word_audio_output
    )

    # Connect pronunciation check button
    check_pronunciation_btn.click(
        check_pronunciation,
        inputs=pronunciation_input,
        outputs=[pronunciation_feedback, pronunciation_feedback_audio]
    )

    # --- Event Handlers for Arabic Storytelling Tab ---
    # When a new story is selected from the dropdown
    story_selection_dropdown.change(
        select_story_func,
        inputs=story_selection_dropdown,
        outputs=[story_title_display, story_text_display, story_image_display, story_audio_output]
    )

    # Connect navigation buttons for story pages
    next_story_page_btn.click(
        next_story_page_func,
        inputs=None,
        outputs=[story_title_display, story_text_display, story_image_display, story_audio_output]
    )
    prev_story_page_btn.click(
        prev_story_page_func,
        inputs=None,
        outputs=[story_title_display, story_text_display, story_image_display, story_audio_output]
    )

    # Connect button to play the current story page's audio
    play_story_btn.click(
        lambda: play_audio(arabic_stories_data[current_story_idx]["pages"][current_story_page_idx]["audio"]),
        inputs=None,
        outputs=story_audio_output
    )

# Launch the Gradio application
demo.launch()