sahinhukuk-bot / app.py
sahinomercan's picture
Update app.py
ef3ea72 verified
import gradio as gr
from sentence_transformers import SentenceTransformer, util
from transformers import pipeline # T5 yerine standart pipeline kullanacağız
import torch
import os
import pickle
import re
# --- 1. KONFİGÜRASYON ---
TEXT_FILE = "icerik.txt"
EMBEDDING_CACHE_FILE = "embeddings.pkl"
EMBEDDING_MODEL_NAME = "all-MiniLM-L6-v2"
# YENİ MODEL: Türkçe için eğitilmiş, "saçmalamayan" Extractive QA modeli
QA_MODEL_NAME = "savasy/bert-base-turkish-squad"
RETRIEVAL_THRESHOLD = 0.55 # Paragraf bulma benzerlik skoru
QA_THRESHOLD = 0.40 # Cevap çıkarma güven skoru
# İLETİŞİM BİLGİLERİ (Arayüze Entegre Edilecek)
PHONE_MAIN = '+90 531 294 22 34'
PHONE_LANDLINE_EXT = '0232 464 41 00 (Dahili 165)'
WHATSAPP_LINK = 'http://wa.me/905312942234'
APPOINTMENT_LINK = 'https://calendar.app.google/JT9A1oGHVGopNZ9y8'
MAP_LINK = 'https://maps.app.goo.gl/PLsBy9afjiRB9WDb6'
# --- 2. MODELLERİN YÜKLENMESİ ve VERİ YÜKLEME ---
print("Modeller yükleniyor...")
# 1. Paragraf Bulucu (Retrieval)
embedding_model = SentenceTransformer(EMBEDDING_MODEL_NAME)
# 2. Cevap Çıkarıcı (Extraction)
qa_pipeline = pipeline("question-answering", model=QA_MODEL_NAME, tokenizer=QA_MODEL_NAME)
print("Tüm modeller yüklendi.")
def load_documents():
"""Dokümanları yükler ve embedding'leri önbellekten çeker."""
try:
if os.path.exists(EMBEDDING_CACHE_FILE):
with open(EMBEDDING_CACHE_FILE, "rb") as f: data = pickle.load(f)
return data["docs"], data["embeddings"]
with open(TEXT_FILE, "r", encoding="utf-8") as f:
paragraphs = f.read().split("\n\n")
docs = [p.strip() for p in paragraphs if len(p.strip()) > 0]
if not docs: raise ValueError("icerik.txt dosyası boş.")
embeddings = embedding_model.encode(docs, convert_to_tensor=True)
with open(EMBEDDING_CACHE_FILE, "wb") as f: pickle.dump({"docs": docs, "embeddings": embeddings}, f)
return docs, embeddings
except (FileNotFoundError, ValueError) as e:
print(f"HATA: {e}")
return [], None
docs, embeddings = load_documents()
# --- 3. POST-PROCESSİNG (Sadece Kaynak Gösterimi İçin) ---
def post_process_context(context: str) -> str:
paragraphs = context.split('\n\n')
cleaned_paragraphs = []
for p in paragraphs:
p = p.strip()
p = re.sub(r'^[\s]*[\*\-\•\d\.\)]+\s*', '', p, flags=re.MULTILINE).strip()
if len(p) > 20:
cleaned_paragraphs.append(p)
return "<br> • " + "<br> • ".join(cleaned_paragraphs)
# --- 4. ANA MANTIK (Extractive RAG) ---
def answer_question(question: str):
if qa_pipeline is None or not docs or embeddings is None:
return "<div style='font-family: Arial; color: #8b0000;'><h3>Sistem Hatası:</h3><p>Lokal bilgi kaynakları veya Yapay Zeka motoru yüklenemedi.</p></div>"
# 1. Retrieval (Çekme): En alakalı paragrafları bul
question_embedding = embedding_model.encode(question, convert_to_tensor=True)
scores = util.pytorch_cos_sim(question_embedding, embeddings)[0]
top_k = min(3, len(docs))
top_results = torch.topk(scores, k=top_k)
selected_context = []
for score, idx in zip(top_results.values, top_results.indices):
if score.item() >= RETRIEVAL_THRESHOLD:
selected_context.append(docs[idx.item()])
if not selected_context:
# Cevap bulunamadı durumu
return f"""
<div style="font-family: Arial; color: #8b0000;">
<h3>Üzgünüz, dahili bilgi bankamızda bu konuyla ilgili doğrudan bir bilgiye ulaşılamadı.</h3>
<p>Daha açıklayıcı bir soru yazabilir veya
<a href='{WHATSAPP_LINK}' style='color: #8b0000; text-decoration: underline;'>WhatsApp üzerinden bize ulaşabilirsiniz</a>.
</p>
</div>
"""
full_context = "\n\n".join(selected_context)
# 2. Extraction (Cevabı Çıkarma) - YENİ KISIM
# Model, bu metin içinden sorunun cevabını bulur
qa_result = qa_pipeline(question=question, context=full_context)
answer = qa_result['answer']
score = qa_result['score']
# Güven skoru düşükse (cevap alakasızsa) veya cevap çok kısaysa
if score < QA_THRESHOLD or len(answer) < 10:
return f"""
<div style="font-family: Arial; color: #8b0000;">
<h3>Bilgi bankamızda bu soruya yönelik net bir cevap bulunamadı.</h3>
<p>Lütfen ofisimizle iletişime geçin.
<a href='{WHATSAPP_LINK}' style='color: #8b0000; text-decoration: underline;'>WhatsApp üzerinden bize ulaşabilirsiniz</a>.
</p>
</div>
"""
# 3. Final Sunum
processed_context_html = post_process_context(full_context)
answer_html = f"""
<div style="font-family: Arial, sans-serif; color: #1f1f1f; line-height: 1.6;">
<h3 style="color: #003366;">🧾 Sorunuz</h3>
<p><strong>{question}</strong></p>
<h3 style="color: #003366;">✅ Yapay Zeka Yanıtı (Çıkarım)</h3>
<p style="background-color: #eef7ff; border-left: 5px solid #005580; padding: 15px; border-radius: 5px; font-weight: bold;">
{answer}
</p>
<h3 style="color: #003366; margin-top: 20px;">📚 Cevabın Alındığı Kaynak Metinler</h3>
<p style="font-size: 14px; color: #333; padding: 0 15px 0 15px;">
{processed_context_html}
</p>
<h3 style="color: #8b0000; margin-top: 25px;">📢 Kişisel Değerlendirme ve Görüşme</h3>
<p style="font-size: 16px;">
Detaylı durum tespiti ve kişisel yol haritanız için hemen bizimle iletişime geçin:
<br><br>
<a href='{WHATSAPP_LINK}' style='color: #003366; font-weight: bold; text-decoration: underline;'>📞 WhatsApp Üzerinden Hızlı İletişim</a>
<br>
<span style="color: #666;">Telefon: {PHONE_MAIN} | Dahili: {PHONE_LANDLINE_EXT}</span>
</p>
</div>
"""
return answer_html
# --- 5. GRADIO ARAYÜZÜ ---
# (Arayüz kodunda değişiklik yok, tüm iletişim bilgileri yerinde)
header_info = """
<div style="font-family: Arial; padding: 15px; background: linear-gradient(to right, #003366, #005580); color: white; border-radius: 10px;">
<h2 style="color: white;">Şahin Hukuk | Akıllı Asistan</h2>
<p style="color: white; font-size: 14px;">
📞 Telefon: {PHONE_MAIN} & {PHONE_LANDLINE_EXT}<br>
💬 WhatsApp: <a href='{WHATSAPP_LINK}' style='color: white; text-decoration: underline;'>Tıklayın</a><br>
📅 Randevu: <a href='{APPOINTMENT_LINK}' style='color: white; text-decoration: underline;'>Randevu Al</a><br>
🗺️ Yol Tarifi: <a href='{MAP_LINK}' style='color: white; text-decoration: underline;'>Haritada Gör</a>
</p>
</div>
""".format(
PHONE_MAIN=PHONE_MAIN,
PHONE_LANDLINE_EXT=PHONE_LANDLINE_EXT,
WHATSAPP_LINK=WHATSAPP_LINK,
APPOINTMENT_LINK=APPOINTMENT_LINK,
MAP_LINK=MAP_LINK
)
interface = gr.Interface(
fn=answer_question,
inputs=gr.Textbox(label="Sorunuzu buraya yazın", lines=2, placeholder="Örn: Kira tespit davası nedir?"),
outputs=gr.HTML(label="Yanıt"),
title="Şahin Hukuk | Akıllı Asistan",
description=header_info,
allow_flagging="never",
submit_btn="Gönder",
clear_btn="Temizle")
interface.launch()