usermma commited on
Commit
f6dd924
ยท
verified ยท
1 Parent(s): 387087c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +545 -0
app.py ADDED
@@ -0,0 +1,545 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from transformers import AutoTokenizer, AutoModelForCausalLM
4
+
5
+ # ----------------------------------------------------------------------
6
+ # Model (unchanged from your working code)
7
+ # ----------------------------------------------------------------------
8
+ MODEL_ID = "SupraLabs/Supra-50M-Reasoning"
9
+
10
+ THINK_START = "<|begin_of_thought|>"
11
+ THINK_END = "<|end_of_thought|>"
12
+ SOL_START = "<|begin_of_solution|>"
13
+ SOL_END = "<|end_of_solution|>"
14
+
15
+ DEFAULT_SYSTEM_PROMPT = (
16
+ "Your role as an assistant involves thoroughly exploring questions through "
17
+ "a systematic long thinking process before providing the final precise and "
18
+ "accurate solutions."
19
+ )
20
+
21
+ # ----------------------------------------------------------------------
22
+ # Load model once
23
+ # ----------------------------------------------------------------------
24
+ print("Loading model...")
25
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
26
+ model = AutoModelForCausalLM.from_pretrained(
27
+ MODEL_ID,
28
+ dtype=torch.float32,
29
+ device_map="cpu",
30
+ )
31
+ model.eval()
32
+ print("Model ready.")
33
+
34
+ # ----------------------------------------------------------------------
35
+ # Prompt construction (as provided)
36
+ # ----------------------------------------------------------------------
37
+ def build_prompt(question: str, system_prompt: str) -> str:
38
+ return (
39
+ f"[SYSTEM]: {system_prompt}\n\n"
40
+ f"[USER]: {question}\n\n"
41
+ f"[ASSISTANT]: {THINK_START}\n"
42
+ )
43
+
44
+ def parse_output(raw: str):
45
+ thought, answer = "", raw
46
+ if THINK_START in raw and THINK_END in raw:
47
+ t0 = raw.index(THINK_START) + len(THINK_START)
48
+ t1 = raw.index(THINK_END)
49
+ thought = raw[t0:t1].strip()
50
+ if SOL_START in raw and SOL_END in raw:
51
+ s0 = raw.index(SOL_START) + len(SOL_START)
52
+ s1 = raw.index(SOL_END)
53
+ answer = raw[s0:s1].strip()
54
+ elif SOL_START in raw:
55
+ s0 = raw.index(SOL_START) + len(SOL_START)
56
+ answer = raw[s0:].strip()
57
+ elif THINK_END in raw:
58
+ answer = raw[raw.index(THINK_END) + len(THINK_END):].strip()
59
+ return thought, answer
60
+
61
+ def generate(prompt, system_prompt, max_new_tokens, temperature, top_p, top_k, show_thinking):
62
+ if not prompt.strip():
63
+ return "", "Please enter a question."
64
+ full_prompt = build_prompt(prompt, system_prompt)
65
+ inputs = tokenizer(full_prompt, return_tensors="pt")
66
+ input_ids = inputs["input_ids"]
67
+ with torch.no_grad():
68
+ output_ids = model.generate(
69
+ input_ids,
70
+ max_new_tokens=max_new_tokens,
71
+ do_sample=temperature > 0,
72
+ temperature=temperature if temperature > 0 else 1.0,
73
+ top_p=top_p,
74
+ top_k=top_k,
75
+ pad_token_id=tokenizer.eos_token_id,
76
+ eos_token_id=tokenizer.eos_token_id,
77
+ )
78
+ generated = output_ids[0][input_ids.shape[-1]:]
79
+ raw = tokenizer.decode(generated, skip_special_tokens=False)
80
+ raw = raw.replace("<s>", "").replace("</s>", "").strip()
81
+ raw = THINK_START + "\n" + raw
82
+ thought, answer = parse_output(raw)
83
+ return (thought if show_thinking else ""), answer
84
+
85
+ # ----------------------------------------------------------------------
86
+ # Chat callback for Gradio
87
+ # ----------------------------------------------------------------------
88
+ def chat_generate(message, history, system_prompt, max_tokens, temperature, top_p, top_k, show_think):
89
+ if not message.strip():
90
+ return "", [], "", ""
91
+ thought, answer = generate(message, system_prompt, max_tokens, temperature, top_p, top_k, show_think)
92
+ new_history = [
93
+ {"role": "user", "content": message},
94
+ {"role": "assistant", "content": answer},
95
+ ]
96
+ return "", new_history, thought, answer
97
+
98
+ def clear_fn():
99
+ return "", [], "", ""
100
+
101
+ # ----------------------------------------------------------------------
102
+ # Custom CSS โ€“ Classic, elegant, dark theme with serif headings
103
+ # ----------------------------------------------------------------------
104
+ CUSTOM_CSS = """
105
+ @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700&family=Inter:wght@300;400;500;600&family=JetBrains+Mono&display=swap');
106
+
107
+ * { box-sizing: border-box; }
108
+
109
+ body, .gradio-container {
110
+ background: #1a1a1a !important;
111
+ color: #d4c5b2 !important;
112
+ font-family: 'Inter', sans-serif !important;
113
+ }
114
+
115
+ .gradio-container {
116
+ max-width: 1300px !important;
117
+ margin: 0 auto !important;
118
+ padding: 2rem 1.5rem !important;
119
+ }
120
+
121
+ /* Header with language toggle */
122
+ #header-section {
123
+ background: linear-gradient(145deg, #2a2118 0%, #1e1b15 100%);
124
+ border: 1px solid #5c4a32;
125
+ border-radius: 18px;
126
+ padding: 2rem;
127
+ margin-bottom: 2rem;
128
+ position: relative;
129
+ box-shadow: 0 8px 30px rgba(0,0,0,0.5);
130
+ }
131
+
132
+ #header-section h1 {
133
+ font-family: 'Playfair Display', serif;
134
+ font-size: 2.5rem;
135
+ color: #d4af37;
136
+ margin-top: 0;
137
+ font-weight: 700;
138
+ letter-spacing: 1px;
139
+ }
140
+
141
+ #header-section p {
142
+ font-size: 1.1rem;
143
+ color: #c0b09a;
144
+ line-height: 1.7;
145
+ }
146
+
147
+ .lang-toggle {
148
+ position: absolute;
149
+ top: 20px;
150
+ right: 20px;
151
+ background: #3e3525;
152
+ border: 1px solid #5c4a32;
153
+ color: #d4af37;
154
+ padding: 6px 16px;
155
+ border-radius: 30px;
156
+ font-family: 'Inter', sans-serif;
157
+ font-weight: 600;
158
+ font-size: 0.9rem;
159
+ cursor: pointer;
160
+ transition: all 0.3s;
161
+ }
162
+ .lang-toggle:hover {
163
+ background: #5c4a32;
164
+ color: #f5e6c8;
165
+ }
166
+
167
+ /* Model cards */
168
+ .model-card {
169
+ background: #2a241c;
170
+ border: 1px solid #4a3e2c;
171
+ border-radius: 14px;
172
+ padding: 1.2rem;
173
+ margin-bottom: 1rem;
174
+ transition: transform 0.2s, box-shadow 0.2s;
175
+ }
176
+ .model-card:hover {
177
+ transform: translateY(-3px);
178
+ box-shadow: 0 10px 25px rgba(0,0,0,0.7);
179
+ }
180
+ .model-card a {
181
+ color: #d4af37;
182
+ text-decoration: none;
183
+ font-weight: 600;
184
+ font-size: 1.15rem;
185
+ }
186
+ .model-card p {
187
+ color: #b9a88c;
188
+ margin: 0.5rem 0 0;
189
+ font-size: 0.9rem;
190
+ }
191
+
192
+ /* Focus list */
193
+ .focus-list {
194
+ list-style: none;
195
+ padding-left: 0;
196
+ }
197
+ .focus-list li {
198
+ padding: 0.3rem 0;
199
+ font-size: 1rem;
200
+ color: #c0b09a;
201
+ }
202
+
203
+ /* Resources table */
204
+ .resources-table {
205
+ width: 100%;
206
+ border-collapse: collapse;
207
+ margin-top: 1rem;
208
+ }
209
+ .resources-table td {
210
+ padding: 10px 0;
211
+ border-bottom: 1px solid #3e3525;
212
+ }
213
+ .resources-table a {
214
+ color: #d4af37;
215
+ text-decoration: none;
216
+ font-weight: 500;
217
+ }
218
+ .resources-table a:hover {
219
+ text-decoration: underline;
220
+ }
221
+
222
+ /* Footer */
223
+ .footer-text {
224
+ text-align: center;
225
+ color: #6b5e4a;
226
+ font-size: 0.85rem;
227
+ margin-top: 2rem;
228
+ padding-top: 1.5rem;
229
+ border-top: 1px solid #3e3525;
230
+ }
231
+ .footer-text a {
232
+ color: #d4af37;
233
+ text-decoration: none;
234
+ }
235
+
236
+ /* Gradio components restyling */
237
+ .chatbot-wrap .wrap {
238
+ background: #1e1b15 !important;
239
+ border: 1px solid #4a3e2c !important;
240
+ border-radius: 14px !important;
241
+ }
242
+
243
+ .message.user {
244
+ background: linear-gradient(135deg, #5c4a32, #7a5c3e) !important;
245
+ color: white !important;
246
+ border-radius: 18px 18px 4px 18px !important;
247
+ padding: 12px 16px !important;
248
+ }
249
+ .message.bot {
250
+ background: #2a241c !important;
251
+ color: #e8dcc8 !important;
252
+ border: 1px solid #5c4a32 !important;
253
+ border-radius: 18px 18px 18px 4px !important;
254
+ }
255
+
256
+ .input-wrap textarea {
257
+ background: #2a241c !important;
258
+ border: 1px solid #4a3e2c !important;
259
+ color: #e8dcc8 !important;
260
+ font-family: 'Inter', sans-serif !important;
261
+ }
262
+ .input-wrap textarea:focus {
263
+ border-color: #d4af37 !important;
264
+ box-shadow: 0 0 0 3px rgba(212,175,55,0.15) !important;
265
+ }
266
+
267
+ button.primary {
268
+ background: linear-gradient(135deg, #7a5c3e, #a67c46) !important;
269
+ border: none !important;
270
+ border-radius: 10px !important;
271
+ color: white !important;
272
+ font-weight: 600 !important;
273
+ transition: all 0.2s !important;
274
+ }
275
+ button.primary:hover {
276
+ transform: translateY(-1px) !important;
277
+ box-shadow: 0 4px 20px rgba(166,124,70,0.4) !important;
278
+ }
279
+
280
+ .thinking-box textarea {
281
+ font-family: 'JetBrains Mono', monospace !important;
282
+ background: #1a1510 !important;
283
+ border: 1px solid #3e3525 !important;
284
+ color: #b9a88c !important;
285
+ }
286
+ .answer-box textarea {
287
+ font-family: 'Inter', sans-serif !important;
288
+ background: #1a1e15 !important;
289
+ border: 1px solid #3e4a2c !important;
290
+ color: #c5d4af !important;
291
+ }
292
+ .system-box textarea {
293
+ background: #1a1510 !important;
294
+ border: 1px solid #5c4a32 !important;
295
+ color: #d4af37 !important;
296
+ }
297
+
298
+ input[type=range] {
299
+ accent-color: #d4af37 !important;
300
+ }
301
+ .accordion {
302
+ background: #1e1b15 !important;
303
+ border: 1px solid #4a3e2c !important;
304
+ }
305
+
306
+ footer { display: none !important; }
307
+ """
308
+
309
+ # ----------------------------------------------------------------------
310
+ # Bilingual content for the header & info section
311
+ # ----------------------------------------------------------------------
312
+ CONTENT = {
313
+ "en": {
314
+ "title": "Welcome to ThingsAI! ๐Ÿค—",
315
+ "intro": "Building efficient, bilingual AI models that run anywhere. ๐Ÿ‡ฎ๐Ÿ‡น ๐Ÿ‡ฌ๐Ÿ‡ง",
316
+ "models_title": "๐Ÿค– Our Models",
317
+ "model_q135": "A lightweight bilingual (Italian + English) language model with <b>135M parameters</b>. Features GQA, SwiGLU, RMSNorm, and RoPE. Trained on 50B+ tokens.",
318
+ "model_q270": "Our most powerful small model โ€” <b>270M parameters</b> with 32 layers, 768 hidden dimensions, and 65K vocabulary. Currently in active training on 10B+ tokens, planned 135B tokens.",
319
+ "model_qmod": "A multi-label moderation model covering <b>9 categories</b>: toxic, severe_toxic, obscene, threat, insult, identity_hate, cyberbullying, hate_speech, offensive.",
320
+ "focus_title": "๐ŸŽฏ What We Focus On",
321
+ "focus_items": [
322
+ "โšก Small, efficient architectures โ€” GQA, weight tying, deepโ€‘thin design",
323
+ "๐ŸŒ Bilingual training โ€” Italian + English from scratch",
324
+ "๐Ÿ”“ Openโ€‘source everything โ€” weights, code, datasets",
325
+ "๐Ÿ’ป Realโ€‘world deployment โ€” runs on consumer hardware"
326
+ ],
327
+ "resources_title": "๐Ÿ“‚ Resources",
328
+ "resources": [
329
+ ("๐Ÿ“š Quark-135M-Bilingual", "https://huggingface.co/ThingAI/Quark-135m-Bilingual"),
330
+ ("๐Ÿ›ก๏ธ Quark-Mod", "https://huggingface.co/ThingsAI/Quark-Mod"),
331
+ ("๐Ÿ“ HuggingFace Community", "https://huggingface.co/ThingsAI"),
332
+ ("๐Ÿ’ป GitHub", "https://github.com/overcastlab")
333
+ ],
334
+ "dataset_link": "๐Ÿ“Š Dataset: <a href='https://huggingface.co/datasets/ThingAI/OmniBook'>ThingAI/OmniBook</a>",
335
+ "footer": "Made with โค๏ธ by ThingsAI ยท <a href='https://things-ai.org'>Website</a> ยท <a href='https://github.com/overcastlab'>GitHub</a>"
336
+ },
337
+ "it": {
338
+ "title": "Benvenuti in ThingsAI! ๐Ÿค—",
339
+ "intro": "Costruiamo modelli AI bilingui efficienti che funzionano ovunque. ๐Ÿ‡ฎ๐Ÿ‡น ๐Ÿ‡ฌ๐Ÿ‡ง",
340
+ "models_title": "๐Ÿค– I Nostri Modelli",
341
+ "model_q135": "Un modello linguistico bilingue leggero (italiano + inglese) con <b>135M parametri</b>. Caratteristiche: GQA, SwiGLU, RMSNorm, RoPE. Addestrato su 50B+ token.",
342
+ "model_q270": "Il nostro piccolo modello piรน potente โ€” <b>270M parametri</b> con 32 strati, dimensione nascosta 768, vocabolario 65K. In addestramento attivo su 10B+ token, pianificato 135B token.",
343
+ "model_qmod": "Un modello di moderazione multiโ€‘etichetta che copre <b>9 categorie</b>: tossico, gravemente_tossico, osceno, minaccia, insulto, odio_identitario, cyberbullismo, incitamento_all'odio, offensivo.",
344
+ "focus_title": "๐ŸŽฏ Su Cosa Ci Concentriamo",
345
+ "focus_items": [
346
+ "โšก Architetture piccole ed efficienti โ€” GQA, weight tying, design deepโ€‘thin",
347
+ "๐ŸŒ Addestramento bilingue โ€” italiano + inglese da zero",
348
+ "๐Ÿ”“ Tutto openโ€‘source โ€” pesi, codice, dataset",
349
+ "๐Ÿ’ป Implementazione reale โ€” funziona su hardware consumer"
350
+ ],
351
+ "resources_title": "๐Ÿ“‚ Risorse",
352
+ "resources": [
353
+ ("๐Ÿ“š Quark-135M-Bilingual", "https://huggingface.co/ThingAI/Quark-135m-Bilingual"),
354
+ ("๐Ÿ›ก๏ธ Quark-Mod", "https://huggingface.co/ThingsAI/Quark-Mod"),
355
+ ("๐Ÿ“ Comunitร  HuggingFace", "https://huggingface.co/ThingsAI"),
356
+ ("๐Ÿ’ป GitHub", "https://github.com/overcastlab")
357
+ ],
358
+ "dataset_link": "๐Ÿ“Š Dataset: <a href='https://huggingface.co/datasets/ThingAI/OmniBook'>ThingAI/OmniBook</a>",
359
+ "footer": "Fatto con โค๏ธ da ThingsAI ยท <a href='https://things-ai.org'>Sito Web</a> ยท <a href='https://github.com/overcastlab'>GitHub</a>"
360
+ }
361
+ }
362
+
363
+ # ----------------------------------------------------------------------
364
+ # Build the complete Gradio interface
365
+ # ----------------------------------------------------------------------
366
+ with gr.Blocks(
367
+ title="ThingsAI โ€“ Chat & Models",
368
+ css=CUSTOM_CSS,
369
+ theme=gr.themes.Soft() # base theme overridden by our CSS
370
+ ) as demo:
371
+
372
+ # --- Header + Language Toggle ---
373
+ gr.HTML("""
374
+ <div id="header-section">
375
+ <button class="lang-toggle" onclick="switchLanguage()">๐Ÿ‡ฎ๐Ÿ‡น Italiano</button>
376
+ <h1 id="main-title">Welcome to ThingsAI! ๐Ÿค—</h1>
377
+ <p id="main-intro">Building efficient, bilingual AI models that run anywhere. ๐Ÿ‡ฎ๐Ÿ‡น ๐Ÿ‡ฌ๐Ÿ‡ง</p>
378
+ </div>
379
+ """)
380
+
381
+ # --- Model Cards (using HTML, IDs for translation) ---
382
+ gr.HTML("""
383
+ <h2 id="models-title" style="color:#d4af37; font-family:'Playfair Display',serif;">๐Ÿค– Our Models</h2>
384
+ <div class="model-card">
385
+ <a href="https://huggingface.co/ThingAI/Quark-135m-Bilingual" target="_blank">Quark-135M</a>
386
+ <p id="model-desc-135">A lightweight bilingual (Italian + English) language model with <b>135M parameters</b>. Features GQA, SwiGLU, RMSNorm, and RoPE. Trained on 50B+ tokens.</p>
387
+ </div>
388
+ <div class="model-card">
389
+ <a href="https://huggingface.co/ThingAI/Quark-270m-Instruct" target="_blank">Quark-270M (Instruct)</a>
390
+ <p id="model-desc-270">Our most powerful small model โ€” <b>270M parameters</b> with 32 layers, 768 hidden dimensions, and 65K vocabulary. Currently in active training on 10B+ tokens, planned 135B tokens.</p>
391
+ </div>
392
+ <div class="model-card">
393
+ <a href="https://huggingface.co/ThingAI/Quark-Mod" target="_blank">Quark-Mod</a>
394
+ <p id="model-desc-mod">A multi-label moderation model covering <b>9 categories</b>: toxic, severe_toxic, obscene, threat, insult, identity_hate, cyberbullying, hate_speech, offensive.</p>
395
+ </div>
396
+ <div class="model-card">
397
+ <a href="https://huggingface.co/ThingAI/Quark-135m" target="_blank">Quark-135m (Base)</a>
398
+ <p>Base model.</p>
399
+ </div>
400
+ <div class="model-card">
401
+ <a href="https://huggingface.co/ThingAI/Quark-50m" target="_blank">Quark-50m</a>
402
+ <p>Lightweight 50M model.</p>
403
+ </div>
404
+ <p id="dataset-paragraph" style="margin-top:1rem; color:#c0b09a;">๐Ÿ“Š Dataset: <a href="https://huggingface.co/datasets/ThingAI/OmniBook" style="color:#d4af37;">ThingAI/OmniBook</a></p>
405
+ """)
406
+
407
+ # --- Focus & Resources ---
408
+ gr.HTML("""
409
+ <h2 id="focus-title" style="color:#d4af37; font-family:'Playfair Display',serif;">๐ŸŽฏ What We Focus On</h2>
410
+ <ul class="focus-list" id="focus-list">
411
+ <li>โšก Small, efficient architectures โ€” GQA, weight tying, deepโ€‘thin design</li>
412
+ <li>๐ŸŒ Bilingual training โ€” Italian + English from scratch</li>
413
+ <li>๐Ÿ”“ Openโ€‘source everything โ€” weights, code, datasets</li>
414
+ <li>๐Ÿ’ป Realโ€‘world deployment โ€” runs on consumer hardware</li>
415
+ </ul>
416
+ <h2 id="resources-title" style="color:#d4af37; font-family:'Playfair Display',serif; margin-top:2rem;">๐Ÿ“‚ Resources</h2>
417
+ <table class="resources-table" id="resources-table">
418
+ <tr><td>๐Ÿ“š <a href="https://huggingface.co/ThingAI/Quark-135m-Bilingual" target="_blank">Quark-135M-Bilingual</a></td></tr>
419
+ <tr><td>๐Ÿ›ก๏ธ <a href="https://huggingface.co/ThingsAI/Quark-Mod" target="_blank">Quark-Mod</a></td></tr>
420
+ <tr><td>๐Ÿ“ <a href="https://huggingface.co/ThingsAI" target="_blank">HuggingFace Community</a></td></tr>
421
+ <tr><td>๐Ÿ’ป <a href="https://github.com/overcastlab" target="_blank">GitHub</a></td></tr>
422
+ </table>
423
+ <p class="footer-text" id="footer-text">Made with โค๏ธ by ThingsAI ยท <a href="https://things-ai.org">Website</a> ยท <a href="https://github.com/overcastlab">GitHub</a></p>
424
+ """)
425
+
426
+ # --- Chat interface (exactly your working code, only relocated inside Blocks) ---
427
+ with gr.Row(equal_height=False):
428
+ with gr.Column(scale=5):
429
+ chatbot = gr.Chatbot(
430
+ label="๐Ÿ’ฌ Conversation",
431
+ height=520,
432
+ elem_classes=["chatbot-wrap"]
433
+ )
434
+ prompt_input = gr.Textbox(
435
+ label="Your Message",
436
+ placeholder="Ask anything... (hallucination may occur โš ๏ธ)",
437
+ lines=3,
438
+ elem_classes=["input-wrap"]
439
+ )
440
+ with gr.Row():
441
+ run_btn = gr.Button("โšก Send", variant="primary", scale=3)
442
+ clear_btn = gr.Button("๐Ÿ—‘๏ธ Clear", variant="secondary", scale=1)
443
+
444
+ with gr.Column(scale=4):
445
+ thinking_out = gr.Textbox(
446
+ label="๐Ÿง  Thinking Process",
447
+ lines=10,
448
+ interactive=False,
449
+ elem_classes=["thinking-box"]
450
+ )
451
+ answer_out = gr.Textbox(
452
+ label="โœ… Final Answer",
453
+ lines=6,
454
+ interactive=False,
455
+ elem_classes=["answer-box"]
456
+ )
457
+ with gr.Accordion("โš™๏ธ Settings", open=False):
458
+ system_prompt_input = gr.Textbox(
459
+ label="๐Ÿ”ง System Prompt",
460
+ value=DEFAULT_SYSTEM_PROMPT,
461
+ lines=4,
462
+ elem_classes=["system-box"]
463
+ )
464
+ max_tokens = gr.Slider(64, 4096, value=4048, step=32, label="Max Tokens")
465
+ temperature = gr.Slider(0.0, 4, value=0.9, step=0.05, label="Temperature")
466
+ top_p = gr.Slider(0.1, 5.0, value=0.35, step=0.05, label="Top-p")
467
+ top_k = gr.Slider(1, 500, value=61, step=1, label="Top-k")
468
+ show_think = gr.Checkbox(value=True, label="Show Thinking Process")
469
+
470
+ # Examples
471
+ gr.Examples(
472
+ examples=[
473
+ ["What is artificial intelligence?"],
474
+ ["How does a large language model learn?"],
475
+ ["Explain the water cycle in simple terms."],
476
+ ["What is the meaning of life?"],
477
+ ["Write a short poem about the universe."],
478
+ ["What is Drugs?"]
479
+ ],
480
+ inputs=[prompt_input],
481
+ label="๐Ÿ’ก Example Questions"
482
+ )
483
+
484
+ # Wire events
485
+ inputs_list = [prompt_input, chatbot, system_prompt_input, max_tokens, temperature, top_p, top_k, show_think]
486
+ outputs_list = [prompt_input, chatbot, thinking_out, answer_out]
487
+
488
+ run_btn.click(chat_generate, inputs=inputs_list, outputs=outputs_list)
489
+ prompt_input.submit(chat_generate, inputs=inputs_list, outputs=outputs_list)
490
+ clear_btn.click(clear_fn, outputs=outputs_list)
491
+
492
+ # ------------------------------------------------------------------
493
+ # Language switch JavaScript โ€“ swaps all translatable text
494
+ # ------------------------------------------------------------------
495
+ gr.HTML("""
496
+ <script>
497
+ const content = """ + str(CONTENT) + """;
498
+ let currentLang = 'en';
499
+
500
+ function switchLanguage() {
501
+ currentLang = currentLang === 'en' ? 'it' : 'en';
502
+ const t = content[currentLang];
503
+
504
+ // Update header
505
+ document.getElementById('main-title').innerHTML = t.title;
506
+ document.getElementById('main-intro').innerHTML = t.intro;
507
+ document.getElementById('models-title').innerHTML = t.models_title;
508
+ document.getElementById('focus-title').innerHTML = t.focus_title;
509
+ document.getElementById('resources-title').innerHTML = t.resources_title;
510
+
511
+ // Model descriptions
512
+ document.getElementById('model-desc-135').innerHTML = t.model_q135;
513
+ document.getElementById('model-desc-270').innerHTML = t.model_q270;
514
+ document.getElementById('model-desc-mod').innerHTML = t.model_qmod;
515
+
516
+ // Dataset paragraph
517
+ document.getElementById('dataset-paragraph').innerHTML = t.dataset_link;
518
+
519
+ // Focus list
520
+ const focusList = document.getElementById('focus-list');
521
+ focusList.innerHTML = t.focus_items.map(item => '<li>' + item + '</li>').join('');
522
+
523
+ // Resources table (rebuild rows)
524
+ const resTable = document.getElementById('resources-table');
525
+ resTable.innerHTML = t.resources.map(r => `<tr><td>${r[0].replace(/๐Ÿ“š|๐Ÿ›ก๏ธ|๐Ÿ“|๐Ÿ’ป/g, '')} <a href="${r[1]}" target="_blank">${r[1].split('/').pop()}</a></td></tr>`).join('');
526
+
527
+ // Footer
528
+ document.getElementById('footer-text').innerHTML = t.footer;
529
+
530
+ // Toggle button text
531
+ const btn = document.querySelector('.lang-toggle');
532
+ btn.innerHTML = currentLang === 'en' ? '๐Ÿ‡ฎ๐Ÿ‡น Italiano' : '๐Ÿ‡ฌ๐Ÿ‡ง English';
533
+ }
534
+ </script>
535
+ """)
536
+
537
+ # ----------------------------------------------------------------------
538
+ # Launch
539
+ # ----------------------------------------------------------------------
540
+ if __name__ == "__main__":
541
+ demo.launch(
542
+ server_name="0.0.0.0",
543
+ server_port=7860,
544
+ show_error=True,
545
+ )