Spaces:
Sleeping
Sleeping
| 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() |