File size: 15,095 Bytes
b9eb636
fd1afcd
b9eb636
 
fd1afcd
b9eb636
 
 
dee1798
 
 
 
b9eb636
dee1798
 
fd1afcd
 
dee1798
 
fd1afcd
b9eb636
fd1afcd
 
 
dee1798
fd1afcd
 
b9eb636
dee1798
 
 
86a5e03
b9eb636
dee1798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b9eb636
 
dee1798
b9eb636
 
 
 
 
 
 
dee1798
 
 
 
 
 
 
 
fd1afcd
dee1798
 
fd1afcd
dee1798
 
fd1afcd
 
dee1798
fd1afcd
dee1798
 
fd1afcd
dee1798
fd1afcd
 
 
dee1798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd1afcd
dee1798
 
b9eb636
dee1798
 
b9eb636
 
dee1798
 
 
b9eb636
dee1798
 
b9eb636
dee1798
 
 
b9eb636
dee1798
b9eb636
 
dee1798
 
 
 
 
b9eb636
dee1798
86a5e03
dee1798
 
 
 
 
 
b9eb636
dee1798
 
b9eb636
dee1798
 
 
 
 
b9eb636
dee1798
 
 
 
 
fd1afcd
dee1798
 
86a5e03
dee1798
 
fd1afcd
dee1798
 
 
 
 
 
 
 
 
 
 
fd1afcd
dee1798
 
fd1afcd
dee1798
 
 
 
 
 
 
 
 
 
 
 
b9eb636
 
 
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
import os
import json
import gradio as gr
from gradio_client import Client
from huggingface_hub import HfApi, hf_hub_download
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ุฅุนุฏุงุฏุงุช ูˆุงู„ุฑูˆุงุจุท ุจูŠู† ุงู„ู…ุณุงุญุงุช
# โš ๏ธ ุชุฃูƒุฏ ู…ู† ู‡ุฐู‡ ุงู„ุฃุณู…ุงุก ุจุงู„ุถุจุท โ€” ุงุณุชูู†ุชุฌุช ู…ู† ุฑุณุงู„ุชูƒุŒ ุตุญู‘ุญู‡ุง ุฅุฐุง ุงุฎุชู„ูุช
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
RADAR_SPACE_URL = "Asem75/Aiocr_Radar"
MEDIA_SPACE_URL = "Asem75/My_teacher_enemation"        # ู…ุณุงุญุฉ ุงู„ุตูˆุฑ ูˆุงู„ุฃู†ู…ูŠุดู† (SD-Turbo + AnimateDiff)
CONTROLLER_SPACE_URL = "Asem75/My_teacher_controller"  # ู…ุณุงุญุฉ ุชู‡ูŠุฆุฉ ุงู„ุฎุฒู†ุฉ (ู„ู„ู…ุฑุฌุนูŠุฉ ูู‚ุทุŒ ุงู„ุชู‡ูŠุฆุฉ ู…ูุถู…ูŽู‘ู†ุฉ ู‡ู†ุง ู…ุจุงุดุฑุฉ)
VAULT_REPO_ID = "Asem75/aiocr_asistant"

MODEL_ID = "Qwen/Qwen2.5-3B-Instruct"
DEVICE = "cpu"

RADAR_API_KEY = os.environ.get("INTERNAL_API_KEY", "").strip()
HF_TOKEN = os.environ.get("HF_TOKEN", "").strip()

if not HF_TOKEN:
    print("โš ๏ธ ุชู†ุจูŠู‡: HF_TOKEN ุบูŠุฑ ู…ุถุจูˆุท ููŠ ุฃุณุฑุงุฑ ู‡ุฐู‡ ุงู„ู…ุณุงุญุฉ โ€” ุงู„ู‚ุฑุงุกุฉ/ุงู„ูƒุชุงุจุฉ ููŠ ุงู„ุฎุฒู†ุฉ ู‚ุฏ ุชูุดู„ ุฅุฐุง ูƒุงู†ุช ุฎุงุตุฉ.")

_hf_api = HfApi(token=HF_TOKEN) if HF_TOKEN else HfApi()

print("โณ ุชุญู…ูŠู„ ู†ู…ูˆุฐุฌ ูƒูˆูŠู† (ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ)...")
_tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
_model = AutoModelForCausalLM.from_pretrained(
    MODEL_ID, torch_dtype=torch.float32, device_map="cpu", low_cpu_mem_usage=True
)
print("โœ… ูƒูˆูŠู† ุฌุงู‡ุฒ")

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุชู‡ูŠุฆุฉ ู…ู„ูุงุช ุงู„ุฎุฒู†ุฉ โ€” ู†ูุณ ุจู†ูŠุฉ ูƒูˆุฏ "controller" ุงู„ุฐูŠ ุฃุฑุณู„ุชู‡ุŒ ู…ูุถู…ูŽู‘ู†ุฉ
# ู‡ู†ุง ู…ุจุงุดุฑุฉ (ู„ุง ุชุนุชู…ุฏ ุนู„ู‰ ุงุณุชุฏุนุงุก ู…ุณุงุญุฉ ู‚ุฏ ุชูƒูˆู† ู†ุงุฆู…ุฉ ุนู†ุฏ ูƒู„ ุฅู‚ู„ุงุน).
#
# ๐Ÿ› ๏ธ ุงู„ุฅุตู„ุงุญ ุงู„ุฐูŠ ูˆุฌุฏุชู‡ ููŠ ู…ุฑุงุฌุนุชูŠ: ุฑูุน ุงู„ู…ู„ู ุงู„ุจุฏูŠู„ (ุนู†ุฏ ุนุฏู… ูˆุฌูˆุฏู‡)
# ู„ู… ูŠูƒู† ู…ุญู…ูŠุงู‹ ุจู€ try/except ุฎุงุต ุจู‡ โ€” ุฃูŠ ูุดู„ ููŠ ุงู„ุฑูุน (ุชูˆูƒู† ุฎุงุทุฆ/ุตู„ุงุญูŠุงุช)
# ูƒุงู† ุณูŠุชุณุจุจ ุจุงู†ู‡ูŠุงุฑ ุงู„ู…ุณุงุญุฉ ุจุงู„ูƒุงู…ู„ ุนู†ุฏ ุงู„ุฅู‚ู„ุงุน. ุงู„ุขู† ู…ุญู…ูŠ ูˆูŠูุณุฌูŽู‘ู„
# ุงู„ูุดู„ ููŠ ุงู„ุณุฌู„ ุจุฏู„ ุฅุณู‚ุงุท ุงู„ุชุทุจูŠู‚.
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
VAULT_STRUCTURE = {
    "curriculum_plans/lessons_division.json": {
        "description": "ุชู‚ุณูŠู… ุงู„ุฏุฑูˆุณ ูˆุงู„ู…ูˆุงุฏ ุงู„ุชุนู„ูŠู…ูŠุฉ ุจูŠู† ุงู„ุนู„ู…ูŠ ูˆุงู„ุฃุฏุจูŠ ูˆุงู„ูˆุณูˆู…",
        "tracks": {"scientific": [], "literary": []}
    },
    "curriculum_plans/co_planning_qwen.json": {
        "description": "ู…ู„ู ุงู„ุชุฎุทูŠุท ุงู„ู…ุดุชุฑูƒ ู…ุน ู…ูˆุฏูŠู„ ูƒูˆูŠู† ู„ุชุญุฏูŠุฏ ุงู„ุฃู‡ุฏุงู ุงู„ุชุฑุจูˆูŠุฉ",
        "qwen_guidelines": {}, "shared_plans": []
    },
    "learning_gaps/student_levels.json": {
        "description": "ุณุฌู„ ู…ุณุชูˆูŠุงุช ุงู„ุทู„ุงุจ ูˆุชุตู†ูŠู ู…ู‡ุงุฑุงุชู‡ู… ุงู„ุชุนู„ูŠู…ูŠุฉ",
        "levels": {"beginner": [], "intermediate": [], "advanced": []}
    },
    "learning_gaps/gap_analysis.json": {
        "description": "ุชุญู„ูŠู„ ุงู„ูุฌูˆุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ ูˆุฎุทุท ุงู„ู…ุนุงู„ุฌุฉ ุงู„ูุฑุฏูŠุฉ ู„ู„ุทู„ุงุจ",
        "detected_gaps": [], "remedial_actions": []
    },
    "teacher_student_interaction/interaction_logs.json": {
        "description": "ุณุฌู„ุงุช ุนู„ุงู‚ุฉ ุงู„ุทุงู„ุจ ุจุงู„ุฃุณุชุงุฐ ูˆุงู„ุฏุนู… ุงู„ุชูˆุฌูŠู‡ูŠ",
        "teacher_notes": [], "student_feedback": []
    },
}


def initialize_vault_files():
    log_lines = []
    for file_path, default_content in VAULT_STRUCTURE.items():
        try:
            hf_hub_download(repo_id=VAULT_REPO_ID, filename=file_path, repo_type="dataset", token=HF_TOKEN or None)
            log_lines.append(f"โœ… {file_path} ู…ูˆุฌูˆุฏ ู…ุณุจู‚ุงู‹ ูˆุฌุงู‡ุฒ.")
        except Exception:
            try:
                local_filename = f"/tmp/{os.path.basename(file_path)}"
                with open(local_filename, "w", encoding="utf-8") as f:
                    json.dump(default_content, f, ensure_ascii=False, indent=4)
                _hf_api.upload_file(
                    path_or_fileobj=local_filename, path_in_repo=file_path,
                    repo_id=VAULT_REPO_ID, repo_type="dataset", token=HF_TOKEN or None,
                )
                os.remove(local_filename)
                log_lines.append(f"๐Ÿš€ ุชู… ุฅู†ุดุงุก ูˆุฑูุน: {file_path}")
            except Exception as e_upload:
                log_lines.append(f"โŒ ูุดู„ ุฅู†ุดุงุก {file_path}: {e_upload}")
    return "\n".join(log_lines)


print("โณ ูุญุต ูˆุชู‡ูŠุฆุฉ ู…ู„ูุงุช ุงู„ุฎุฒู†ุฉ...")
VAULT_INIT_LOG = initialize_vault_files()
print(VAULT_INIT_LOG)

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ู…ุนู„ู…ูˆู† ูˆุงู„ุฃุตูˆุงุช (Tab 1 โ€” ุญุฌุฒ ู…ุจุฏุฆูŠุŒ ุชุทูˆูŠุฑ ูƒุงู…ู„ ู„ุงุญู‚ุงู‹)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
TEACHERS = [
    ("ุงู„ุฃุณุชุงุฐ ุนุจูˆุฏ", "ar-JO-TaimNeural"),
    ("ุงู„ุฃุณุชุงุฐุฉ ุณู„ู…ู‰", "ar-EG-SalmaNeural"),
    ("ุงู„ุฃุณุชุงุฐ ุญุงู…ุฏ", "ar-SA-HamedNeural"),
]

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ุฑุจุท ุจู…ุณุงุญุฉ ุงู„ุฑุงุฏุงุฑ (ุตูˆุช) โ€” ุจู†ูุณ ู†ู…ุท ุงู„ุญู…ุงูŠุฉ ุจู…ูุชุงุญ ุณุฑูŠ ุงู„ู…ูุนุชู…ุฏ ุณุงุจู‚ุงู‹
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
def synth_via_radar(text, speaker_name):
    try:
        client = Client(RADAR_SPACE_URL)
        audio_url = client.predict(text, speaker_name, RADAR_API_KEY, api_name="/synth_arabic")
        if audio_url and isinstance(audio_url, (list, tuple)):
            audio_url = audio_url[0]
        return str(audio_url).strip() if audio_url else None
    except Exception as e:
        print(f"โš ๏ธ ุฎุทุฃ ุงู„ุฑุงุฏุงุฑ: {e}")
        return None


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ุฑุจุท ุจู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑ/ุฃู†ู…ูŠุดู†)
# โš ๏ธ ู…ู„ุงุญุธุฉ ุฃู…ุงู†: ู†ู‚ุทุชุง API ู‡ุฐู‡ (generate_image, generate_animation) ููŠ
# ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท ุบูŠุฑ ู…ุญู…ูŠุชูŠู† ุจุฃูŠ ู…ูุชุงุญ ุณุฑูŠ ุญุงู„ูŠุงู‹ (ุจุฎู„ุงู ุงู„ุฑุงุฏุงุฑ). ุฅุฐุง
# ุฃุฑุฏุช ุญู…ุงูŠุชู‡ู…ุง ุจู†ูุณ ู…ุจุฏุฃ INTERNAL_API_KEYุŒ ุฃุฎุจุฑู†ูŠ ูˆุฃุถูŠูู‡ ู‡ู†ุงูƒ ุฃูŠุถุงู‹.
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
def generate_image_via_media(prompt):
    try:
        client = Client(MEDIA_SPACE_URL)
        return client.predict(prompt, api_name="/generate_image")
    except Exception as e:
        print(f"โš ๏ธ ุฎุทุฃ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑุฉ): {e}")
        return None


def generate_animation_via_media(prompt):
    try:
        client = Client(MEDIA_SPACE_URL)
        return client.predict(prompt, api_name="/generate_animation")
    except Exception as e:
        print(f"โš ๏ธ ุฎุทุฃ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุฃู†ู…ูŠุดู†): {e}")
        return None


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ (ูƒูˆูŠู†)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
def ask_teacher(prompt, history):
    history = history or []
    messages = [{
        "role": "system",
        "content": "ุฃู†ุช ูƒูˆูŠู†ุŒ ุงู„ุนู‚ู„ ุงู„ู…ุฏุจุฑ ู„ู…ู†ุตุฉ ุชุนู„ูŠู…ูŠุฉ ุนุฑุจูŠุฉ. ุชุณุงุนุฏ ููŠ ุตูŠุงุบุฉ ุฏุฑูˆุณ ูˆู…ุญุชูˆู‰ ุชุนู„ูŠู…ูŠ ู‚ุตูŠุฑ ูˆูˆุงุถุญ ุจุงู„ุนุฑุจูŠุฉุŒ ูˆุชุฌูŠุจ ุจุฅูŠุฌุงุฒ ูˆูˆุถูˆุญ."
    }]
    messages.extend(history)
    messages.append({"role": "user", "content": prompt})

    text_prompt = _tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
    inputs = _tokenizer([text_prompt], return_tensors="pt").to(DEVICE)

    with torch.no_grad():
        out_ids = _model.generate(
            **inputs, max_new_tokens=200, temperature=0.5, do_sample=True,
            repetition_penalty=1.15, pad_token_id=_tokenizer.eos_token_id
        )
    out_ids = [o[len(i):] for i, o in zip(inputs.input_ids, out_ids)]
    response = _tokenizer.batch_decode(out_ids, skip_special_tokens=True)[0].strip()

    new_history = history + [{"role": "user", "content": prompt}, {"role": "assistant", "content": response}]
    return response, new_history


def integration_test(prompt, teacher_choice, gen_image, gen_anim, history_state):
    if not prompt or not prompt.strip():
        return "โš ๏ธ ุงูƒุชุจ ู†ุตุงู‹ ุฃูˆู„ุงู‹", history_state, None, None, None

    response, new_history = ask_teacher(prompt, history_state)
    speaker_name = dict(TEACHERS).get(teacher_choice, "ar-JO-TaimNeural")

    audio_path = synth_via_radar(response, speaker_name)
    image_path = generate_image_via_media(response) if gen_image else None
    anim_path = generate_animation_via_media(response) if gen_anim else None

    return response, new_history, audio_path, image_path, anim_path


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ุงู„ูˆุงุฌู‡ุฉ: ุณุชุฉ ุชุจูˆูŠุจุงุช ุญุฌุฒ ู…ูƒุงู† + ู„ูˆุญุฉ ูุญุต ุงู„ุฑุจุท
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.Blocks(title="My Teacher โ€” ุงู„ู…ู†ุตุฉ ุงู„ุฑุฆูŠุณูŠุฉ", theme=gr.themes.Soft()) as demo:
    gr.Markdown("# ๐ŸŽ“ ุงู„ู…ู†ุตุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ ุงู„ุฐูƒูŠุฉ ุงู„ู…ูˆุญุฏุฉ")

    qwen_history_state = gr.State([])

    with gr.Tabs():
        with gr.Tab("๐Ÿ‘จโ€๐Ÿซ ุฅุนุฏุงุฏุงุช ุงู„ู…ุนู„ู… ูˆุงู„ุตูˆุช"):
            gr.Markdown(
                "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุณูŠุชู… ู‡ู†ุง: ุชุตูุญ ุงู„ู…ุนู„ู…ูŠู† ุงู„ู…ุชุงุญูŠู†ุŒ ูˆุงุฎุชูŠุงุฑ "
                "ุงู„ุฃุณุชุงุฐ ุงู„ู…ู†ุงุณุจุŒ ูˆุฑุจุท ูƒู„ ู…ุนู„ู… ุจุฎุงู…ุฉ ุตูˆุชูŠุฉ ุนุจุฑ edge-tts/ุงู„ุฑุงุฏุงุฑ."
            )

        with gr.Tab("๐ŸŽฌ ุงู„ููŠุฏูŠูˆู‡ุงุช ุงู„ุชุนู„ูŠู…ูŠุฉ ุงู„ู…ุณุฌู„ุฉ"):
            gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ู…ูƒุชุจุฉ ุงู„ุฏุฑูˆุณ ูˆุงู„ููŠุฏูŠูˆู‡ุงุช ุงู„ู…ุณุฌู„ุฉ ู…ุณุจู‚ุงู‹ ู„ู„ู…ุฑุงุฌุนุฉ.")

        with gr.Tab("๐Ÿ—‚๏ธ ุฎุทุท ุงู„ุฏุฑูˆุณ ูˆุงู„ุชู‚ุณูŠู…"):
            gr.Markdown(
                "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ู†ุงูุฐุฉ ุชูุงุนู„ูŠุฉ ู…ุน ูƒูˆูŠู† ู„ู„ุชุฎุทูŠุท ุงู„ู…ุดุชุฑูƒุŒ "
                "ูˆุชู‚ุณูŠู… ุงู„ู…ูˆุงุฏ ุจูŠู† ุงู„ุนู„ู…ูŠ ูˆุงู„ุฃุฏุจูŠ."
            )

        with gr.Tab("๐Ÿ“Š ุงู„ู…ุณุชูˆูŠุงุช ูˆุชุญู„ูŠู„ ุงู„ูุฌูˆุฉ ุงู„ุชุนู„ูŠู…ูŠุฉ"):
            gr.Markdown(
                "๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุชุชุจุน ู…ุณุชูˆู‰ ุงู„ุทุงู„ุจ ูˆุชุญู„ูŠู„ ุงู„ุฃุฎุทุงุก "
                "(ุจุงู„ุงุณุชุนุงู†ุฉ ุจู€ CAMeL-BERT) ูˆุฎุทุท ุณุฏ ุงู„ูุฌูˆุงุช."
            )

        with gr.Tab("๐Ÿ’ฌ ุนู„ุงู‚ุฉ ุงู„ุทุงู„ุจ ูˆุงู„ุฃุณุชุงุฐ"):
            gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ุงู„ุฑุณุงุฆู„ ุงู„ุชูˆุฌูŠู‡ูŠุฉุŒ ุงู„ุชู‚ูŠูŠู…ุงุชุŒ ูˆุงู„ุฏุนู… ุงู„ูุฑุฏูŠ.")

        with gr.Tab("๐Ÿ–ผ๏ธ ุฃุฑุดูŠู ูˆุฅุฏุงุฑุฉ ุงู„ูˆุณุงุฆุท"):
            gr.Markdown("๐Ÿšง **ู‚ูŠุฏ ุงู„ุชุทูˆูŠุฑ.** ูู‡ุฑุณุฉ ุงู„ุตูˆุฑ ูˆุงู„ุฃู†ู…ูŠุดู† ุงู„ู…ูˆู„ู‘ุฏุฉ ู„ู…ู†ุน ุฅุนุงุฏุฉ ุงู„ุชูˆู„ูŠุฏ.")

        with gr.Tab("๐Ÿ”— ู„ูˆุญุฉ ูุญุต ุงู„ุฑุจุท (API)"):
            gr.Markdown(
                "ุชุฌุฑุจุฉ ู…ุจุงุดุฑุฉ ุชูุซุจุช ุฃู† **ูƒูˆูŠู† + ุงู„ุฑุงุฏุงุฑ (ุตูˆุช) + ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท (ุตูˆุฑุฉ/ุฃู†ู…ูŠุดู†)** "
                "ู…ุฑุจูˆุทูˆู† ูุนู„ูŠุงู‹ ุนุจุฑ APIุŒ ู‚ุจู„ ุจู†ุงุก ุงู„ุชุจูˆูŠุจุงุช ุงู„ุณุช ุจุงู„ุชูุตูŠู„."
            )
            prompt_in = gr.Textbox(label="โœ๏ธ ุงูƒุชุจ ููƒุฑุฉ ุฃูˆ ุณุคุงู„ุงู‹ ุชุนู„ูŠู…ูŠุงู‹", lines=3)
            teacher_pick = gr.Dropdown(choices=[t[0] for t in TEACHERS], value=TEACHERS[0][0], label="๐ŸŽ™๏ธ ุงุฎุชุฑ ุงู„ู…ุนู„ู…/ุงู„ุตูˆุช")
            with gr.Row():
                want_image = gr.Checkbox(label="๐Ÿ–ผ๏ธ ุชูˆู„ูŠุฏ ุตูˆุฑุฉ ุชูˆุถูŠุญูŠุฉ", value=False)
                want_anim = gr.Checkbox(label="๐ŸŽฌ ุชูˆู„ูŠุฏ ุฃู†ู…ูŠุดู† (ุฃุจุทุฃ ุจูƒุซูŠุฑ)", value=False)
            run_btn = gr.Button("๐Ÿš€ ุฌุฑู‘ุจ ุงู„ุฑุจุท ุงู„ูƒุงู…ู„", variant="primary")

            response_out = gr.Textbox(label="๐Ÿ“ ุฑุฏ ูƒูˆูŠู†", lines=4, interactive=False)
            audio_out = gr.Audio(label="๐Ÿ”Š ุงู„ุตูˆุช (ุนุจุฑ ุงู„ุฑุงุฏุงุฑ)", type="filepath", autoplay=True)
            with gr.Row():
                image_out = gr.Image(label="๐Ÿ–ผ๏ธ ุงู„ุตูˆุฑุฉ (ุนุจุฑ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท)")
                anim_out = gr.Image(label="๐ŸŽฌ ุงู„ุฃู†ู…ูŠุดู† GIF (ุนุจุฑ ู…ุณุงุญุฉ ุงู„ูˆุณุงุฆุท)")

            run_btn.click(
                fn=integration_test,
                inputs=[prompt_in, teacher_pick, want_image, want_anim, qwen_history_state],
                outputs=[response_out, qwen_history_state, audio_out, image_out, anim_out],
                api_name=False,
            )

    with gr.Accordion("๐Ÿ—„๏ธ ุณุฌู„ ุชู‡ูŠุฆุฉ ุงู„ุฎุฒู†ุฉ ุนู†ุฏ ุงู„ุฅู‚ู„ุงุน", open=False):
        gr.Textbox(value=VAULT_INIT_LOG, lines=8, interactive=False, show_label=False)

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860)