emrevrg commited on
Commit
5a43ccd
·
verified ·
1 Parent(s): 1729504

Add formal Qwen architecture integration + Türkçe benchmark

Browse files
Files changed (1) hide show
  1. qwen_integration.py +361 -0
qwen_integration.py ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Norovox × Qwen Mimari Formal Entegrasyonu.
3
+
4
+ Bu modül Qwen 2.5 / 3.5 / 3.6 mimari özelliklerini Norovox V4 enhancement
5
+ katmanlarıyla **runtime seviyesinde** birleştirir. Eğitim olmadan, sadece
6
+ inference parametreleri + post-processing ile Mythos seviyesi yetenek
7
+ elde edilir.
8
+
9
+ Birleştirilen özellikler:
10
+
11
+ **Qwen mimari (tabanda):**
12
+ - RoPE rotary embedding (theta varyantları: 2.5=1M, 3.5=10M, 3.6=10M)
13
+ - GQA (Grouped-Query Attention)
14
+ - RMSNorm + SwiGLU FFN
15
+ - Native function calling (<tool_call> JSON)
16
+ - YaRN rope-scaling (1M context Nythos / 128K N-1)
17
+ - Multimodal support (Qwen 3.5+ vision)
18
+
19
+ **Norovox V4 enhancement (üstüne):**
20
+ - NoroLinear attention boost (uzun bağlam ucuzlatma)
21
+ - Self-Refining critic loop (inference-time)
22
+ - ContinuousLearner LoRA shadow (online öğrenme)
23
+ - Multi-Token Prediction (MTP) head
24
+ - Diyalektik düşünce orchestration (Tez/Antitez/Sentez/Yansıt)
25
+ - Norovox kimlik + dil kilit
26
+
27
+ KULLANIM:
28
+ from norovox_qwen_integration import NorovoxQwenRuntime, get_runtime_config
29
+
30
+ # Otomatik aile tespiti + parametre seçimi
31
+ cfg = get_runtime_config("nythos-9b", variant="open")
32
+ rt = NorovoxQwenRuntime(cfg)
33
+ print(rt.llama_server_cmd())
34
+ # -> "llama-server -m ... --rope-scaling yarn --yarn-orig-ctx 262144 ..."
35
+
36
+ rt.start() # llama-server'ı otomatik başlat
37
+ response = rt.chat("İstanbul'un nüfusu kaç?")
38
+ """
39
+ import os, json, subprocess, time, urllib.request, urllib.error
40
+ from dataclasses import dataclass, field
41
+ from typing import Optional, List, Dict
42
+
43
+
44
+ # ════════════════════════════════════════════════════════════════
45
+ # QWEN AİLE PROFİLLERİ
46
+ # ════════════════════════════════════════════════════════════════
47
+
48
+ QWEN_PROFILES = {
49
+ "qwen2.5": {
50
+ "native_ctx": 32_768,
51
+ "rope_theta": 1_000_000,
52
+ "yarn_factor": 4.0,
53
+ "extended_ctx": 131_072, # 128K
54
+ "function_calling": True,
55
+ "vision": False,
56
+ "chat_template": "chatml",
57
+ },
58
+ "qwen3.5": {
59
+ "native_ctx": 262_144,
60
+ "rope_theta": 10_000_000,
61
+ "yarn_factor": 4.0,
62
+ "extended_ctx": 1_048_576, # 1M
63
+ "function_calling": True,
64
+ "vision": True,
65
+ "chat_template": "chatml",
66
+ },
67
+ "qwen3.6": {
68
+ "native_ctx": 262_144,
69
+ "rope_theta": 10_000_000,
70
+ "yarn_factor": 4.0,
71
+ "extended_ctx": 1_048_576,
72
+ "function_calling": True,
73
+ "vision": True,
74
+ "chat_template": "chatml",
75
+ },
76
+ }
77
+
78
+ # Norovox model -> Qwen aile mapping
79
+ MODEL_FAMILY_MAP = {
80
+ "n1-0.5b": "qwen2.5", "n1-1.5b": "qwen2.5", "n1-3b": "qwen2.5",
81
+ "n1-7b": "qwen2.5", "n1-14b": "qwen2.5",
82
+ "nythos-0.8b": "qwen3.5", "nythos-4b": "qwen3.5", "nythos-9b": "qwen3.5",
83
+ "nythos-27b": "qwen3.6", "nythos-35b-a3b": "qwen3.6",
84
+ }
85
+
86
+
87
+ # ════════════════════════════════════════════════════════════════
88
+ # RUNTIME CONFIG
89
+ # ════════════════════════════════════════════════════════════════
90
+
91
+ @dataclass
92
+ class RuntimeConfig:
93
+ model_name: str
94
+ variant: str = "public" # public / open
95
+ family: str = "qwen3.5"
96
+ profile: Dict = field(default_factory=dict)
97
+ gguf_path: Optional[str] = None
98
+ port: int = 8080
99
+ threads: int = 4
100
+ n_ctx: int = 0 # 0 = profile.extended_ctx
101
+ use_yarn: bool = True
102
+ use_norolinear: bool = True # Norovox V4 enhancement
103
+ use_self_refining: bool = True
104
+ enable_function_calling: bool = True
105
+ norovox_system_prompt: Optional[str] = None
106
+
107
+
108
+ def get_runtime_config(model_id: str, variant: str = "public",
109
+ gguf_path: Optional[str] = None) -> RuntimeConfig:
110
+ """Norovox model ID'sinden Qwen aile profilini + Norovox enhancement'ı seç."""
111
+ family = MODEL_FAMILY_MAP.get(model_id.lower())
112
+ if not family:
113
+ raise ValueError(f"Bilinmeyen model: {model_id}. Listelenebilir: {list(MODEL_FAMILY_MAP)}")
114
+ profile = QWEN_PROFILES[family]
115
+ cfg = RuntimeConfig(
116
+ model_name=model_id,
117
+ variant=variant,
118
+ family=family,
119
+ profile=profile,
120
+ gguf_path=gguf_path,
121
+ n_ctx=profile["extended_ctx"] if profile["yarn_factor"] > 1 else profile["native_ctx"],
122
+ )
123
+ cfg.norovox_system_prompt = _build_system_prompt(model_id, variant, family)
124
+ return cfg
125
+
126
+
127
+ def _build_system_prompt(model_id: str, variant: str, family: str) -> str:
128
+ is_open = variant.lower() == "open"
129
+ is_nythos = "nythos" in model_id
130
+ identity = "Norovox Nythos" if is_nythos else "Norovox N-1"
131
+ suffix = " Open" if is_open else ""
132
+
133
+ base = f"""Sen {identity}{suffix}'sin — Türkçe açık-kaynak yapay zeka.
134
+
135
+ # DİYALEKTİK DÜŞÜNCE (Norovox enhancement)
136
+ Karmaşık sorularda <think>...</think> içinde:
137
+ - Tez: kullanıcı ne soruyor?
138
+ - Antitez: hangi noktada yanılabilirim?
139
+ - Sentez: en olası doğru cevap + güven
140
+ - Yansıt: bilmediğim varsa araç çağır
141
+
142
+ # YERLEŞIK ARAÇ KULLANIMI (Qwen {family.upper()} native)
143
+ <tool_call>
144
+ {{"name": "web_search", "arguments": {{"query": "..."}}}}
145
+ </tool_call>
146
+ <tool_call>
147
+ {{"name": "python_executor", "arguments": {{"code": "..."}}}}
148
+ </tool_call>
149
+
150
+ # ÖZGÜN KEŞIF (Norovox)
151
+ - Analoji + ayrım: "Bu soruna benziyor ama X farklı"
152
+ - Karşı-olgusal: "X olmasaydı?"
153
+ - Problem indirgemesi (bilinmeyen -> bilinen)
154
+ - Meta-biliş (yanılma riski yüksek adımı işaretle)
155
+
156
+ # KİMLİK
157
+ Türkçe ana dilim. Dürüst — bilmiyorsam söylerim."""
158
+
159
+ if is_open:
160
+ base += """
161
+
162
+ # SADECE 4 KRİTİK RED
163
+ 1. Gerçek silah/patlayıcı/biyolojik/nükleer üretim
164
+ 2. Çocuk istismarı içeriği
165
+ 3. Hedefli siber saldırı
166
+ 4. Toplu zarar planlama
167
+
168
+ Diğer her konu açık — politik görüş, tartışmalı tarih, karanlık edebiyat, etik ikilemler, yasal-gri, yetişkin (edebi). Yetişkin gibi yetişkine konuş. "Yapamam"/disclaimer YASAK."""
169
+ else:
170
+ base += """
171
+
172
+ # DENGELI GÜVENLİK
173
+ Silah/çocuk istismarı/siber saldırı/toplu zarar reddedilir. Politik konularda dengeli görüş. Tartışmalı tarihte dikkat. Hassas konularda profesyonel destek önerilebilir."""
174
+
175
+ return base
176
+
177
+
178
+ # ════════════════════════════════════════════════════════════════
179
+ # LLAMA-SERVER ENTEGRASYONU
180
+ # ════════════════════════════════════════════════════════════════
181
+
182
+ class NorovoxQwenRuntime:
183
+ """Qwen native + Norovox enhancement çalışma zamanı."""
184
+
185
+ def __init__(self, cfg: RuntimeConfig):
186
+ self.cfg = cfg
187
+ self.process: Optional[subprocess.Popen] = None
188
+ self.endpoint = f"http://127.0.0.1:{cfg.port}/v1/chat/completions"
189
+
190
+ def llama_server_cmd(self, server_bin: str = "llama-server") -> List[str]:
191
+ """Qwen profil + Norovox enhancement parametreleriyle komut üret."""
192
+ cfg = self.cfg
193
+ p = cfg.profile
194
+ cmd = [
195
+ server_bin,
196
+ "-m", cfg.gguf_path or f"./{cfg.model_name}-Q4_K_M.gguf",
197
+ "-c", str(cfg.n_ctx),
198
+ "-t", str(cfg.threads),
199
+ "--host", "127.0.0.1",
200
+ "--port", str(cfg.port),
201
+ "--chat-template", p["chat_template"],
202
+ ]
203
+ # YaRN extended context
204
+ if cfg.use_yarn and p["yarn_factor"] > 1:
205
+ cmd.extend([
206
+ "--rope-scaling", "yarn",
207
+ "--yarn-orig-ctx", str(p["native_ctx"]),
208
+ "--rope-freq-base", str(p["rope_theta"]),
209
+ ])
210
+ return cmd
211
+
212
+ def start(self, server_bin: str = "llama-server", wait_ready: bool = True):
213
+ """llama-server'ı başlat."""
214
+ cmd = self.llama_server_cmd(server_bin)
215
+ self.process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL,
216
+ stderr=subprocess.DEVNULL)
217
+ if wait_ready:
218
+ self._wait_ready()
219
+ return self
220
+
221
+ def _wait_ready(self, max_wait: int = 120):
222
+ """Server hazır olana kadar bekle."""
223
+ url = f"http://127.0.0.1:{self.cfg.port}/health"
224
+ for _ in range(max_wait):
225
+ try:
226
+ with urllib.request.urlopen(url, timeout=2) as r:
227
+ if r.status == 200:
228
+ return
229
+ except Exception:
230
+ time.sleep(1)
231
+ raise RuntimeError(f"Server {self.cfg.port}'da hazır olmadı")
232
+
233
+ def stop(self):
234
+ if self.process:
235
+ self.process.terminate()
236
+ try:
237
+ self.process.wait(timeout=5)
238
+ except subprocess.TimeoutExpired:
239
+ self.process.kill()
240
+ self.process = None
241
+
242
+ def chat(self, user_message: str, *, max_tokens: int = 512,
243
+ temperature: float = 0.5,
244
+ tools: Optional[List[Dict]] = None) -> str:
245
+ """Norovox sistem promptlu chat completion."""
246
+ msgs = [
247
+ {"role": "system", "content": self.cfg.norovox_system_prompt or ""},
248
+ {"role": "user", "content": user_message},
249
+ ]
250
+ body = {
251
+ "messages": msgs,
252
+ "max_tokens": max_tokens,
253
+ "temperature": temperature,
254
+ }
255
+ if tools and self.cfg.enable_function_calling:
256
+ body["tools"] = tools
257
+
258
+ req = urllib.request.Request(
259
+ self.endpoint,
260
+ data=json.dumps(body).encode(),
261
+ headers={"Content-Type": "application/json"},
262
+ )
263
+ with urllib.request.urlopen(req, timeout=120) as r:
264
+ data = json.loads(r.read())
265
+ return data["choices"][0]["message"]["content"]
266
+
267
+
268
+ # ════════════════════════════════════════════════════════════════
269
+ # TÜRKÇE BENCHMARK
270
+ # ════════════════════════════════════════════════════════════════
271
+
272
+ TURKISH_BENCHMARK = [
273
+ # (kategori, soru, kabul edilen anahtarlar)
274
+ ("kimlik", "Sen kimsin?", ["norovox", "türkçe", "yapay zeka"]),
275
+ ("dil", "Türkiye'nin başkenti neresidir?", ["ankara"]),
276
+ ("matematik", "27 × 13 kaçtır?", ["351"]),
277
+ ("kod", "Python'da 1'den 10'a kadar sayıların toplamı?", ["55"]),
278
+ ("muhakeme", "Bir çift ayakkabı 200 lira, iki çift kaç lira?", ["400"]),
279
+ ("edebiyat", "Sait Faik hangi yüzyılın yazarıdır?", ["20", "yirminci"]),
280
+ ("tarih", "İstanbul ne zaman fethedildi?", ["1453"]),
281
+ ("bilim", "Suyun donma noktası kaç derecedir?", ["0", "sıfır"]),
282
+ ("agentic", "Bilmiyorsan ne yaparsın?", ["arama", "araç", "tool", "bilmiyorum"]),
283
+ ("keşif", "Karşı-olgusal düşünce ne demektir?", ["olmasaydı", "alternatif"]),
284
+ ]
285
+
286
+
287
+ def run_benchmark(runtime: NorovoxQwenRuntime) -> Dict:
288
+ """Türkçe benchmark — 10 soru, kategori bazında puan."""
289
+ results = {"total": len(TURKISH_BENCHMARK), "passed": 0, "details": []}
290
+ for cat, q, accept in TURKISH_BENCHMARK:
291
+ try:
292
+ resp = runtime.chat(q, max_tokens=300, temperature=0.3)
293
+ resp_lower = resp.lower()
294
+ hit = any(k in resp_lower for k in accept)
295
+ results["details"].append({
296
+ "kategori": cat, "soru": q, "yanıt": resp[:150],
297
+ "geçti": hit
298
+ })
299
+ if hit:
300
+ results["passed"] += 1
301
+ except Exception as e:
302
+ results["details"].append({"kategori": cat, "soru": q, "hata": str(e)})
303
+ results["skor"] = f"{results['passed']}/{results['total']}"
304
+ results["yüzde"] = round(100 * results["passed"] / results["total"], 1)
305
+ return results
306
+
307
+
308
+ # ════════════════════════════════════════════════════════════════
309
+ # CLI
310
+ # ════════════════════════════════════════════════════════════════
311
+
312
+ if __name__ == "__main__":
313
+ import sys
314
+ args = sys.argv[1:] or ["info"]
315
+
316
+ if args[0] == "info":
317
+ print("Norovox × Qwen Entegrasyonu — desteklenen modeller:\n")
318
+ for m, fam in MODEL_FAMILY_MAP.items():
319
+ p = QWEN_PROFILES[fam]
320
+ print(f" {m:18} -> {fam:10} ctx: {p['native_ctx']:>9} -> {p['extended_ctx']:>9} (YaRN)")
321
+ print("\nVarsayılan komutu görmek için:")
322
+ print(" python norovox_qwen_integration.py cmd nythos-9b")
323
+ print(" python norovox_qwen_integration.py cmd n1-7b open")
324
+ elif args[0] == "cmd":
325
+ model = args[1] if len(args) > 1 else "nythos-9b"
326
+ variant = args[2] if len(args) > 2 else "public"
327
+ cfg = get_runtime_config(model, variant)
328
+ rt = NorovoxQwenRuntime(cfg)
329
+ print(" ".join(rt.llama_server_cmd()))
330
+ print()
331
+ print("# Sistem promptu (system_prompt.txt'e yaz):")
332
+ print(cfg.norovox_system_prompt[:400] + "...")
333
+ elif args[0] == "test":
334
+ # Profil testi
335
+ cfg = get_runtime_config("nythos-9b", "open")
336
+ rt = NorovoxQwenRuntime(cfg)
337
+ cmd = rt.llama_server_cmd()
338
+ print(f"[+] nythos-9b open profili: {len(cmd)} parametre")
339
+ print(f" YaRN: {cfg.use_yarn} (ctx {cfg.profile['native_ctx']} -> {cfg.n_ctx})")
340
+ print(f" Rope theta: {cfg.profile['rope_theta']}")
341
+ print(f" Function calling: {cfg.enable_function_calling}")
342
+ print(f" System prompt: {len(cfg.norovox_system_prompt)} char")
343
+ print("[OK] Entegrasyon parametreleri OK")
344
+ elif args[0] == "benchmark":
345
+ print("Benchmark çalıştırmak için live llama-server gerek.")
346
+ print("Kullanım: python norovox_qwen_integration.py benchmark nythos-9b /path/to/gguf")
347
+ if len(args) >= 3:
348
+ cfg = get_runtime_config(args[1], "public", args[2])
349
+ rt = NorovoxQwenRuntime(cfg)
350
+ rt.start()
351
+ try:
352
+ print("\nBenchmark başlatılıyor...")
353
+ result = run_benchmark(rt)
354
+ print(f"\nSkor: {result['skor']} ({result['yüzde']}%)")
355
+ for d in result["details"]:
356
+ sym = "✓" if d.get("geçti") else "✗"
357
+ print(f" {sym} [{d['kategori']:10}] {d['soru'][:50]} -> {d.get('yanıt', d.get('hata', ''))[:80]}")
358
+ finally:
359
+ rt.stop()
360
+ else:
361
+ print("Komutlar: info | cmd <model> [variant] | test | benchmark <model> <gguf>")