| 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"), |
| |
| |
| |
| "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"), |
| |
| |
| "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"(?<![a-z0-9]){re.escape(key)}(?![a-z0-9])", q) |
| or key_terms <= raw_tokens |
| or key_stem in stem_tokens |
| or (key_stems and key_stems <= stem_tokens) |
| ): |
| terms.update(expansions) |
|
|
| if interpretive is None: |
| interpretive = any(pattern in q for pattern in INTERPRETIVE_PATTERNS) |
| if practical_effect is None: |
| practical_effect = interpretive and any(term in q for term in ("sonuc", "hak", "yukumluluk", "pratik")) |
|
|
| if interpretive: |
| terms.update(INTENT_EXPANSIONS["interpretation"]) |
| if practical_effect: |
| terms.update(INTENT_EXPANSIONS["practical_effect"]) |
|
|
| normalized_terms: set[str] = set() |
| for term in terms: |
| norm = normalize_for_search(term) |
| if len(norm) < 4: |
| continue |
| normalized_terms.add(norm) |
| stem = get_turkish_stem(norm) |
| if stem and len(stem) >= 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 |
|
|