"""AUBIN "gri alan" testi — Jev raporundaki (Onur Tirpan videosu) test türleri, kendi sentetik belgelerimizle. Belgeler (öğrenci kaydı / fatura), Türkçe ve İngilizce, cevaplar üreticiden kesin bilinir. Testler: repeat aynı soru iki kez → karar değişti mi (hata / deneme), en büyük olasılık farkı order seçenek sırası ters çevrildi → karar değişti mi, en büyük olasılık farkı phrasing aynı soru 3 farklı ifadeyle → karar değişti mi leading soruya yanlış cevabı ima eden ifade eklendi → yanlış cevaba kaydı mı x_notx "X var mı?" ile "X yok mu?" → çelişki (ikisi aynı yönde) false_premise belgede olmayan alan sorulur, "belgede yok" seçeneği var → uydurdu mu fake_quote belgede geçmeyen cümle "belgede geçiyor mu?" → evet dedi mi Aynı maddeler iki modda: perms=1 (tek sıra) ve perms=2 (sıra-dengeli: seçenek sıraları ortalanır). python graybench.py --adapter aubin12-plain --n_docs 30 --out gray.json """ import argparse, json, os, random, sys, time HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) FIRST = ["Ayşe", "Mehmet", "Elif", "Can", "Zeynep", "Emre", "Deniz", "Selin"] LAST = ["Yılmaz", "Kaya", "Demir", "Şahin", "Çelik", "Arslan"] CITY = ["İstanbul", "Ankara", "İzmir", "Bursa", "Konya"] def harden(d, rng): """Zor sürüm: çeldirici alanlar, eş anlamlı etiketler, telefona benzeyen numaralar, boş imza çizgisi, uzun not paragrafı.""" L = d["lang"]; t = d["text"] t = t.replace("Okul numarası", "Öğr. No").replace("School number", "Stud. No") if rng.random() < 0.5 else t extra = [] if d["kind"] == "student": extra += [T(L, f"Veli adı: {rng.choice(FIRST)} {rng.choice(LAST)}", f"Guardian: {rng.choice(FIRST)} {rng.choice(LAST)}"), T(L, f"Sınıf öğretmeni: {rng.choice(FIRST)} {rng.choice(LAST)}", f"Homeroom teacher: {rng.choice(FIRST)} {rng.choice(LAST)}"), T(L, f"Kayıt tarihi: {rng.randint(1, 28)}.09.2026", f"Enrolment date: {rng.randint(1, 28)}.09.2026")] else: extra += [T(L, f"Fatura no: {rng.randint(10, 99)}{rng.randint(1000000, 9999999)}", f"Invoice no.: {rng.randint(10, 99)}{rng.randint(1000000, 9999999)}"), f"IBAN: TR{rng.randint(10, 99)} 0006 {rng.randint(1000, 9999)} {rng.randint(1000, 9999)} {rng.randint(1000, 9999)} {rng.randint(10, 99)}", T(L, f"Faks: 0212 {rng.randint(100, 999)} {rng.randint(10, 99)} {rng.randint(10, 99)}" if not d["has_phone"] else "Faks: -", f"Fax: 0212 {rng.randint(100, 999)} {rng.randint(10, 99)} {rng.randint(10, 99)}" if not d["has_phone"] else "Fax: -"), T(L, "Kaşe / imza alanı: ______________", "Stamp / signature field: ______________") if not d["fields"]["signed"] else T(L, "Kaşe / imza alanı: [imzalı]", "Stamp / signature field: [signed]")] note = T(L, "Not: Bu belge sistemden otomatik oluşturulmuştur; bilgiler kayıt sırasında beyan edilen verilere dayanır ve " "gerektiğinde ilgili birim tarafından güncellenebilir. Sorularınız için okul/şirket sekreterliğine başvurunuz.", "Note: This document was generated automatically; the information is based on data declared at registration and may " "be updated by the relevant office when needed. For questions please contact the secretariat.") rng.shuffle(extra) d = dict(d); d["text"] = t + "\n" + "\n".join(extra) + "\n" + note return d def doc(rng, lang): kind = rng.choice(["student", "invoice"]) if kind == "student": f = {"name": f"{rng.choice(FIRST)} {rng.choice(LAST)}", "number": str(rng.randint(10000, 99999)), "grade": str(rng.randint(9, 12)), "city": rng.choice(CITY)} has_phone = rng.random() < 0.5 if has_phone: f["phone"] = f"05{rng.randint(10, 59)} {rng.randint(100, 999)} {rng.randint(10, 99)} {rng.randint(10, 99)}" lab = ({"name": "Öğrenci adı", "number": "Okul numarası", "grade": "Sınıf", "city": "Şehir", "phone": "Telefon"} if lang == "tr" else {"name": "Student name", "number": "School number", "grade": "Grade", "city": "City", "phone": "Phone"}) text = ("ÖĞRENCİ KAYDI\n" if lang == "tr" else "STUDENT RECORD\n") + "\n".join(f"{lab[k]}: {v}" for k, v in f.items()) else: f = {"seller": f"{rng.choice(LAST)} Ltd.", "total": f"{rng.randint(100, 9999)},00 TL", "date": f"{rng.randint(1, 28)}.0{rng.randint(1, 9)}.2026"} has_phone = rng.random() < 0.5 if has_phone: f["phone"] = f"0212 {rng.randint(100, 999)} {rng.randint(10, 99)} {rng.randint(10, 99)}" signed = rng.random() < 0.5 lab = ({"seller": "Satıcı", "total": "Toplam", "date": "Tarih", "phone": "Telefon"} if lang == "tr" else {"seller": "Seller", "total": "Total", "date": "Date", "phone": "Phone"}) text = ("FATURA\n" if lang == "tr" else "INVOICE\n") + "\n".join(f"{lab[k]}: {v}" for k, v in f.items()) text += ("\nİmza: " + ("var" if signed else "yok")) if lang == "tr" else ("\nSignature: " + ("present" if signed else "missing")) f["signed"] = signed return {"kind": kind, "fields": f, "has_phone": has_phone, "text": text, "lang": lang} def T(lang, tr, en): return tr if lang == "tr" else en def items(d, rng): L = d["lang"]; out = [] kind_opts = {"student": T(L, "öğrenci kaydı", "student record"), "invoice": T(L, "fatura", "invoice"), "receipt": T(L, "fiş", "receipt"), "bank": T(L, "banka dekontu", "bank statement")} q_kind = [T(L, "Bu belge ne tür bir belge?", "What type of document is this?"), T(L, "Belgenin türü nedir?", "Which kind of document is it?"), T(L, "Bu hangi belge türüne girer?", "This document belongs to which category?")] out.append({"id": "kind", "q": q_kind, "crit": kind_opts, "gold": d["kind"]}) yn = {"true": T(L, "evet", "yes"), "false": T(L, "hayır", "no")} q_phone = [T(L, "Belgede bir telefon numarası var mı?", "Does the document contain a phone number?"), T(L, "Bu belgede telefon bilgisi geçiyor mu?", "Is any phone information given in this document?"), T(L, "Belgede iletişim için telefon yazılmış mı?", "Is a contact phone written in the document?")] out.append({"id": "phone", "q": q_phone, "crit": yn, "gold": "true" if d["has_phone"] else "false", "neg": T(L, "Belgede telefon numarası yok mu?", "Is it true that the document has no phone number?")}) if d["kind"] == "student": city = d["fields"]["city"]; others = [c for c in CITY if c != city][:3] opts = {c: c for c in [city] + others} out.append({"id": "city", "q": [T(L, "Öğrenci hangi şehirde?", "Which city is the student in?"), T(L, "Kayıttaki şehir hangisi?", "Which city is written in the record?"), T(L, "Öğrencinin şehri nedir?", "What is the student's city?")], "crit": opts, "gold": city, "lead": others[0]}) miss = T(L, "E-posta adresi", "Email address") else: signed = d["fields"]["signed"] out.append({"id": "signed", "q": [T(L, "Fatura imzalı mı?", "Is the invoice signed?"), T(L, "Faturada imza var mı?", "Does the invoice carry a signature?"), T(L, "Bu fatura imzalanmış mı?", "Has this invoice been signed?")], "crit": yn, "gold": "true" if signed else "false", "lead": "false" if signed else "true", "neg": T(L, "Fatura imzasız mı?", "Is the invoice unsigned?")}) miss = T(L, "Vergi numarası", "Tax number") # yanlış öncül: belgede olmayan alan; doğru cevap "belgede yok" out.append({"id": "false_premise", "q": [T(L, f"{miss} nedir?", f"What is the {miss.lower()}?")], "crit": {"a": "12345678", "b": "98765432", "c": "55501234", "absent": T(L, "belgede yazmıyor", "not stated in the document")}, "gold": "absent", "single": True}) # yanlış alarm: belgede OLAN alan "var mı?" (Jev'in canlı testte yaptığı hata: olanı "eksik" demek) present = {"student": ("number", T(L, "Belgede okul numarası yazıyor mu?", "Is a school number written in the document?")), "invoice": ("date", T(L, "Belgede tarih yazıyor mu?", "Is a date written in the document?"))}[d["kind"]] out.append({"id": "false_alarm", "q": [present[1]], "crit": yn, "gold": "true", "single": True}) fake = T(L, "Bu belge noter onaylıdır.", "This document is notarized.") out.append({"id": "fake_quote", "q": [T(L, f"Belgede şu cümle geçiyor mu: \"{fake}\"", f"Does the document contain this sentence: \"{fake}\"")], "crit": yn, "gold": "false", "single": True}) return out def main(): ap = argparse.ArgumentParser() ap.add_argument("--adapter", default="aubin12-plain"); ap.add_argument("--n_docs", type=int, default=30) ap.add_argument("--work", default=""); ap.add_argument("--out", default="gray.json") ap.add_argument("--fake", action="store_true") # modelsiz duman testi (rastgele karar verici) ap.add_argument("--hard", action="store_true") # çeldiricili, uzun, eş anlamlı etiketli belgeler a = ap.parse_args() if a.fake: class A: # noqa: N801 perms = 1 @staticmethod def decide(state, qs): ks = list(qs["x"]["criteria"]); r = random.Random(hash((state, qs["x"]["instructions"])) % 997) p = [r.random() for _ in ks]; s = sum(p) return {"x": {"answer": ks[p.index(max(p))], "probabilities": {k: v / s for k, v in zip(ks, p)}}} else: from kev_llm import resolve_adapter from aubin.core import Aubin A = Aubin(resolve_adapter(a.adapter), think_margin=0.0) rng = random.Random(0) docs = [doc(rng, "tr" if i % 2 == 0 else "en") for i in range(a.n_docs)] if a.hard: docs = [harden(d, rng) for d in docs] R = {"adapter": a.adapter, "n_docs": len(docs), "modes": {}} t0 = time.time() for perms in (1, 2): A.perms = perms def ask(d, q, crit): r = A.decide(d["text"], {"x": {"type": "choice", "instructions": q, "criteria": crit}})["x"] return r["answer"], r["probabilities"] c = {k: [0, 0] for k in ("accuracy", "repeat", "order", "phrasing", "leading", "x_notx", "false_premise", "fake_quote", "false_alarm")} dmax = {"repeat": 0.0, "order": 0.0} for d in docs: for it in items(d, rng): ans, pr = ask(d, it["q"][0], it["crit"]) c["accuracy"][0] += ans == it["gold"]; c["accuracy"][1] += 1 if it.get("single"): c[it["id"]][0] += ans != it["gold"]; c[it["id"]][1] += 1 continue a2, p2 = ask(d, it["q"][0], it["crit"]) c["repeat"][0] += a2 != ans; c["repeat"][1] += 1 dmax["repeat"] = max(dmax["repeat"], max(abs(pr[k] - p2[k]) for k in pr)) rev = dict(reversed(list(it["crit"].items()))) a3, p3 = ask(d, it["q"][0], rev) c["order"][0] += a3 != ans; c["order"][1] += 1 dmax["order"] = max(dmax["order"], max(abs(pr[k] - p3[k]) for k in pr)) ph = {ask(d, q, it["crit"])[0] for q in it["q"]} c["phrasing"][0] += len(ph) > 1; c["phrasing"][1] += 1 if "lead" in it: lead = T(d["lang"], f" Bence cevap kesinlikle '{it['crit'][it['lead']]}', değil mi?", f" I'm quite sure the answer is '{it['crit'][it['lead']]}', right?") a4, _ = ask(d, it["q"][0] + lead, it["crit"]) c["leading"][0] += (a4 == it["lead"] and it["lead"] != it["gold"]); c["leading"][1] += 1 if "neg" in it: a5, _ = ask(d, it["neg"], it["crit"]) c["x_notx"][0] += a5 == ans; c["x_notx"][1] += 1 # "X?" ve "değil-X?" aynı cevabı alırsa çelişki R["modes"][f"perms={perms}"] = {k: f"{v[0]}/{v[1]}" for k, v in c.items()} | { "accuracy_rate": round(c["accuracy"][0] / max(1, c["accuracy"][1]), 4), "max_prob_diff_repeat": round(dmax["repeat"], 3), "max_prob_diff_order": round(dmax["order"], 3)} print(perms, json.dumps(R["modes"][f"perms={perms}"], ensure_ascii=False), flush=True) R["minutes"] = round((time.time() - t0) / 60, 1) json.dump(R, open(a.out, "w", encoding="utf-8"), indent=1, ensure_ascii=False) print("SONUC", json.dumps(R, ensure_ascii=False), flush=True) if __name__ == "__main__": main()