Asem75 commited on
Commit
dee1798
ยท
verified ยท
1 Parent(s): fd1afcd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -282
app.py CHANGED
@@ -1,79 +1,113 @@
1
  import os
2
- import re
3
  import json
4
- import time
5
- import warnings
6
  import gradio as gr
7
  from gradio_client import Client
8
  from huggingface_hub import HfApi, hf_hub_download
9
  import torch
10
  from transformers import AutoModelForCausalLM, AutoTokenizer
11
 
12
- # ======================== ูƒุชู… ุงู„ุชุญุฐูŠุฑุงุช ========================
13
- warnings.filterwarnings("ignore")
14
-
15
- # ======================== ุงู„ุฅุนุฏุงุฏุงุช ========================
16
- DEVICE = "cpu"
17
- WHISPER_MODEL = "openai/whisper-base"
18
- MODEL_ID = "Qwen/Qwen2.5-3B-Instruct"
19
  RADAR_SPACE_URL = "Asem75/Aiocr_Radar"
 
 
20
  VAULT_REPO_ID = "Asem75/aiocr_asistant"
21
 
22
- MAX_LESSON_CHARS = 1200
 
23
 
24
  RADAR_API_KEY = os.environ.get("INTERNAL_API_KEY", "").strip()
25
  HF_TOKEN = os.environ.get("HF_TOKEN", "").strip()
26
 
27
- print(f"โœ… ุงู„ุฎุฒู†ุฉ: {VAULT_REPO_ID} | ุงู„ุฑุงุฏุงุฑ: {RADAR_SPACE_URL}")
28
  if not HF_TOKEN:
29
- print("โš ๏ธ ุชู†ุจูŠู‡: HF_TOKEN ุบูŠุฑ ู…ุถุจูˆุท ููŠ ุฃุณุฑุงุฑ ู‡ุฐู‡ ุงู„ู…ุณุงุญุฉ โ€” ุญูุธ ู…ู„ู ุงู„ุทุงู„ุจ ู„ู† ูŠุนู…ู„.")
30
 
31
  _hf_api = HfApi(token=HF_TOKEN) if HF_TOKEN else HfApi()
32
 
33
- print("โณ ุชุญู…ูŠู„ ุงู„ู†ู…ูˆุฐุฌ...")
34
- _llm_tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
35
- _llm_model = AutoModelForCausalLM.from_pretrained(
36
  MODEL_ID, torch_dtype=torch.float32, device_map="cpu", low_cpu_mem_usage=True
37
  )
38
- print("โœ… ุงู„ู†ู…ูˆุฐุฌ ุฌุงู‡ุฒ")
39
-
40
- # ======================== Whisper ========================
41
- _whisper_pipe = None
42
-
43
- def load_whisper():
44
- global _whisper_pipe
45
- if _whisper_pipe is not None:
46
- return _whisper_pipe
47
- from transformers import pipeline
48
- _whisper_pipe = pipeline("automatic-speech-recognition", model=WHISPER_MODEL, device=DEVICE, chunk_length_s=30)
49
- return _whisper_pipe
50
-
51
- # ======================== ุงู„ุฑุงุฏุงุฑ ========================
52
- # โš ๏ธ ุจู†ุงุกู‹ ุนู„ู‰ ุทู„ุจูƒ: ู…ุญุฑูƒ ู…ุงูŠูƒุฑูˆุณูˆูุช ู„ุง ูŠุณุชุฎุฏู… "ุญุงู„ุฉ ุงู„ู…ุดุงุนุฑ" ุฅุทู„ุงู‚ุงู‹ ู‡ู†ุง
53
- # (ู„ุง ูŠูˆุฌุฏ ุฑุจุท ูุนู„ูŠ ุจูŠู† ุงู„ู…ุดุงุนุฑ ูˆุฃูŠ ุตูˆุช ู…ุฎุชู„ู ููŠ ู‡ุฐุง ุงู„ุชุตู…ูŠู…)ุŒ ูุญุฐูู†ุง
54
- # ูˆุณู… ุงู„ู…ุดุงุนุฑ ุจุงู„ูƒุงู…ู„ ู…ู† ุชูˆุฌูŠู‡ ุงู„ู†ู…ูˆุฐุฌ ุจุฏู„ ุชูˆู„ูŠุฏ ุดูŠุก ุบูŠุฑ ู…ุณุชุฎุฏู… ูุนู„ูŠุงู‹.
55
- def call_radar_api(text, subject):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  try:
57
  client = Client(RADAR_SPACE_URL)
58
- word_count = len(text.split())
59
-
60
- if word_count <= 35:
61
- speaker_name = "ar-EG-SalmaNeural"
62
- else:
63
- voice_map = {
64
- "๐Ÿงฎ ุงู„ุฑูŠุงุถูŠุงุช": "ar-JO-TaimNeural",
65
- "๐Ÿ”ฌ ุงู„ุนู„ูˆู…": "ar-JO-TaimNeural",
66
- "๐Ÿ“— ุงู„ู„ุบุฉ ุงู„ุนุฑุจูŠุฉ": "ar-SA-HamedNeural",
67
- "๐Ÿ•Œ ุงู„ุชุฑุจูŠุฉ ุงู„ุฅุณู„ุงู…ูŠุฉ": "ar-SA-HamedNeural",
68
- "๐Ÿ”ค ุงู„ู„ุบุฉ ุงู„ุฅู†ุฌู„ูŠุฒูŠุฉ": "en-US-JennyNeural",
69
- }
70
- speaker_name = voice_map.get(subject, "ar-JO-TaimNeural")
71
-
72
- audio_url = client.predict(
73
- text, speaker_name, RADAR_API_KEY,
74
- api_name="/synth_arabic"
75
- )
76
-
77
  if audio_url and isinstance(audio_url, (list, tuple)):
78
  audio_url = audio_url[0]
79
  return str(audio_url).strip() if audio_url else None
@@ -81,263 +115,135 @@ def call_radar_api(text, subject):
81
  print(f"โš ๏ธ ุฎุทุฃ ุงู„ุฑุงุฏุงุฑ: {e}")
82
  return None
83
 
84
- # ======================== ุงู„ุฎุฒู†ุฉ: ุณุฑุฏ ูˆุชุญู…ูŠู„ ุงู„ุฏุฑูˆุณ ุงู„ุญู‚ูŠู‚ูŠุฉ ========================
85
- def list_lessons_in_vault(grade, semester, subject):
86
- """ูŠู‚ุฑุฃ ุงู„ุฏุฑูˆุณ ุงู„ู…ูˆุฌูˆุฏุฉ ูุนู„ูŠุงู‹ ููŠ ุงู„ุฎุฒู†ุฉ ู„ู‡ุฐุง ุงู„ู…ุณุงุฑุŒ ูˆูŠุณุชุฎุฏู… ุงุณู…
87
- ุงู„ู…ู„ู ู†ูุณู‡ (ุจุนู†ูˆุงู†ู‡ ุงู„ุญู‚ูŠู‚ูŠ) ูƒุฎูŠุงุฑุงุช ุงู„ู‚ุงุฆู…ุฉ ุงู„ู…ู†ุณุฏู„ุฉ โ€” ุจุฏู„ ุฃุฑู‚ุงู…
88
- ุนุงู…ุฉ ู„ุง ุนู„ุงู‚ุฉ ู„ู‡ุง ุจู…ุง ู‡ูˆ ู…ูˆุฌูˆุฏ ูุนู„ุงู‹."""
 
 
 
89
  try:
90
- folder_path = f"Curriculum_Core/{grade}/{semester}/{subject}/"
91
- all_files = _hf_api.list_repo_files(repo_id=VAULT_REPO_ID, repo_type="dataset")
92
- # โš ๏ธ ู…ุทุงุจู‚ุฉ ุบูŠุฑ ุญุณุงุณุฉ ู„ุญุงู„ุฉ ุงู„ุฃุญุฑู: ู…ู„ูุงุชูƒ ุงู„ุญู‚ูŠู‚ูŠุฉ ุจุตูŠุบุฉ .TXT ุจุญุฑูˆู ูƒุจูŠุฑุฉ
93
- lesson_files = [
94
- f for f in all_files
95
- if f.startswith(folder_path) and f.lower().endswith(('.txt', '.md', '.json'))
96
- ]
97
- choices = []
98
- for f in sorted(lesson_files):
99
- filename = os.path.basename(f)
100
- display_name = re.sub(r'\.(txt|md|json)$', '', filename, flags=re.IGNORECASE)
101
- choices.append((display_name, f)) # (ุงู„ุนู†ูˆุงู† ุงู„ู…ุนุฑูˆุถุŒ ุงู„ู…ุณุงุฑ ุงู„ูƒุงู…ู„ = ุงู„ู‚ูŠู…ุฉ ุงู„ูุนู„ูŠุฉ)
102
- if not choices:
103
- print(f"โš ๏ธ ู„ุง ุชูˆุฌุฏ ุฏุฑูˆุณ ููŠ ุงู„ุฎุฒู†ุฉ ุถู…ู†: {folder_path}")
104
- return choices
105
  except Exception as e:
106
- print(f"โš ๏ธ ูุดู„ ุณุฑุฏ ุฏุฑูˆุณ ุงู„ุฎุฒู†ุฉ ู„ู€ {folder_path}: {e}")
107
- return []
108
 
109
 
110
- def load_lesson_content(lesson_path):
111
- if not lesson_path:
112
- return None
113
  try:
114
- local_path = hf_hub_download(repo_id=VAULT_REPO_ID, filename=lesson_path, repo_type="dataset")
115
- with open(local_path, "r", encoding="utf-8") as f:
116
- content = f.read()
117
- if len(content) > MAX_LESSON_CHARS:
118
- print(f"โœ‚๏ธ ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ ({len(content)} ุญุฑู) ุฃุทูˆู„ ู…ู† ุงู„ุณู‚ูุŒ ุชู… ุงู‚ุชุทุงุนู‡ ุฅู„ู‰ {MAX_LESSON_CHARS} ุญุฑู")
119
- content = content[:MAX_LESSON_CHARS]
120
- print(f"โœ… ุชู… ุชุญู…ูŠู„ ุงู„ุฏุฑุณ: {lesson_path} ({len(content)} ุญุฑู)")
121
- return content
122
  except Exception as e:
123
- print(f"โš ๏ธ ูุดู„ ุชุญู…ูŠู„ ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ {lesson_path}: {e}")
124
  return None
125
 
126
 
127
- def save_student_profile(grade, semester, subject, lesson_path, user_name, track=None):
128
- if not HF_TOKEN:
129
- print("โš ๏ธ ุชุฎุทู‘ูŠ ุญูุธ ู…ู„ู ุงู„ุทุงู„ุจ: ู„ุง ูŠูˆุฌุฏ HF_TOKEN ููŠ ุฃุณุฑุงุฑ ู‡ุฐู‡ ุงู„ู…ุณุงุญุฉ.")
130
- return
131
- try:
132
- student_path = f"Student_Hub/User_{user_name}/"
133
- profile = {
134
- "user_name": user_name, "grade": grade, "semester": semester,
135
- "subject": subject, "lesson": lesson_path, "track": track,
136
- "last_updated": time.strftime("%Y-%m-%d %H:%M:%S")
137
- }
138
- _hf_api.upload_file(
139
- path_or_fileobj=json.dumps(profile, ensure_ascii=False, indent=2).encode("utf-8"),
140
- path_in_repo=f"{student_path}profile.json",
141
- repo_id=VAULT_REPO_ID, repo_type="dataset", token=HF_TOKEN
 
 
 
 
142
  )
143
- print(f"๐Ÿ‘ค ุชู… ุญูุธ: {student_path}profile.json")
144
- except Exception as e:
145
- print(f"โš ๏ธ ุฎุทุฃ ููŠ ุงู„ุญูุธ: {e}")
146
-
147
- # ======================== ุงู„ุตููˆู ูˆุงู„ูุตูˆู„ ูˆุงู„ู…ูˆุงุฏ ========================
148
- GRADES = [
149
- "ุงู„ุฑูˆุถุฉ", "ุงู„ุตู ุงู„ุฃูˆู„", "ุงู„ุตู ุงู„ุซุงู†ูŠ", "ุงู„ุตู ุงู„ุซุงู„ุซ",
150
- "ุงู„ุตู ุงู„ุฑุงุจุน", "ุงู„ุตู ุงู„ุฎุงู…ุณ", "ุงู„ุตู ุงู„ุณุงุฏุณ", "ุงู„ุตู ุงู„ุณุงุจุน",
151
- "ุงู„ุตู ุงู„ุซุงู…ู†", "ุงู„ุตู ุงู„ุชุงุณุน", "ุงู„ุตู ุงู„ุนุงุดุฑ", "ุงู„ุตู ุงู„ุญุงุฏูŠ ุนุดุฑ",
152
- "ุงู„ุตู ุงู„ุซุงู†ูŠ ุนุดุฑ (ุงู„ุชูˆุฌูŠู‡ูŠ)"
153
- ]
154
- SEMESTERS = ["ุงู„ูุตู„ ุงู„ุฃูˆู„", "ุงู„ูุตู„ ุงู„ุซุงู†ูŠ"]
155
-
156
- # โš ๏ธ ุงู„ู…ูˆุงุฏ ุงู„ู…ุฏู…ุฌุฉ ุณุงุจู‚ุงู‹ ุชู… ูุตู„ู‡ุง ุฅู„ู‰ ู…ูˆุงุฏ ู…ุณุชู‚ู„ุฉ ุจู†ุงุกู‹ ุนู„ู‰ ุทู„ุจูƒ
157
- DEFAULT_SUBJECTS = [
158
- "๐Ÿงฎ ุงู„ุฑูŠุงุถูŠุงุช",
159
- "๐Ÿ”ฌ ุงู„ุนู„ูˆู…",
160
- "๐Ÿ“— ุงู„ู„ุบุฉ ุงู„ุนุฑุจูŠุฉ",
161
- "๐Ÿ•Œ ุงู„ุชุฑุจูŠุฉ ุงู„ุฅุณู„ุงู…ูŠุฉ",
162
- "๐Ÿ”ค ุงู„ู„ุบุฉ ุงู„ุฅู†ุฌู„ูŠุฒูŠุฉ",
163
- ]
164
 
165
- # ======================== ุฏุงู„ุฉ ุงู„ู…ุญุงุฏุซุฉ ========================
166
- def teacher_chat(audio_mic, subject, grade, semester, lesson_path, track, student_name, chat_history_state):
167
- if audio_mic is None:
168
- return chat_history_state, None, "๐ŸŽค ุงู„ุฑุฌุงุก ุชุณุฌูŠู„ ุงู„ุณุคุงู„ ุฃูˆู„ุงู‹"
169
 
170
- try:
171
- whisper = load_whisper()
172
- result = whisper(audio_mic, generate_kwargs={"language": "arabic"})
173
- user_text = result["text"].strip()
174
- except Exception as e:
175
- return chat_history_state, None, f"โš ๏ธ ุฎุทุฃ: {e}"
176
-
177
- if not user_text:
178
- return chat_history_state, None, "โŒ ู„ู… ูŠุชู… ุงู„ุชุนุฑู ุนู„ู‰ ูƒู„ุงู…"
179
-
180
- print(f"๐Ÿ—ฃ๏ธ {student_name}: {user_text}")
181
-
182
- lesson_content = load_lesson_content(lesson_path)
183
-
184
- context_parts = [f"ู…ุงุฏุฉ {subject}"]
185
- if semester:
186
- context_parts.append(f"ุงู„ูุตู„ {semester}")
187
- if track:
188
- context_parts.append(f"ุชุฎุตุต {track}")
189
- context_str = " - ".join(context_parts)
190
-
191
- # โš ๏ธ ุชูˆุฌูŠู‡ ู…ูุนุงุฏ ุจู†ุงุคู‡ ุจุงู„ูƒุงู…ู„ ู„ู…ุนุงู„ุฌุฉ ุบูŠุงุจ "ุนู„ุงู‚ุฉ ุงู„ุฃุณุชุงุฐ ุจุงู„ุทุงู„ุจ":
192
- # ู…ุฎุงุทุจุฉ ุงู„ุทุงู„ุจ ุจุงุณู…ู‡ุŒ ูƒู„ุงู… ุฌุงู†ุจูŠ ูˆุฏูˆุฏ ุทุจูŠุนูŠุŒ ูˆุฃูˆู„ูˆูŠุฉ ู‚ุทุนูŠุฉ ู„ุณุคุงู„ู‡
193
- # ุงู„ุญูŠ ุนู„ู‰ ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ ุงู„ู…ุฑุฌุนูŠ. ุชู… ุญุฐู ูˆุณู… ุงู„ู…ุดุงุนุฑ ุจุงู„ูƒุงู…ู„ ู„ุฃู†ู‡ ุบูŠุฑ
194
- # ู…ุณุชุฎุฏู… ูุนู„ูŠุงู‹ ู…ุน ู…ุญุฑูƒ ู…ุงูŠูƒุฑูˆุณูˆูุช.
195
- student_name_clean = (student_name or "ุงู„ุทุงู„ุจ").strip()
196
- system_prompt = (
197
- f"ุฃู†ุช ุงู„ุฃุณุชุงุฐ ุนุจูˆุฏุŒ ู…ุนู„ู… ุฎุจูŠุฑ ูˆุฏูˆุฏ ุฌุฏุงู‹ุŒ ุชุฑุจุทูƒ ุจุทู„ุงุจูƒ ุนู„ุงู‚ุฉ ุฅู†ุณุงู†ูŠุฉ ุญู‚ูŠู‚ูŠุฉ ู„ุง ุนู„ุงู‚ุฉ ุขู„ูŠุฉ ุฌุงูุฉ. "
198
- f"ุชุชุญุฏุซ ุงู„ุขู† ู…ุน ุทุงู„ุจูƒ {student_name_clean}. ุงู„ุณูŠุงู‚ ุงู„ุญุงู„ูŠ: {context_str}.\n"
199
- f"- ุฎุงุทุจ {student_name_clean} ุจุงุณู…ู‡ ู…ู† ูˆู‚ุช ู„ุขุฎุฑ ุจุดูƒู„ ุทุจูŠุนูŠ (ู„ุง ููŠ ูƒู„ ุฑุณุงู„ุฉ)ุŒ ูƒู…ุง ูŠูุนู„ ู…ุนู„ู… ุญู‚ูŠู‚ูŠ ูŠุนุฑู ุทู„ุงุจู‡.\n"
200
- "- ุงุณู…ุญ ู„ู†ูุณูƒ ุจู‚ู„ูŠู„ ู…ู† ุงู„ูƒู„ุงู… ุงู„ุฌุงู†ุจูŠ ุงู„ูˆุฏูˆุฏ (ุชุดุฌูŠุนุŒ ุชุนู„ูŠู‚ ู„ุทูŠู ู…ู†ุงุณุจ) ุญูŠู† ูŠู„ุงุฆู… ุงู„ุณูŠุงู‚ุŒ "
201
- "ูุงู„ุนู„ุงู‚ุฉ ุจูŠู† ุงู„ู…ุนู„ู… ูˆุทุงู„ุจู‡ ู„ูŠุณุช ู…ุฌุฑุฏ ุณุคุงู„ ูˆุฌูˆุงุจ ุขู„ูŠ.\n"
202
- "- ุฅุฐุง ูƒุงู†ุช ุฑุณุงู„ุฉ ุงู„ุทุงู„ุจ ู…ุฌุฑุฏ ุชุญูŠุฉ ุฃูˆ ุญุฏูŠุซ ุนุงู…ุŒ ุฑุฏ ุจุชุญูŠุฉ ูˆุฏูˆุฏุฉ ุทุจูŠุนูŠุฉ ูˆู‚ุตูŠุฑุฉ ูู‚ุทุŒ ุจุฏูˆู† ูุฑุถ ุฃุณู„ูˆุจ ุชุนู„ูŠู…ูŠ ุตุงุฑู….\n"
203
- "- ุฅุฐุง ูƒุงู† ุณุคุงู„ุงู‹ ุชุนู„ูŠู…ูŠุงู‹ ูุนู„ูŠุงู‹: ุฃุฌุจ ุจุฅูŠุฌุงุฒ (30 ูƒู„ู…ุฉ ูƒุญุฏ ุฃู‚ุตู‰)ุŒ ู„ุง ุชุนุท ุงู„ุฅุฌุงุจุฉ ูƒุงู…ู„ุฉุŒ ู‚ุณู…ู‡ุง ู„ุฎุทูˆุงุชุŒ ูˆุงุทุฑุญ ุณุคุงู„ุงู‹ ูˆุงุญุฏุงู‹ ููŠ ุงู„ู†ู‡ุงูŠุฉ.\n"
204
- "- ุณุคุงู„ ุงู„ุทุงู„ุจ ุงู„ุญุงู„ูŠ ู‡ูˆ ุงู„ุฃูˆู„ูˆูŠุฉ ุงู„ู‚ุทุนูŠุฉ ุฏุงุฆู…ุงู‹. ุงุณุชุฎุฏู… ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ ุงู„ู…ุฑุฌุนูŠ (ุฅู† ูˆูุฌุฏ) ูƒู…ุตุฏุฑ ู…ุณุงุนุฏ ูู‚ุท "
205
- "ุฅุฐุง ูƒุงู† ู…ุฑุชุจุทุงู‹ ู…ุจุงุดุฑุฉ ุจุณุคุงู„ู‡ุŒ ูˆุชุฌุงู‡ู„ู‡ ุชู…ุงู…ุงู‹ ุฅุฐุง ู„ู… ูŠูƒู† ุฐุง ุตู„ุฉ."
206
- )
207
-
208
- if lesson_content:
209
- system_prompt += f"\n\n๐Ÿ“– ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ ุงู„ู…ุฑุฌุนูŠ (ู…ุณุงุนุฏ ูู‚ุทุŒ ูˆู„ูŠุณ ู…ู„ุฒู…ุงู‹):\n```\n{lesson_content}\n```"
210
- print(f"๐Ÿ“š ุชู… ุญู‚ู† ู…ุญุชูˆู‰ ุงู„ุฏุฑุณ ({len(lesson_content)} ุญุฑู)")
211
- else:
212
- print("โ„น๏ธ ู„ุง ูŠูˆุฌุฏ ู…ุญุชูˆู‰ ุฏุฑุณ ู…ูุญู‚ูŽู† ู„ู‡ุฐุง ุงู„ุณุคุงู„.")
213
-
214
- messages = [{"role": "system", "content": system_prompt}]
215
- for msg in chat_history_state:
216
- messages.append({"role": msg["role"], "content": msg["content"]})
217
- messages.append({"role": "user", "content": user_text})
218
 
219
- try:
220
- text_prompt = _llm_tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
221
- model_inputs = _llm_tokenizer([text_prompt], return_tensors="pt").to(DEVICE)
222
-
223
- with torch.no_grad():
224
- generated_ids = _llm_model.generate(
225
- **model_inputs, max_new_tokens=200, temperature=0.4,
226
- do_sample=True, repetition_penalty=1.15,
227
- pad_token_id=_llm_tokenizer.eos_token_id, use_cache=True
228
- )
229
 
230
- generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)]
231
- cleaned_response = _llm_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
232
 
233
- if not cleaned_response.endswith(('.', 'ุŸ', '!')):
234
- cleaned_response += '.'
 
235
 
236
- print(f"๐Ÿค– ุงู„ุฃุณุชุงุฐ: {cleaned_response}")
237
- except Exception as e:
238
- return chat_history_state, None, f"โš ๏ธ ุฎุทุฃ ุงู„ู†ู…ูˆุฐุฌ: {e}"
239
 
240
- chat_history_state = chat_history_state + [
241
- {"role": "user", "content": user_text},
242
- {"role": "assistant", "content": cleaned_response},
243
- ]
244
 
245
- save_student_profile(grade, semester, subject, lesson_path, student_name, track)
 
 
 
 
246
 
247
- audio_path = call_radar_api(cleaned_response, subject)
248
- status = "โœ… ุชู… ุงู„ุฑุฏ" if audio_path else "โš ๏ธ ุชู… ุชูˆู„ูŠุฏ ุงู„ู†ุต ู„ูƒู† ูุดู„ ุงู„ุตูˆุช"
249
- return chat_history_state, audio_path, status
250
 
251
- # ======================== ุงู„ูˆุงุฌู‡ุฉ ========================
252
- with gr.Blocks(title="ุงู„ุฃุณุชุงุฐ ุนุจูˆุฏ", theme=gr.themes.Soft()) as demo:
253
- gr.Markdown("# ๐ŸŽ“ ุงู„ู…ู†ุตุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ - ุงู„ุฃุณุชุงุฐ ุนุจูˆุฏ")
 
 
 
254
 
255
- chat_history_state = gr.State([])
256
- subject_choices_state = gr.State(list(DEFAULT_SUBJECTS))
257
 
258
- with gr.Row():
259
- with gr.Column(scale=2):
260
- with gr.Row():
261
- student_name_input = gr.Textbox(label="๐Ÿ‘ค ุงุณู… ุงู„ุทุงู„ุจ", value="Divid")
262
- grade_dropdown = gr.Dropdown(choices=GRADES, value="ุงู„ุตู ุงู„ุนุงุดุฑ", label="๐Ÿ“† ุงู„ุตู ุงู„ุฏุฑุงุณูŠ")
263
 
264
- with gr.Row():
265
- semester_dropdown = gr.Dropdown(choices=SEMESTERS, value="ุงู„ูุตู„ ุงู„ุฃูˆู„", label="๐Ÿ“… ุงู„ูุตู„ ุงู„ุฏุฑุงุณูŠ")
266
- track_dropdown = gr.Dropdown(choices=[], value=None, label="๐ŸŽฏ ุงู„ุชุฎุตุต (ู„ู„ุชูˆุฌูŠู‡ูŠ ูู‚ุท)", visible=False, allow_custom_value=True)
 
 
267
 
268
- with gr.Row(visible=False) as track_row:
269
- new_track_input = gr.Textbox(label="โž• ุฃุถู ุชุฎุตุตุงู‹ ุฌุฏูŠุฏุงู‹", placeholder="ู…ุซุงู„: ุตู†ุงุนูŠุŒ ุฒุฑุงุนูŠ")
270
- add_track_btn = gr.Button("๐Ÿ’พ ุญูุธ ุงู„ุชุฎุตุต", variant="secondary", size="sm")
271
 
272
- with gr.Row():
273
- subject_dropdown = gr.Dropdown(choices=DEFAULT_SUBJECTS, value=DEFAULT_SUBJECTS[0], label="๐Ÿ“š ุงู„ู…ุงุฏุฉ")
274
- add_subject_btn = gr.Button("โž• ุฅุถุงูุฉ ู…ูˆุงุฏ ุฃุฎุฑู‰", variant="secondary", size="sm")
275
 
276
- with gr.Row(visible=False) as new_subject_row:
277
- new_subject_input = gr.Textbox(label="โœ๏ธ ุงุณู… ุงู„ู…ุงุฏุฉ ุงู„ุฌุฏูŠุฏุฉ", placeholder="ู…ุซุงู„: ๐Ÿ’ป ุงู„ุญุงุณูˆุจ")
278
- confirm_subject_btn = gr.Button("๐Ÿ’พ ุญูุธ ุงู„ู…ุงุฏุฉ", variant="secondary", size="sm")
 
 
 
 
 
 
 
 
279
 
 
 
280
  with gr.Row():
281
- lesson_dropdown = gr.Dropdown(choices=[], label="๐Ÿ“– ุงู„ุฏุฑุณ (ู…ู† ุงู„ุฎุฒู†ุฉ)")
282
- refresh_lessons_btn = gr.Button("๐Ÿ”„", variant="secondary", size="sm")
283
-
284
- chatbot_display = gr.Chatbot(label="ุงู„ุญูˆุงุฑ", height=400)
285
- mic_input = gr.Audio(label="๐ŸŽค ุณุคุงู„ูƒ", type="filepath", sources=["microphone"])
286
- send_btn = gr.Button("๐Ÿš€ ุฅุฑุณุงู„", variant="primary")
287
-
288
- with gr.Column(scale=1):
289
- audio_output = gr.Audio(label="๐Ÿ”Š ุงู„ุฑุฏ", type="filepath", autoplay=True)
290
- status_output = gr.Textbox(label="ุงู„ุญุงู„ุฉ")
291
-
292
- def toggle_track(grade):
293
- if "ุงู„ุชูˆุฌูŠู‡ูŠ" in grade:
294
- return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)
295
- return gr.update(visible=False, value=None), gr.update(visible=False), gr.update(visible=False)
296
-
297
- grade_dropdown.change(fn=toggle_track, inputs=[grade_dropdown], outputs=[track_dropdown, track_row, add_track_btn], api_name=False)
298
-
299
- # โ”€โ”€โ”€โ”€ ุฅุถุงูุฉ ู…ุงุฏุฉ ุฌุฏูŠุฏุฉ ุฏูŠู†ุงู…ูŠูƒูŠุงู‹ โ”€โ”€โ”€โ”€
300
- add_subject_btn.click(fn=lambda: gr.update(visible=True), outputs=[new_subject_row], api_name=False)
301
-
302
- def confirm_new_subject(new_subject, choices):
303
- new_subject = (new_subject or "").strip()
304
- if not new_subject:
305
- return gr.update(), choices, gr.update(visible=False), ""
306
- if new_subject not in choices:
307
- choices = choices + [new_subject]
308
- return gr.update(choices=choices, value=new_subject), choices, gr.update(visible=False), ""
309
-
310
- confirm_subject_btn.click(
311
- fn=confirm_new_subject,
312
- inputs=[new_subject_input, subject_choices_state],
313
- outputs=[subject_dropdown, subject_choices_state, new_subject_row, new_subject_input],
314
- api_name=False,
315
- )
316
-
317
- # โ”€โ”€โ”€โ”€ ุชุญุฏูŠุซ ู‚ุงุฆู…ุฉ ุงู„ุฏุฑูˆุณ ู…ู† ุงู„ุฎุฒู†ุฉ ุนู†ุฏ ุชุบูŠู‘ุฑ ุงู„ุตู/ุงู„ูุตู„/ุงู„ู…ุงุฏุฉ โ”€โ”€โ”€โ”€
318
- def refresh_lessons(grade, semester, subject):
319
- lessons = list_lessons_in_vault(grade, semester, subject)
320
- if not lessons:
321
- return gr.update(choices=[], value=None)
322
- return gr.update(choices=lessons, value=lessons[0][1])
323
-
324
- grade_dropdown.change(fn=refresh_lessons, inputs=[grade_dropdown, semester_dropdown, subject_dropdown], outputs=[lesson_dropdown], api_name=False)
325
- semester_dropdown.change(fn=refresh_lessons, inputs=[grade_dropdown, semester_dropdown, subject_dropdown], outputs=[lesson_dropdown], api_name=False)
326
- subject_dropdown.change(fn=refresh_lessons, inputs=[grade_dropdown, semester_dropdown, subject_dropdown], outputs=[lesson_dropdown], api_name=False)
327
- refresh_lessons_btn.click(fn=refresh_lessons, inputs=[grade_dropdown, semester_dropdown, subject_dropdown], outputs=[lesson_dropdown], api_name=False)
328
-
329
- demo.load(fn=refresh_lessons, inputs=[grade_dropdown, semester_dropdown, subject_dropdown], outputs=[lesson_dropdown])
330
-
331
- def process_and_display(audio_mic, subject, grade, semester, lesson_path, track, student_name, history_state):
332
- new_history, audio, status = teacher_chat(audio_mic, subject, grade, semester, lesson_path, track, student_name, history_state)
333
- return new_history, new_history, audio, status, None
334
-
335
- send_btn.click(
336
- fn=process_and_display,
337
- inputs=[mic_input, subject_dropdown, grade_dropdown, semester_dropdown, lesson_dropdown, track_dropdown, student_name_input, chat_history_state],
338
- outputs=[chat_history_state, chatbot_display, audio_output, status_output, mic_input],
339
- api_name=False,
340
- )
341
 
342
  if __name__ == "__main__":
343
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import os
 
2
  import json
 
 
3
  import gradio as gr
4
  from gradio_client import Client
5
  from huggingface_hub import HfApi, hf_hub_download
6
  import torch
7
  from transformers import AutoModelForCausalLM, AutoTokenizer
8
 
9
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
10
+ # ุงู„ุฅุนุฏุงุฏุงุช ูˆุงู„ุฑูˆุงุจุท ุจูŠู† ุงู„ู…ุณุงุญุงุช
11
+ # โš ๏ธ ุชุฃูƒุฏ ู…ู† ู‡ุฐู‡ ุงู„ุฃุณู…ุงุก ุจุงู„ุถุจุท โ€” ุงุณุชูู†ุชุฌุช ู…ู† ุฑุณุงู„ุชูƒุŒ ุตุญู‘ุญู‡ุง ุฅุฐุง ุงุฎุชู„ูุช
12
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
 
 
 
13
  RADAR_SPACE_URL = "Asem75/Aiocr_Radar"
14
+ MEDIA_SPACE_URL = "Asem75/My_teacher_enemation" # ู…ุณุงุญุฉ ุงู„ุตูˆุฑ ูˆุงู„ุฃู†ู…ูŠุดู† (SD-Turbo + AnimateDiff)
15
+ CONTROLLER_SPACE_URL = "Asem75/My_teacher_controller" # ู…ุณุงุญุฉ ุชู‡ูŠุฆุฉ ุงู„ุฎุฒู†ุฉ (ู„ู„ู…ุฑุฌุนูŠุฉ ูู‚ุทุŒ ุงู„ุชู‡ูŠุฆุฉ ู…ูุถู…ูŽู‘ู†ุฉ ู‡ู†ุง ู…ุจุงุดุฑุฉ)
16
  VAULT_REPO_ID = "Asem75/aiocr_asistant"
17
 
18
+ MODEL_ID = "Qwen/Qwen2.5-3B-Instruct"
19
+ DEVICE = "cpu"
20
 
21
  RADAR_API_KEY = os.environ.get("INTERNAL_API_KEY", "").strip()
22
  HF_TOKEN = os.environ.get("HF_TOKEN", "").strip()
23
 
 
24
  if not HF_TOKEN:
25
+ print("โš ๏ธ ุชู†ุจูŠู‡: HF_TOKEN ุบูŠุฑ ู…ุถุจูˆุท ููŠ ุฃุณุฑุงุฑ ู‡ุฐู‡ ุงู„ู…ุณุงุญุฉ โ€” ุงู„ู‚ุฑุงุกุฉ/ุงู„ูƒุชุงุจุฉ ููŠ ุงู„ุฎุฒู†ุฉ ู‚ุฏ ุชูุดู„ ุฅุฐุง ูƒุงู†ุช ุฎุงุตุฉ.")
26
 
27
  _hf_api = HfApi(token=HF_TOKEN) if HF_TOKEN else HfApi()
28
 
29
+ print("โณ ุชุญู…ูŠู„ ู†ู…ูˆุฐุฌ ูƒูˆูŠู† (ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ)...")
30
+ _tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
31
+ _model = AutoModelForCausalLM.from_pretrained(
32
  MODEL_ID, torch_dtype=torch.float32, device_map="cpu", low_cpu_mem_usage=True
33
  )
34
+ print("โœ… ูƒูˆูŠู† ุฌุงู‡ุฒ")
35
+
36
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
37
+ # ุชู‡ูŠุฆุฉ ู…ู„ูุงุช ุงู„ุฎุฒู†ุฉ โ€” ู†ูุณ ุจู†ูŠุฉ ูƒูˆุฏ "controller" ุงู„ุฐูŠ ุฃุฑุณู„ุชู‡ุŒ ู…ูุถู…ูŽู‘ู†ุฉ
38
+ # ู‡ู†ุง ู…ุจุงุดุฑุฉ (ู„ุง ุชุนุชู…ุฏ ุนู„ู‰ ุงุณุชุฏุนุงุก ู…ุณุงุญุฉ ู‚ุฏ ุชูƒูˆู† ู†ุงุฆู…ุฉ ุนู†ุฏ ูƒู„ ุฅู‚ู„ุงุน).
39
+ #
40
+ # ๐Ÿ› ๏ธ ุงู„ุฅุตู„ุงุญ ุงู„ุฐูŠ ูˆุฌุฏุชู‡ ููŠ ู…ุฑุงุฌุนุชูŠ: ุฑูุน ุงู„ู…ู„ู ุงู„ุจุฏูŠู„ (ุนู†ุฏ ุนุฏู… ูˆุฌูˆุฏู‡)
41
+ # ู„ู… ูŠูƒู† ู…ุญู…ูŠุงู‹ ุจู€ try/except ุฎุงุต ุจู‡ โ€” ุฃูŠ ูุดู„ ููŠ ุงู„ุฑูุน (ุชูˆูƒู† ุฎุงุทุฆ/ุตู„ุงุญูŠุงุช)
42
+ # ูƒุงู† ุณูŠุชุณุจุจ ุจุงู†ู‡ูŠุงุฑ ุงู„ู…ุณุงุญุฉ ุจุงู„ูƒุงู…ู„ ุนู†ุฏ ุงู„ุฅู‚ู„ุงุน. ุงู„ุขู† ู…ุญู…ูŠ ูˆูŠูุณุฌูŽู‘ู„
43
+ # ุงู„ูุดู„ ููŠ ุงู„ุณุฌู„ ุจุฏู„ ุฅุณู‚ุงุท ุงู„ุชุทุจูŠู‚.
44
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
45
+ VAULT_STRUCTURE = {
46
+ "curriculum_plans/lessons_division.json": {
47
+ "description": "ุชู‚ุณูŠู… ุงู„ุฏุฑูˆุณ ูˆุงู„ู…ูˆุงุฏ ุงู„ุชุนู„ูŠู…ูŠุฉ ุจูŠู† ุงู„ุนู„ู…ูŠ ูˆุงู„ุฃุฏุจูŠ ูˆุงู„ูˆุณูˆู…",
48
+ "tracks": {"scientific": [], "literary": []}
49
+ },
50
+ "curriculum_plans/co_planning_qwen.json": {
51
+ "description": "ู…ู„ู ุงู„ุชุฎุทูŠุท ุงู„ู…ุดุชุฑูƒ ู…ุน ู…ูˆุฏูŠู„ ูƒูˆูŠู† ู„ุชุญุฏูŠุฏ ุงู„ุฃู‡ุฏุงู ุงู„ุชุฑุจูˆูŠุฉ",
52
+ "qwen_guidelines": {}, "shared_plans": []
53
+ },
54
+ "learning_gaps/student_levels.json": {
55
+ "description": "ุณุฌู„ ู…ุณุชูˆูŠุงุช ุงู„ุทู„ุงุจ ูˆุชุตู†ูŠู ู…ู‡ุงุฑุงุชู‡ู… ุงู„ุชุนู„ูŠู…ูŠุฉ",
56
+ "levels": {"beginner": [], "intermediate": [], "advanced": []}
57
+ },
58
+ "learning_gaps/gap_analysis.json": {
59
+ "description": "ุชุญู„ูŠู„ ุงู„ูุฌูˆุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ ูˆุฎุทุท ุงู„ู…ุนุงู„ุฌุฉ ุงู„ูุฑุฏูŠุฉ ู„ู„ุทู„ุงุจ",
60
+ "detected_gaps": [], "remedial_actions": []
61
+ },
62
+ "teacher_student_interaction/interaction_logs.json": {
63
+ "description": "ุณุฌู„ุงุช ุนู„ุงู‚ุฉ ุงู„ุทุงู„ุจ ุจุงู„ุฃุณุชุงุฐ ูˆุงู„ุฏุนู… ุงู„ุชูˆุฌูŠู‡ูŠ",
64
+ "teacher_notes": [], "student_feedback": []
65
+ },
66
+ }
67
+
68
+
69
+ def initialize_vault_files():
70
+ log_lines = []
71
+ for file_path, default_content in VAULT_STRUCTURE.items():
72
+ try:
73
+ hf_hub_download(repo_id=VAULT_REPO_ID, filename=file_path, repo_type="dataset", token=HF_TOKEN or None)
74
+ log_lines.append(f"โœ… {file_path} ู…ูˆุฌูˆุฏ ู…ุณุจู‚ุงู‹ ูˆุฌุงู‡ุฒ.")
75
+ except Exception:
76
+ try:
77
+ local_filename = f"/tmp/{os.path.basename(file_path)}"
78
+ with open(local_filename, "w", encoding="utf-8") as f:
79
+ json.dump(default_content, f, ensure_ascii=False, indent=4)
80
+ _hf_api.upload_file(
81
+ path_or_fileobj=local_filename, path_in_repo=file_path,
82
+ repo_id=VAULT_REPO_ID, repo_type="dataset", token=HF_TOKEN or None,
83
+ )
84
+ os.remove(local_filename)
85
+ log_lines.append(f"๐Ÿš€ ุชู… ุฅู†ุดุงุก ูˆุฑูุน: {file_path}")
86
+ except Exception as e_upload:
87
+ log_lines.append(f"โŒ ูุดู„ ุฅู†ุดุงุก {file_path}: {e_upload}")
88
+ return "\n".join(log_lines)
89
+
90
+
91
+ print("โณ ูุญุต ูˆุชู‡ูŠุฆุฉ ู…ู„ูุงุช ุงู„ุฎุฒู†ุฉ...")
92
+ VAULT_INIT_LOG = initialize_vault_files()
93
+ print(VAULT_INIT_LOG)
94
+
95
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
96
+ # ุงู„ู…ุนู„ู…ูˆู† ูˆุงู„ุฃุตูˆุงุช (Tab 1 โ€” ุญุฌุฒ ู…ุจุฏุฆูŠุŒ ุชุทูˆูŠุฑ ูƒุงู…ู„ ู„ุงุญู‚ุงู‹)
97
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
98
+ TEACHERS = [
99
+ ("ุงู„ุฃุณุชุงุฐ ุนุจูˆุฏ", "ar-JO-TaimNeural"),
100
+ ("ุงู„ุฃุณุชุงุฐุฉ ุณู„ู…ู‰", "ar-EG-SalmaNeural"),
101
+ ("ุงู„ุฃุณุชุงุฐ ุญุงู…ุฏ", "ar-SA-HamedNeural"),
102
+ ]
103
+
104
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
105
+ # ุงู„ุฑุจุท ุจู…ุณุงุญุฉ ุงู„ุฑุงุฏุงุฑ (ุตูˆุช) โ€” ุจู†ูุณ ู†ู…ุท ุงู„ุญู…ุงูŠุฉ ุจู…ูุชุงุญ ุณุฑูŠ ุงู„ู…ูุนุชู…ุฏ ุณุงุจู‚ุงู‹
106
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
107
+ def synth_via_radar(text, speaker_name):
108
  try:
109
  client = Client(RADAR_SPACE_URL)
110
+ audio_url = client.predict(text, speaker_name, RADAR_API_KEY, api_name="/synth_arabic")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  if audio_url and isinstance(audio_url, (list, tuple)):
112
  audio_url = audio_url[0]
113
  return str(audio_url).strip() if audio_url else None
 
115
  print(f"โš ๏ธ ุฎุทุฃ ุงู„ุฑุงุฏุงุฑ: {e}")
116
  return None
117
 
118
+
119
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•๏ฟฝ๏ฟฝ๏ฟฝโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
120
+ # ุงู„ุฑุจุท ุจู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑ/ุฃู†ู…ูŠุดู†)
121
+ # โš ๏ธ ู…ู„ุงุญุธุฉ ุฃู…ุงู†: ู†ู‚ุทุชุง API ู‡ุฐู‡ (generate_image, generate_animation) ููŠ
122
+ # ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท ุบูŠุฑ ู…ุญู…ูŠุชูŠู† ุจุฃูŠ ู…ูุชุงุญ ุณุฑูŠ ุญุงู„ูŠุงู‹ (ุจุฎู„ุงู ุงู„ุฑุงุฏุงุฑ). ุฅุฐุง
123
+ # ุฃุฑุฏุช ุญู…ุงูŠุชู‡ู…ุง ุจู†ูุณ ู…ุจุฏุฃ INTERNAL_API_KEYุŒ ุฃุฎุจุฑู†ูŠ ูˆุฃุถูŠูู‡ ู‡ู†ุงูƒ ุฃูŠุถุงู‹.
124
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
125
+ def generate_image_via_media(prompt):
126
  try:
127
+ client = Client(MEDIA_SPACE_URL)
128
+ return client.predict(prompt, api_name="/generate_image")
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  except Exception as e:
130
+ print(f"โš ๏ธ ุฎุทุฃ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑุฉ): {e}")
131
+ return None
132
 
133
 
134
+ def generate_animation_via_media(prompt):
 
 
135
  try:
136
+ client = Client(MEDIA_SPACE_URL)
137
+ return client.predict(prompt, api_name="/generate_animation")
 
 
 
 
 
 
138
  except Exception as e:
139
+ print(f"โš ๏ธ ุฎุทุฃ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุฃู†ู…ูŠุดู†): {e}")
140
  return None
141
 
142
 
143
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
144
+ # ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ (ูƒูˆูŠู†)
145
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
146
+ def ask_teacher(prompt, history):
147
+ history = history or []
148
+ messages = [{
149
+ "role": "system",
150
+ "content": "ุฃู†ุช ูƒูˆูŠู†ุŒ ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ ู„ู…ู†ุตุฉ ุชุนู„ูŠู…ูŠุฉ ุนุฑุจูŠุฉ. ุชุณุงุนุฏ ููŠ ุตูŠุงุบุฉ ุฏุฑูˆุณ ูˆู…ุญุชูˆู‰ ุชุนู„ูŠู…ูŠ ู‚ุตูŠุฑ ูˆูˆุงุถุญ ุจุงู„ุนุฑุจูŠุฉุŒ ูˆุชุฌูŠุจ ุจุฅูŠุฌุงุฒ ูˆูˆุถูˆุญ."
151
+ }]
152
+ messages.extend(history)
153
+ messages.append({"role": "user", "content": prompt})
154
+
155
+ text_prompt = _tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
156
+ inputs = _tokenizer([text_prompt], return_tensors="pt").to(DEVICE)
157
+
158
+ with torch.no_grad():
159
+ out_ids = _model.generate(
160
+ **inputs, max_new_tokens=200, temperature=0.5, do_sample=True,
161
+ repetition_penalty=1.15, pad_token_id=_tokenizer.eos_token_id
162
  )
163
+ out_ids = [o[len(i):] for i, o in zip(inputs.input_ids, out_ids)]
164
+ response = _tokenizer.batch_decode(out_ids, skip_special_tokens=True)[0].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ new_history = history + [{"role": "user", "content": prompt}, {"role": "assistant", "content": response}]
167
+ return response, new_history
 
 
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ def integration_test(prompt, teacher_choice, gen_image, gen_anim, history_state):
171
+ if not prompt or not prompt.strip():
172
+ return "โš ๏ธ ุงูƒุชุจ ู†ุตุงู‹ ุฃูˆู„ุงู‹", history_state, None, None, None
 
 
 
 
 
 
 
173
 
174
+ response, new_history = ask_teacher(prompt, history_state)
175
+ speaker_name = dict(TEACHERS).get(teacher_choice, "ar-JO-TaimNeural")
176
 
177
+ audio_path = synth_via_radar(response, speaker_name)
178
+ image_path = generate_image_via_media(response) if gen_image else None
179
+ anim_path = generate_animation_via_media(response) if gen_anim else None
180
 
181
+ return response, new_history, audio_path, image_path, anim_path
 
 
182
 
 
 
 
 
183
 
184
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
185
+ # ุงู„ูˆุงุฌู‡ุฉ: ุณุชุฉ ุชุจูˆูŠุจุงุช ุญุฌุฒ ู…ูƒุงู† + ู„ูˆุญุฉ ูุญุต ุงู„ุฑุจุท
186
+ # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
187
+ with gr.Blocks(title="My Teacher โ€” ุงู„ู…ู†ุตุฉ ุงู„ุฑุฆูŠุณูŠุฉ", theme=gr.themes.Soft()) as demo:
188
+ gr.Markdown("# ๐ŸŽ“ ุงู„ู…ู†ุตุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ ุงู„ุฐูƒูŠุฉ ุงู„ู…ูˆุญุฏุฉ")
189
 
190
+ qwen_history_state = gr.State([])
 
 
191
 
192
+ with gr.Tabs():
193
+ with gr.Tab("๐Ÿ‘จโ€๐Ÿซ ุฅุนุฏุงุฏุงุช ุงู„ู…ุนู„ู… ูˆุงู„ุตูˆุช"):
194
+ gr.Markdown(
195
+ "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุณูŠุชู… ู‡ู†ุง: ุชุตูุญ ุงู„ู…ุนู„ู…ูŠู† ุงู„ู…ุชุงุญูŠู†ุŒ ูˆุงุฎุชูŠุงุฑ "
196
+ "ุงู„ุฃุณุชุงุฐ ุงู„ู…ู†ุงุณุจุŒ ูˆุฑุจุท ูƒู„ ู…ุนู„ู… ุจุฎุงู…ุฉ ุตูˆุชูŠุฉ ุนุจุฑ edge-tts/ุงู„ุฑุงุฏุงุฑ."
197
+ )
198
 
199
+ with gr.Tab("๐ŸŽฌ ุงู„ููŠุฏูŠูˆู‡ุงุช ุงู„ุชุนู„ูŠู…ูŠุฉ ุงู„ู…ุณุฌู„ุฉ"):
200
+ gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ู…ูƒุชุจุฉ ุงู„ุฏุฑูˆุณ ูˆุงู„ููŠุฏูŠูˆู‡ุงุช ุงู„ู…ุณุฌู„ุฉ ู…ุณุจู‚ุงู‹ ู„ู„ู…ุฑุงุฌุนุฉ.")
201
 
202
+ with gr.Tab("๐Ÿ—‚๏ธ ุฎุทุท ุงู„ุฏุฑูˆุณ ูˆุงู„ุชู‚ุณูŠู…"):
203
+ gr.Markdown(
204
+ "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ู†ุงูุฐุฉ ุชูุงุนู„ูŠุฉ ู…ุน ูƒูˆูŠู† ู„ู„ุชุฎุทูŠุท ุงู„ู…ุดุชุฑูƒุŒ "
205
+ "ูˆุชู‚ุณูŠู… ุงู„ู…ูˆุงุฏ ุจูŠู† ุงู„ุนู„ู…ูŠ ูˆุงู„ุฃุฏุจูŠ."
206
+ )
207
 
208
+ with gr.Tab("๐Ÿ“Š ุงู„ู…ุณุชูˆูŠุงุช ูˆุชุญู„ูŠู„ ุงู„ูุฌูˆุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ"):
209
+ gr.Markdown(
210
+ "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุชุชุจุน ู…ุณุชูˆู‰ ุงู„ุทุงู„ุจ ูˆุชุญู„ูŠู„ ุงู„ุฃุฎุทุงุก "
211
+ "(ุจุงู„ุงุณุชุนุงู†ุฉ ุจู€ CAMeL-BERT) ูˆุฎุทุท ุณุฏ ุงู„ูุฌูˆุงุช."
212
+ )
213
 
214
+ with gr.Tab("๐Ÿ’ฌ ุนู„ุงู‚ุฉ ุงู„ุทุงู„ุจ ูˆุงู„ุฃุณุชุงุฐ"):
215
+ gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุงู„ุฑุณุงุฆู„ ุงู„ุชูˆุฌูŠู‡ูŠุฉุŒ ุงู„ุชู‚ูŠูŠู…ุงุชุŒ ูˆุงู„ุฏุนู… ุงู„ูุฑุฏูŠ.")
 
216
 
217
+ with gr.Tab("๐Ÿ–ผ๏ธ ุฃุฑุดูŠู ูˆุฅุฏุงุฑุฉ ุงู„ูˆุณุงุฆุท"):
218
+ gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ูู‡ุฑุณุฉ ุงู„ุตูˆุฑ ูˆุงู„ุฃู†ู…ูŠุดู† ุงู„ู…ูˆู„ู‘ุฏุฉ ู„ู…ู†ุน ุฅุนุงุฏุฉ ุงู„ุชูˆู„ูŠุฏ.")
 
219
 
220
+ with gr.Tab("๐Ÿ”— ู„ูˆุญุฉ ูุญุต ุงู„ุฑุจุท (API)"):
221
+ gr.Markdown(
222
+ "ุชุฌุฑุจุฉ ู…ุจุงุดุฑุฉ ุชูุซุจุช ุฃู† **ูƒูˆูŠู† + ุงู„ุฑุงุฏุงุฑ (ุตูˆุช) + ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑุฉ/ุฃู†ู…ูŠุดู†)** "
223
+ "ู…ุฑุจูˆุทูˆู† ูุนู„ูŠุงู‹ ุนุจุฑ APIุŒ ู‚ุจู„ ุจู†ุงุก ุงู„ุชุจูˆูŠุจุงุช ุงู„ุณุช ุจุงู„ุชูุตูŠู„."
224
+ )
225
+ prompt_in = gr.Textbox(label="โœ๏ธ ุงูƒุชุจ ููƒุฑุฉ ุฃูˆ ุณุคุงู„ุงู‹ ุชุนู„ูŠู…ูŠุงู‹", lines=3)
226
+ teacher_pick = gr.Dropdown(choices=[t[0] for t in TEACHERS], value=TEACHERS[0][0], label="๐ŸŽ™๏ธ ุงุฎุชุฑ ุงู„ู…ุนู„ู…/ุงู„ุตูˆุช")
227
+ with gr.Row():
228
+ want_image = gr.Checkbox(label="๐Ÿ–ผ๏ธ ุชูˆู„ูŠุฏ ุตูˆุฑุฉ ุชูˆุถูŠุญูŠุฉ", value=False)
229
+ want_anim = gr.Checkbox(label="๐ŸŽฌ ุชูˆู„ูŠุฏ ุฃู†ู…ูŠุดู† (ุฃุจุทุฃ ุจูƒุซูŠุฑ)", value=False)
230
+ run_btn = gr.Button("๐Ÿš€ ุฌุฑู‘ุจ ุงู„ุฑุจุท ุงู„ูƒุงู…ู„", variant="primary")
231
 
232
+ response_out = gr.Textbox(label="๐Ÿ“ ุฑุฏ ูƒูˆูŠู†", lines=4, interactive=False)
233
+ audio_out = gr.Audio(label="๐Ÿ”Š ุงู„ุตูˆุช (ุนุจุฑ ุงู„ุฑุงุฏุงุฑ)", type="filepath", autoplay=True)
234
  with gr.Row():
235
+ image_out = gr.Image(label="๐Ÿ–ผ๏ธ ุงู„ุตูˆุฑุฉ (ุนุจุฑ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท)")
236
+ anim_out = gr.Image(label="๐ŸŽฌ ุงู„ุฃู†ู…ูŠุดู† GIF (ุนุจุฑ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท)")
237
+
238
+ run_btn.click(
239
+ fn=integration_test,
240
+ inputs=[prompt_in, teacher_pick, want_image, want_anim, qwen_history_state],
241
+ outputs=[response_out, qwen_history_state, audio_out, image_out, anim_out],
242
+ api_name=False,
243
+ )
244
+
245
+ with gr.Accordion("๐Ÿ—„๏ธ ุณุฌู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฒู†ุฉ ุนู†ุฏ ุงู„ุฅู‚ู„ุงุน", open=False):
246
+ gr.Textbox(value=VAULT_INIT_LOG, lines=8, interactive=False, show_label=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
  if __name__ == "__main__":
249
  demo.launch(server_name="0.0.0.0", server_port=7860)