Alide21 commited on
Commit
e71dc85
·
verified ·
1 Parent(s): f278b50

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -52
app.py CHANGED
@@ -14,7 +14,7 @@ api = HfApi()
14
 
15
  SURAH_NAMES = ["الفاتحة", "البقرة", "آل عمران", "النساء", "المائدة", "الأنعام", "الأعراف", "الأنفال", "التوبة", "يونس", "هود", "يوسف", "الرعد", "إبراهيم", "الحجر", "النحل", "الإسراء", "الكهف", "مريم", "طه", "الأنبياء", "الحج", "المؤمنون", "النور", "الفرقان", "الشعراء", "النمل", "القصص", "العنكبوت", "الروم", "لقمان", "السجدة", "الأحزاب", "سبأ", "فاطر", "يس", "الصافات", "ص", "الزمر", "غافر", "فصلت", "الشورى", "الزخرف", "الدخان", "الجاثية", "الأحقاف", "محمد", "الفتح", "الحجرات", "ق", "الذاريات", "الطور", "النجم", "القمر", "الرحمن", "الواقعة", "الحديد", "المجادلة", "الحشر", "الممتحنة", "الصف", "الجمعة", "المنافقون", "التغابن", "الطلاق", "التحريم", "الملك", "القلم", "الحاقة", "المعارج", "نوح", "الجن", "المزمل", "المدثر", "القيامة", "الإنسان", "المرسلات", "النبأ", "النازعات", "عبس", "التكوير", "الانفطار", "المطففين", "الانشقاق", "البروج", "الطارق", "الأعلى", "الغاشية", "الفجر", "البلد", "الشمس", "الليل", "الضحى", "الشرح", "التين", "العلق", "القدر", "البينة", "الزلزلة", "العاديات", "القارعة", "التكاثر", "العصر", "الهمزة", "الفيل", "قريش", "الماعون", "الكوثر", "الكافرون", "النصر", "المسد", "الإخلاص", "الفلق", "الناس"]
16
 
17
- # --- التنسيق البصري المحسن ---
18
  custom_css = """
19
  @import url('https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&family=Reem+Kufi:wght@400;700&display=swap');
20
  :root { --gold: #D4AF37; --dark-green: #064635; }
@@ -29,26 +29,27 @@ body { direction: rtl; background-color: #f4f6f9; }
29
  padding: 50px 20px;
30
  border-radius: 0 0 40px 40px;
31
  text-align: center;
 
32
  }
33
 
34
- .real-count { font-size: 4rem; color: #FFFFFF !important; font-weight: bold; }
 
 
 
 
 
 
 
35
 
36
  .instruction-box {
37
  background: #fff9e6;
38
- border-right: 8px solid var(--gold);
39
- padding: 25px;
40
  border-radius: 15px;
41
  margin: 20px 0;
42
  text-align: right;
43
  direction: rtl;
44
- box-shadow: 0 4px 10px rgba(0,0,0,0.08);
45
- }
46
-
47
- /* تكبير خط الملاحظة */
48
- .instruction-box strong, .instruction-box span {
49
- font-size: 1.3rem !important;
50
- line-height: 1.8;
51
- color: #444;
52
  }
53
 
54
  .custom-card {
@@ -56,18 +57,28 @@ body { direction: rtl; background-color: #f4f6f9; }
56
  border-radius: 20px !important;
57
  padding: 25px !important;
58
  box-shadow: 0 8px 20px rgba(0,0,0,0.06) !important;
 
59
  }
60
 
61
  .ayah-text {
62
  font-family: 'Amiri', serif !important;
63
- font-size: 2.5rem !important;
64
  color: var(--dark-green);
65
  line-height: 1.8 !important;
66
  text-align: center;
67
  }
 
 
 
68
  """
69
 
70
- # --- المنطق ---
 
 
 
 
 
 
71
  def clean_text(text): return re.sub(r'<[^>]*>', '', text).strip()
72
 
73
  def fetch_surah(s_idx):
@@ -84,21 +95,12 @@ ALL_AYAT = [item for sublist in results for item in sublist]
84
  def validate_ayah(v):
85
  return len(v['text']) <= 200
86
 
87
- def get_random_valid_ayah_data():
 
88
  while True:
89
  idx = random.randint(0, len(ALL_AYAT)-1)
90
- v = ALL_AYAT[idx]
91
- if validate_ayah(v):
92
- return f"<div class='ayah-text'>{v['text']}</div>", f"### {v['surah_name']} | آية {v['ayah']}", idx
93
-
94
- def on_submit(audio, current_idx):
95
- if not audio: return "⚠️ سجل صوتك أولاً", gr.update(), gr.update(), current_idx
96
- v = ALL_AYAT[current_idx]
97
- try:
98
- api.upload_file(path_or_fileobj=audio, path_in_repo=f"data/s{v['surah']}_a{v['ayah']}_{uuid.uuid4().hex[:6]}.wav", repo_id=REPO_ID, repo_type="dataset", token=HF_TOKEN)
99
- text, info, idx = get_random_valid_ayah_data()
100
- return "✅ تم الحفظ بنجاح، بارك الله فيك", text, info, idx
101
- except Exception as e: return f"❌ فشل الرفع: {str(e)}", gr.update(), gr.update(), current_idx
102
 
103
  def jump_to_ayah(s_name, a_num):
104
  try:
@@ -106,46 +108,63 @@ def jump_to_ayah(s_name, a_num):
106
  for i, v in enumerate(ALL_AYAT):
107
  if v['surah_name'] == s_name and v['ayah'] == target_num:
108
  if not validate_ayah(v):
109
- return "⚠️ الآية طويلة جداً (أكثر من 200 رمز).", gr.update(), gr.update(), gr.update()
110
- return "✅ تم العثور على الآية", f"<div class='ayah-text'>{v['text']}</div>", f"### {v['surah_name']} | آية {v['ayah']}", i
111
- return "⚠️ الآية غير موجودة.", gr.update(), gr.update(), gr.update()
112
- except: return "⚠️ خطأ في البيانات.", gr.update(), gr.update(), gr.update()
 
 
113
 
114
- # --- واجهة المستخدم ---
 
 
 
 
 
 
 
 
 
 
115
  with gr.Blocks(title="منصة تلاوة") as demo:
116
- # استخدام دالة get_random_valid_ayah_data مباشرة في القيم الابتدائية لضمان التغيير في كل لود
117
- init_text, init_info, init_idx = get_random_valid_ayah_data()
118
-
119
- idx_state = gr.State(init_idx)
120
 
121
  gr.HTML(f"""
122
  <div class="hero-header">
123
- <h1 style="color:white">مِنَصَّة التِّلَاوَة</h1>
124
- <p style="color:white">بناء قاعدة بيانات صوتية لتدريب الذكاء الاصطناعي</p>
125
  <div style="margin-top:20px;">
126
- <span style="color:white; font-size: 1.3rem;">مساهمات الأمة</span>
127
- <div class="real-count">100</div>
128
  </div>
129
  </div>
130
  """)
131
 
132
  with gr.Column(elem_classes="gradio-container"):
133
- # ملاحظة بخط كبير وRTL
134
  gr.HTML("""
135
  <div class="instruction-box">
136
- <strong>💡 تنبيه هام للجودة:</strong><br>
137
- <span>يرجى قراءة الآية بنفس واحد. <b>في حال الوقف والابتداء، يرجى عدم إعادة الكلمات السابقة</b>؛ ابدأ فوراً من الكلمة التالية للوقف لضمان دقة تدريب النموذج.</span>
 
138
  </div>
139
  """)
140
 
141
  with gr.Row():
142
  with gr.Column(scale=2):
143
  with gr.Column(elem_classes="custom-card"):
144
- info_text = gr.Markdown(init_info)
145
- text_html = gr.HTML(init_text)
146
- status_msg = gr.Markdown("", elem_id="status-msg")
 
 
 
 
 
 
 
147
  with gr.Row():
148
- send_btn = gr.Button("🎤 إرسال المساهمة", variant="primary")
149
  rnd_btn = gr.Button("🔄 آية عشوائية", variant="secondary")
150
 
151
  with gr.Column(scale=1):
@@ -156,13 +175,17 @@ with gr.Blocks(title="منصة تلاوة") as demo:
156
  with gr.Column(elem_classes="custom-card"):
157
  gr.Markdown("### 🔍 اختيار آية")
158
  s_drop = gr.Dropdown(choices=SURAH_NAMES, label="السورة", value="الفاتحة")
159
- a_num = gr.Number(label="الآية", value=1, precision=0)
160
  go_btn = gr.Button("انتقال")
161
 
162
- # أحداث
 
 
 
163
  rnd_btn.click(
164
- get_random_valid_ayah_data,
165
- outputs=[text_html, info_text, idx_state],
 
166
  show_progress="hidden"
167
  )
168
 
@@ -181,4 +204,4 @@ with gr.Blocks(title="منصة تلاوة") as demo:
181
  )
182
 
183
  if __name__ == "__main__":
184
- demo.launch()
 
14
 
15
  SURAH_NAMES = ["الفاتحة", "البقرة", "آل عمران", "النساء", "المائدة", "الأنعام", "الأعراف", "الأنفال", "التوبة", "يونس", "هود", "يوسف", "الرعد", "إبراهيم", "الحجر", "النحل", "الإسراء", "الكهف", "مريم", "طه", "الأنبياء", "الحج", "المؤمنون", "النور", "الفرقان", "الشعراء", "النمل", "القصص", "العنكبوت", "الروم", "لقمان", "السجدة", "الأحزاب", "سبأ", "فاطر", "يس", "الصافات", "ص", "الزمر", "غافر", "فصلت", "الشورى", "الزخرف", "الدخان", "الجاثية", "الأحقاف", "محمد", "الفتح", "الحجرات", "ق", "الذاريات", "الطور", "النجم", "القمر", "الرحمن", "الواقعة", "الحديد", "المجادلة", "الحشر", "الممتحنة", "الصف", "الجمعة", "المنافقون", "التغابن", "الطلاق", "التحريم", "الملك", "القلم", "الحاقة", "المعارج", "نوح", "الجن", "المزمل", "المدثر", "القيامة", "الإنسان", "المرسلات", "النبأ", "النازعات", "عبس", "التكوير", "الانفطار", "المطففين", "الانشقاق", "البروج", "الطارق", "الأعلى", "الغاشية", "الفجر", "البلد", "الشمس", "الليل", "الضحى", "الشرح", "التين", "العلق", "القدر", "البينة", "الزلزلة", "العاديات", "القارعة", "التكاثر", "العصر", "الهمزة", "الفيل", "قريش", "الماعون", "الكوثر", "الكافرون", "النصر", "المسد", "الإخلاص", "الفلق", "الناس"]
16
 
17
+ # --- التنسيق البصري ---
18
  custom_css = """
19
  @import url('https://fonts.googleapis.com/css2?family=Amiri:wght@400;700&family=Reem+Kufi:wght@400;700&display=swap');
20
  :root { --gold: #D4AF37; --dark-green: #064635; }
 
29
  padding: 50px 20px;
30
  border-radius: 0 0 40px 40px;
31
  text-align: center;
32
+ color: white !important;
33
  }
34
 
35
+ .hero-header h1, .hero-header p, .hero-header span { color: white !important; }
36
+
37
+ .real-count {
38
+ font-size: 4rem;
39
+ color: #FFFFFF !important;
40
+ font-weight: bold;
41
+ text-shadow: 2px 2px 8px rgba(0,0,0,0.3);
42
+ }
43
 
44
  .instruction-box {
45
  background: #fff9e6;
46
+ border-right: 6px solid var(--gold);
47
+ padding: 20px;
48
  border-radius: 15px;
49
  margin: 20px 0;
50
  text-align: right;
51
  direction: rtl;
52
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
 
 
 
 
 
 
 
53
  }
54
 
55
  .custom-card {
 
57
  border-radius: 20px !important;
58
  padding: 25px !important;
59
  box-shadow: 0 8px 20px rgba(0,0,0,0.06) !important;
60
+ margin-bottom: 20px !important;
61
  }
62
 
63
  .ayah-text {
64
  font-family: 'Amiri', serif !important;
65
+ font-size: 2.3rem !important;
66
  color: var(--dark-green);
67
  line-height: 1.8 !important;
68
  text-align: center;
69
  }
70
+
71
+ /* ضبط اتجاه رسائل الحالة */
72
+ .status-msg { direction: rtl !important; text-align: right !important; }
73
  """
74
 
75
+ # --- المنطق الخلفي ---
76
+ def get_real_total():
77
+ try:
78
+ files = api.list_repo_files(repo_id=REPO_ID, repo_type="dataset", token=HF_TOKEN)
79
+ return len([f for f in files if f.startswith("data/")])
80
+ except: return 0
81
+
82
  def clean_text(text): return re.sub(r'<[^>]*>', '', text).strip()
83
 
84
  def fetch_surah(s_idx):
 
95
  def validate_ayah(v):
96
  return len(v['text']) <= 200
97
 
98
+ # دالة لاختيار آية عشوائية صالحة
99
+ def get_random_valid_ayah():
100
  while True:
101
  idx = random.randint(0, len(ALL_AYAT)-1)
102
+ if validate_ayah(ALL_AYAT[idx]):
103
+ return idx
 
 
 
 
 
 
 
 
 
 
104
 
105
  def jump_to_ayah(s_name, a_num):
106
  try:
 
108
  for i, v in enumerate(ALL_AYAT):
109
  if v['surah_name'] == s_name and v['ayah'] == target_num:
110
  if not validate_ayah(v):
111
+ return "⚠️ الآية المختارة طويلة جداً (تتجاوز 200 رمز).", gr.update(), gr.update(), gr.update()
112
+ # الرسالة هنا RTL
113
+ return " تم العثور على الآية بنجاح", f"<div class='ayah-text'>{v['text']}</div>", f"### {v['surah_name']} | آية {v['ayah']}", i
114
+ return "⚠️ الآية غير موجودة في هذه السورة.", gr.update(), gr.update(), gr.update()
115
+ except:
116
+ return "⚠️ يرجى التأكد من رقم الآية.", gr.update(), gr.update(), gr.update()
117
 
118
+ def on_submit(audio, current_idx):
119
+ if not audio: return "⚠️ سجل صوتك أولاً", gr.update(), gr.update(), current_idx
120
+ v = ALL_AYAT[current_idx]
121
+ try:
122
+ api.upload_file(path_or_fileobj=audio, path_in_repo=f"data/s{v['surah']}_a{v['ayah']}_{uuid.uuid4().hex[:6]}.wav", repo_id=REPO_ID, repo_type="dataset", token=HF_TOKEN)
123
+ next_idx = get_random_valid_ayah()
124
+ nv = ALL_AYAT[next_idx]
125
+ return "✅ تم الحفظ بنجاح، جزاك الله خيراً", f"<div class='ayah-text'>{nv['text']}</div>", f"### {nv['surah_name']} | آية {nv['ayah']}", next_idx
126
+ except Exception as e: return f"❌ فشل الرفع: {str(e)}", gr.update(), gr.update(), current_idx
127
+
128
+ # --- بناء الواجهة ---
129
  with gr.Blocks(title="منصة تلاوة") as demo:
130
+ # الآن سيتم اختيار آية جديدة في كل مرة يتم فيها بناء الـ Blocks (أي عند التحديث)
131
+ idx_state = gr.State(get_random_valid_ayah())
 
 
132
 
133
  gr.HTML(f"""
134
  <div class="hero-header">
135
+ <h1>مِنَصَّة التِّلَاوَة</h1>
136
+ <p>بناء قاعدة بيانات صوتية لتدريب الذكاء الاصطناعي على تصحيح التلاوة</p>
137
  <div style="margin-top:20px;">
138
+ <span style="font-size: 1.3rem;">مساهمات الأمة</span>
139
+ <div class="real-count">{get_real_total()}</div>
140
  </div>
141
  </div>
142
  """)
143
 
144
  with gr.Column(elem_classes="gradio-container"):
 
145
  gr.HTML("""
146
  <div class="instruction-box">
147
+ <strong>💡 تنبيه للجودة:</strong>
148
+ يرجى قراءة الآية بنفس واحد.
149
+ <br>نقبل الآيات التي لا تتجاوز 200 رمز لضمان دقة التحليل.
150
  </div>
151
  """)
152
 
153
  with gr.Row():
154
  with gr.Column(scale=2):
155
  with gr.Column(elem_classes="custom-card"):
156
+ # نستخدم دالة لتهيئة العرض الأول بناءً على idx_state
157
+ def load_initial_ayah(idx):
158
+ v = ALL_AYAT[idx]
159
+ return f"<div class='ayah-text'>{v['text']}</div>", f"### {v['surah_name']} | آية {v['ayah']}"
160
+
161
+ # إنشاء المكونات بقيم فارغة ثم تعبئتها
162
+ info_text = gr.Markdown()
163
+ text_html = gr.HTML()
164
+ status_msg = gr.Markdown(elem_classes="status-msg")
165
+
166
  with gr.Row():
167
+ send_btn = gr.Button("🎤 إرسال التسجيل", variant="primary")
168
  rnd_btn = gr.Button("🔄 آية عشوائية", variant="secondary")
169
 
170
  with gr.Column(scale=1):
 
175
  with gr.Column(elem_classes="custom-card"):
176
  gr.Markdown("### 🔍 اختيار آية")
177
  s_drop = gr.Dropdown(choices=SURAH_NAMES, label="السورة", value="الفاتحة")
178
+ a_num = gr.Number(label="رقم الآية", value=1, precision=0)
179
  go_btn = gr.Button("انتقال")
180
 
181
+ # حدث لتحميل الآية عند فتح الصفحة لأول مرة
182
+ demo.load(load_initial_ayah, inputs=[idx_state], outputs=[text_html, info_text])
183
+
184
+ # أحداث الأزرار
185
  rnd_btn.click(
186
+ lambda: (idx := get_random_valid_ayah()) and (v := ALL_AYAT[idx]) and
187
+ (f"<div class='ayah-text'>{v['text']}</div>", f"### {v['surah_name']} | آية {v['ayah']}", idx, ""),
188
+ outputs=[text_html, info_text, idx_state, status_msg],
189
  show_progress="hidden"
190
  )
191
 
 
204
  )
205
 
206
  if __name__ == "__main__":
207
+ demo.launch(css=custom_css)