YOKPilot3 / conversation_intent.py
mfirat007's picture
Upload 5 files
273b770 verified
Raw
History Blame Contribute Delete
5.95 kB
from __future__ import annotations
import re
from dataclasses import dataclass
from utils import normalize_for_search
class ConversationIntent:
EMPTY = "empty"
GREETING = "greeting"
HELP = "help"
THANKS = "thanks"
OUT_OF_SCOPE = "out_of_scope"
LEGAL_QUERY = "legal_query"
GREETING_ANSWER = (
"Merhaba. Ben MitrAnlil Yükseköğretim Mevzuatı AI Asistanıyım. "
"2547, 2914 ve 2809 sayılı kanunlara dayalı olarak kaynak gösterimli cevaplar üretirim. "
"YÖK, üniversiteler, akademik personel, öğrenciler, teşkilat, ödenekler, görevler, yetkiler ve ilgili hükümler hakkında soru sorabilirsiniz."
)
HELP_ANSWER = (
"Ben yükseköğretim mevzuatı için geliştirilmiş kaynak gösterimli bir mevzuat asistanıyım. "
"Sorunuzu kanundaki madde, alt hüküm ve kanıt parçalarıyla eşleştirerek cevaplamaya çalışırım. "
"Örneğin dekanın görevleri, YÖK'ün oluşumu, ek ders ücreti, üniversite ödeneği, teşkilat yapısı veya kurumların kuruluşu hakkında soru sorabilirsiniz."
)
THANKS_ANSWER = "Rica ederim. Yükseköğretim mevzuatı ile ilgili başka bir soru sorabilirsiniz."
OUT_OF_SCOPE_ANSWER = (
"Bu pilot yükseköğretim mevzuatı kapsamında kaynak gösterimli cevap üretmek üzere tasarlanmıştır. "
"YÖK, üniversiteler, akademik personel, öğrenciler, diplomalar, teşkilat, ödenekler, görevler ve yetkiler gibi konularda soru sorabilirsiniz."
)
@dataclass(frozen=True)
class ConversationIntentResult:
intent: str
answer: str = ""
LEGAL_CUE_TERMS = {
"egitim", "uzaktan egitim", "yonetmelik", "yonerge", "tez", "savunma",
"tez savunmasi", "basvuru", "devam", "akademik takvim",
"2547", "2914", "2809", "kanun", "madde", "yok", "yök", "yuksekogretim", "yükseköğretim",
"universite", "üniversite", "rektor", "rektör", "dekan", "senato", "fakulte", "fakülte",
"enstitu", "enstitü", "yuksekokul", "yüksekokul", "meslek", "onlisans", "önlisans",
"on lisans", "ön lisans", "lisans", "diploma", "ogrenci", "öğrenci", "ogretim", "öğretim",
"profesor", "profesör", "docent", "doçent", "arastirma", "araştırma", "gorev", "görev",
"yetki", "sorumluluk", "atan", "atama", "kurul", "kurulus", "kuruluş", "disiplin",
"harc", "harç", "katki", "katkı", "ucret", "ücret", "denklik", "azami", "sure", "süre",
"ek ders", "ödenek", "odenek", "derece", "kademe", "teşkilat", "teskilat",
"faaliyete", "ek gösterge", "ek gosterge", "makam tazminatı", "makam tazminati",
"maaş", "maas", "aylık", "aylik", "mali hak", "özlük hakkı", "ozluk hakki",
"tazminat", "ödeme", "odeme", "gösterge", "gosterge", "sosyal hak",
}
OUT_OF_SCOPE_CUE_TERMS = {
"hava", "yemek", "tarif", "siir", "şiir", "hikaye", "futbol", "borsa", "kripto",
"film", "muzik", "müzik", "resim", "kod yaz", "mail yaz", "cevir", "çevir",
}
def detect_conversation_intent(message: str) -> ConversationIntentResult:
raw = (message or "").strip()
normalized = normalize_for_search(raw)
compact = normalized.replace(" ", "")
if not normalized:
return ConversationIntentResult(ConversationIntent.EMPTY, "Lütfen yükseköğretim mevzuatı ile ilgili bir soru yazın.")
if _is_greeting(normalized, compact):
return ConversationIntentResult(ConversationIntent.GREETING, GREETING_ANSWER)
if _is_thanks(normalized):
return ConversationIntentResult(ConversationIntent.THANKS, THANKS_ANSWER)
if _is_help_request(normalized):
return ConversationIntentResult(ConversationIntent.HELP, HELP_ANSWER)
if _has_legal_cue(normalized):
return ConversationIntentResult(ConversationIntent.LEGAL_QUERY, "")
if _has_out_of_scope_cue(normalized):
return ConversationIntentResult(ConversationIntent.OUT_OF_SCOPE, OUT_OF_SCOPE_ANSWER)
# Questions without legal cues should still reach the MCKF engine when they look
# like normative questions. This avoids blocking short queries such as "kim atar?"
# in follow-up-like usage while keeping pure greetings outside retrieval.
if any(term in normalized for term in ("nedir", "nasil", "nasıl", "kim", "hangi", "ne zaman", "kac", "kaç", "gerekir", "olur")):
return ConversationIntentResult(ConversationIntent.LEGAL_QUERY, "")
return ConversationIntentResult(ConversationIntent.OUT_OF_SCOPE, OUT_OF_SCOPE_ANSWER)
def _is_greeting(normalized: str, compact: str) -> bool:
greetings = {
"merhaba", "selam", "selamlar", "gunaydin", "günaydın", "iyi gunler", "iyi günler",
"iyi aksamlar", "iyi akşamlar", "iyi geceler", "kolay gelsin", "mrb", "slm",
}
if normalized in greetings or compact in {g.replace(" ", "") for g in greetings}:
return True
if len(normalized.split()) <= 3 and any(g in normalized for g in greetings):
return True
return False
def _is_thanks(normalized: str) -> bool:
return len(normalized.split()) <= 6 and any(term in normalized for term in ("tesekkur", "teşekkür", "sag ol", "sağ ol", "eyvallah", "tşk"))
def _is_help_request(normalized: str) -> bool:
phrases = (
"ne yapabilirsin", "neler yapabilirsin", "nasil calisiyorsun", "nasıl çalışıyorsun",
"bu sistem nedir", "hangi sorular", "ne sorabilirim",
)
if any(phrase in normalized for phrase in phrases):
return True
# "yardım" tek başına yardım niyetidir; "kurumlararası yardımlaşma"
# içindeki kök aynı niyet değildir.
return bool(re.search(r"(?<![a-z0-9])yardim(?![a-z0-9])", normalized))
def _has_legal_cue(normalized: str) -> bool:
return any(term in normalized for term in LEGAL_CUE_TERMS)
def _has_out_of_scope_cue(normalized: str) -> bool:
return any(term in normalized for term in OUT_OF_SCOPE_CUE_TERMS)