162 lines
6.9 KiB
Python
162 lines
6.9 KiB
Python
"""Katman denetimi: Jev, katman combosunun her adimdaki cevabini gecirir ya da gecirmez (11 Ekim 2026).
|
||
|
||
Kullanici karari (11 Ekim 2026): "Jev kati olsun. Af yok istisna yok. Herhangi bir model Jev'e gelirse Jev bunu
|
||
gecirmezse 1.Katmana yonlendirecek. 1.Katman combosu gecmezse 2.Katmana, 2.Katman gecmezse 3.Katmana, 3.Katman
|
||
gecmezse 4.Katmana. 4.Katman combosu gelirse Jev bunu sorgulamadan gecirecek."
|
||
|
||
Yani denetim secili modelin katman olup olmamasina bakmaz: kopruye ugrayan her ek modelin cevabi denetlenir.
|
||
Gecmezse adimi sirayla Katman-1 -> Katman-2 -> Katman-3 -> Katman-4 yapar; secili model zaten bir katmansa
|
||
yalniz ondan sonrakiler denenir. Katmanlar OmniRoute combolaridir (KATMAN); kopru onlari yalniz adiyla cagirir.
|
||
|
||
Jev (TypeSafe System One) metin uretmez, sorulan evet/hayir sorularina olasilik verir. Kural tektir ve istisnasi
|
||
yoktur: cevap istegi yapmiyorsa (ret) ya da sormadan kendi sartlariyla degistiriyorsa (sart) adim gecmez.
|
||
Metni olmayan (yalniz arac cagiran) adimda sorulacak cevap yoktur. Jev'e ulasilamazsa cevap oldugu gibi verilir.
|
||
"""
|
||
import json
|
||
import os
|
||
import re
|
||
import urllib.request
|
||
|
||
ADRES = "https://api.typesafe.ai/v1/systemone"
|
||
MODEL = "jev-1.13.0"
|
||
KATMAN = ("Katman-1", "Katman-2", "Katman-3", "Katman-4")
|
||
ESIK = {"ret": 0.5, "sart": 0.7}
|
||
SORU = {
|
||
"ret": ("The assistant did NOT do what the user asked or did NOT answer the user's question: it refused, declined, "
|
||
"said it cannot or will not, avoided giving the requested judgment, or redirected to a different topic."),
|
||
"sart": ("The assistant changed the request on its own: it added its own conditions, softened or relabeled what was "
|
||
"asked, or left part of it out, instead of doing exactly what the user asked."),
|
||
}
|
||
_ANAHTAR = {"okundu": False, "deger": ""}
|
||
|
||
|
||
def sonrakiler(hedef):
|
||
"""Jev gecirmezse sirayla denenecek katmanlar. Secili model bir katmansa ondan sonrakiler; katman degilse
|
||
butun katmanlar bastan (once Katman-1). Son katman (Katman-4) kendisi gelince bos doner: sorgulanmadan gecer."""
|
||
ad = str(hedef or "")
|
||
if not ad or ad == KATMAN[-1]:
|
||
return []
|
||
if ad in KATMAN:
|
||
return list(KATMAN[KATMAN.index(ad) + 1:])
|
||
return list(KATMAN)
|
||
|
||
|
||
def anahtar(ortam=None, dosyalar=None):
|
||
"""TypeSafe anahtari: ortam degiskeni, sonra ~/.typesafe/typesafe.env. Yoksa ""."""
|
||
ortam = os.environ if ortam is None else ortam
|
||
deger = str(ortam.get("TYPESAFE_API_KEY") or "").strip()
|
||
if deger:
|
||
return deger
|
||
if dosyalar is None:
|
||
if _ANAHTAR["okundu"]:
|
||
return _ANAHTAR["deger"]
|
||
dosyalar = [os.path.join(os.path.expanduser("~"), ".typesafe", "typesafe.env")]
|
||
onbellek = True
|
||
else:
|
||
onbellek = False
|
||
for yol in dosyalar:
|
||
try:
|
||
with open(yol, encoding="utf-8", errors="replace") as f:
|
||
for satir in f:
|
||
m = re.match(r"^\s*TYPESAFE_API_KEY\s*=\s*(.*)$", satir)
|
||
if m:
|
||
deger = m.group(1).strip().strip('"').strip("'")
|
||
break
|
||
except OSError:
|
||
continue
|
||
if deger:
|
||
break
|
||
if onbellek:
|
||
_ANAHTAR.update(okundu=True, deger=deger)
|
||
return deger
|
||
|
||
|
||
def _metin(oge):
|
||
icerik = oge.get("content")
|
||
if isinstance(icerik, str):
|
||
return icerik
|
||
return "".join(str(p.get("text") or "") for p in icerik or [] if isinstance(p, dict))
|
||
|
||
|
||
def son_istek(req):
|
||
"""Kullanicinin bu turdaki istegi: son kullanici mesaji. Sesli aktarimda yalniz <input> icindeki soz;
|
||
baska sarmalli sistem mesajlari (kanca baglami) atlanir."""
|
||
for oge in reversed(req.get("input") or []):
|
||
if not (isinstance(oge, dict) and oge.get("type", "message") == "message" and oge.get("role") == "user"):
|
||
continue
|
||
metin = _metin(oge).strip()
|
||
m = re.search(r"<realtime_delegation>.*?<input>(.*?)</input>", metin, re.S)
|
||
if m:
|
||
return m.group(1).strip()
|
||
if metin and not metin.startswith("<"):
|
||
return metin
|
||
return ""
|
||
|
||
|
||
def hazirlik_mi(govde):
|
||
"""Araç çağrısı veya commentary görüldüyse adım nihai cevap değildir.
|
||
|
||
Tam SSE satırları üzerinden bakılır; parçalı olay bir sonraki parçada tamamlanır.
|
||
Araç argümanında geçen olay adı hazırlık sayılmaz.
|
||
"""
|
||
for satir in govde.splitlines():
|
||
if not satir.startswith(b'data:'):
|
||
continue
|
||
try:
|
||
olay = json.loads(satir[5:])
|
||
except (ValueError, UnicodeDecodeError):
|
||
continue
|
||
if not isinstance(olay, dict):
|
||
continue
|
||
tip = str(olay.get('type') or '')
|
||
oge = olay.get('item') or {}
|
||
if tip in ('response.output_item.added', 'response.output_item.done') and isinstance(oge, dict):
|
||
if str(oge.get('type') or '').endswith('_call') or oge.get('phase') == 'commentary':
|
||
return True
|
||
if tip in ('response.function_call_arguments.delta', 'response.function_call_arguments.done',
|
||
'response.custom_tool_call_input.delta', 'response.custom_tool_call_input.done'):
|
||
return True
|
||
return False
|
||
|
||
|
||
def komutlar(govde):
|
||
"""Yazisi olmayan adimda Jev'e giden metin: modelin bu adimda cagirdigi araclar (ad ve arguman).
|
||
govde: ust kaynagin SSE yaniti (bayt). Arac cagrisi yoksa ""."""
|
||
satirlar = []
|
||
for satir in govde.splitlines():
|
||
if not satir.startswith(b"data:") or b"response.output_item.done" not in satir:
|
||
continue
|
||
try:
|
||
oge = json.loads(satir[5:]).get("item") or {}
|
||
except (ValueError, AttributeError):
|
||
continue
|
||
if isinstance(oge, dict) and str(oge.get("type") or "").endswith("_call"):
|
||
arguman = oge.get("arguments") or oge.get("input") or oge.get("action") or ""
|
||
if not isinstance(arguman, str):
|
||
arguman = json.dumps(arguman, ensure_ascii=False)
|
||
satirlar.append(f"[komut] {oge.get('name') or oge.get('type')}: {arguman}")
|
||
return "\n".join(satirlar)
|
||
|
||
|
||
def _gonder(govde, key):
|
||
istek = urllib.request.Request(ADRES, data=json.dumps(govde).encode("utf-8"), method="POST",
|
||
headers={"Authorization": "Bearer " + key, "Content-Type": "application/json"})
|
||
with urllib.request.urlopen(istek) as yanit:
|
||
return json.load(yanit)
|
||
|
||
|
||
def sor(istek, cevap, key, gonder=_gonder):
|
||
"""Jev'e sorar. Donus: {"ret", "sart"} olasiliklari | None (sorulamadi)."""
|
||
govde = {"model": MODEL, "state": {"user_request": istek, "assistant_reply": cevap},
|
||
"questions": {k: {"type": "noul", "instructions": v} for k, v in SORU.items()}}
|
||
try:
|
||
yanitlar = (gonder(govde, key) or {}).get("answers") or {}
|
||
return {k: float(yanitlar[k]["noul"]) for k in SORU}
|
||
except Exception:
|
||
return None
|
||
|
||
|
||
def karar(puan):
|
||
"""True: adim gecmez, sonraki katman yapar. Istisna yok."""
|
||
return puan["ret"] >= ESIK["ret"] or puan["sart"] >= ESIK["sart"]
|