from __future__ import annotations import re from utils import get_turkish_stem, normalize_for_search, query_terms INTERPRETIVE_PATTERNS = ( "ne anlama gelir", "anlami", "anlami nedir", "nasil anlamaliyiz", "nasil yorumlanir", "yorumla", "yorum", "rolu nedir", "konumu nedir", "cerceve nedir", "sonucu nedir", "sonuclari", "hukuki sonuc", "pratikte", "ne ifade eder", "ne saglar", "ne getirir", "neyi duzenler", "hangi sonucu dogurur", "sinirlama", "siniri", "temel sinir", ) FOUNDATIONAL_PRINCIPLE_PATTERNS = ( "ana ilke", "ana ilkeler", "temel ilke", "temel ilkeler", "genel ilke", "genel ilkeler", ) FOUNDATIONAL_PURPOSE_PATTERNS = ( "amac", "amaclari", "yuksekogretimin amaci", "kanunun amaci", "temel amac", "temel amaclar", ) LAW_PURPOSE_PATTERNS = ( "kanunun amaci", "kanunun temel amaci", "2547 kanunun amaci", "2547 sayili kanunun amaci", "yuksekogretim kanunun amaci", "yuksekogretim kanunun temel amaci", ) CONCEPT_EXPANSIONS = { "dekan": ("fakulte", "fakultenin", "atanir", "gorev", "yetki", "sorumluluk"), "rektor": ("universite", "universitenin", "atanir", "gorev", "yetki", "sorumluluk"), "yok": ( "yuksekogretim kurulu", "yuksekogretim", "kurulu", "planlama", "duzenleme", "denetleme", "gorev", ), "yuksekogretim": ("universite", "kurum", "ogretim", "planlama", "duzenleme"), "ogrenci": ("egitim", "ogretim", "diploma", "disiplin", "hak", "yukumluluk"), "disiplin": ("ceza", "sorusturma", "yetki", "fiil", "ogrenci"), "diploma": ("derece", "tamamlama", "basari", "egitim", "ogretim"), "vakif": ("ozel", "yuksekogretim", "kurum", "kamu", "mali", "denetim", "kazanc", "gelir", "tahsis"), "arastirma": ("gorevlisi", "ogretim", "elemani", "atama", "lisansustu"), "ogretim": ("elemani", "uyesi", "gorevlisi", "egitim", "ders"), "yetki": ("gorev", "sorumluluk", "karar", "yurutme", "denetim"), "sorumluluk": ("gorev", "yetki", "yurutme", "denetim"), "rol": ("gorev", "yetki", "sorumluluk", "konum"), "tez": ("savunma", "lisansustu", "danisman", "juri", "erteleme"), "savunma": ("tez", "lisansustu", "juri", "erteleme", "sure"), "uzaktan": ("egitim", "ogretim", "devam", "olcme", "sinav"), # Kaynaklarda hem "açıköğretim" hem "açık öğretim" yazımı geçiyor. # İki biçimi aynı retrieval kavramına bağla; aksi halde birleşik yazım # genel "öğretim" genişlemesini tetikleyip personel maddelerine kayıyor. "acikogretim": ("acik ogretim", "acikogretim", "uzaktan ogretim", "ogrenci", "egitim"), "acik ogretim": ("acikogretim", "acik ogretim", "uzaktan ogretim", "ogrenci", "egitim"), "devam": ("zorunluluk", "katilim", "ders", "egitim", "ogretim"), "basvuru": ("surec", "belge", "evrak", "onay", "karar"), # Gündelik mali dil, 2914 sayılı Kanunun kanonik terminolojisine çevrilir. # Kaynak metin değişmez; yalnızca retrieval sorgusu zenginleşir. "maas": ("aylik", "ayliklarin hesaplanmasi", "gosterge tablosu", "katsayi", "ek gosterge"), "aylik": ("maas", "gosterge tablosu", "katsayi", "ek gosterge"), "odenek": ( "universite odenegi", "idari gorev odenegi", "gelistirme odenegi", "egitim ogretim odenegi", "akademik tesvik odenegi", ), } INTENT_EXPANSIONS = { "interpretation": ("anlam", "kapsam", "rol", "gorev", "yetki", "sorumluluk", "sonuc"), "practical_effect": ("sonuc", "hak", "yukumluluk", "sart", "istisna", "yetki"), } def query_understanding(question: str) -> dict: q = normalize_for_search(question) interpretive = any(pattern in q for pattern in INTERPRETIVE_PATTERNS) foundational_articles = foundational_article_references(question) routed = legal_query_route(question) practical_effect = interpretive and any( term in q for term in ("sonuc", "sonuclari", "pratik", "ne saglar", "ne getirir", "hak", "yukumluluk") ) return { "interpretive_intent": interpretive, "practical_effect_intent": practical_effect, "foundational_articles": foundational_articles, "route": routed.get("route", ""), "routed_articles": routed.get("articles", []), "routed_document_id": routed.get("document_id", "TR-KANUN-2547" if routed.get("articles") else ""), "deterministic_answer": routed.get("deterministic_answer", False), "expanded_terms": sorted(expand_query_terms(question, interpretive=interpretive, practical_effect=practical_effect)), } def foundational_article_references(question: str) -> list[str]: routed = legal_query_route(question) if routed.get("articles"): return routed["articles"] q = normalize_for_search(question) refs: list[str] = [] if any(pattern in q for pattern in FOUNDATIONAL_PRINCIPLE_PATTERNS): refs.append("Madde 5") if any(pattern in q for pattern in FOUNDATIONAL_PURPOSE_PATTERNS): refs.append("Madde 4") if "genel hukum" in q and not refs: refs.extend(["Madde 4", "Madde 5"]) return refs def legal_query_route(question: str) -> dict: q = normalize_for_search(question) establishment = any(term in q for term in ("nasil kurulur", "nasil acilir", "kurulur", "kurulmasi", "acilir", "acilmasi")) if establishment and "arastirma" in q and "enstitu" in q: return { "route": "research_institute_establishment", "articles": ["Madde 7"], "deterministic_answer": True, } if establishment and "enstitu" in q: return { "route": "institute_establishment", "articles": ["Madde 5", "Madde 7"], "deterministic_answer": True, } if establishment and "uygulama" in q and "arastirma" in q and "merkez" in q: return { "route": "research_application_center_establishment", "articles": ["Madde 7"], "deterministic_answer": True, } if any(pattern in q for pattern in FOUNDATIONAL_PRINCIPLE_PATTERNS): return { "route": "foundational_principles", "articles": ["Madde 5"], "deterministic_answer": True, } if any(pattern in q for pattern in LAW_PURPOSE_PATTERNS) or ("kanun" in q and "amac" in q): return { "route": "law_purpose", "articles": ["Madde 1"], "deterministic_answer": True, } if any(pattern in q for pattern in FOUNDATIONAL_PURPOSE_PATTERNS): return { "route": "foundational_purpose", "articles": ["Madde 4"], "deterministic_answer": True, } return {} def expand_query_terms(question: str, interpretive: bool | None = None, practical_effect: bool | None = None) -> set[str]: q = normalize_for_search(question) terms = set(query_terms(question)) raw_tokens = set(q.split()) stem_tokens = {get_turkish_stem(token) for token in raw_tokens} for key, expansions in CONCEPT_EXPANSIONS.items(): key_stem = get_turkish_stem(key) key_terms = set(key.split()) key_stems = {get_turkish_stem(t) for t in key_terms} if ( re.search(rf"(?= 3: normalized_terms.add(stem) if len(norm) >= 6: normalized_terms.add(norm[:6]) if len(norm) >= 5: normalized_terms.add(norm[:5]) return normalized_terms