import torch import gradio as gr import faiss import numpy as np from sentence_transformers import SentenceTransformer from peft import PeftModel, PeftConfig from transformers import AutoModelForCausalLM, AutoTokenizer import json import os from typing import List, Tuple, Dict # === CSS ve Emoji Fonksiyonu === current_css = """ #chatbot { height: 500px; overflow-y: auto; } """ def add_emojis(text: str) -> str: emoji_mapping = { "kitap": "📚", "kitaplar": "📚", "bilgi": "🧠", "öğrenmek": "🧠", "özgürlük": "🕊️", "özgür": "🕊️", "düşünce": "💭", "düşünmek": "💭", "ateş": "🔥", "yanmak": "🔥", "yasak": "🚫", "yasaklamak": "🚫", "tehlike": "⚠️", "tehlikeli": "⚠️", "devlet": "🏛️", "hükümet": "🏛️", "soru": "❓", "cevap": "✅", "okumak": "👁️", "oku": "👁️", "itfaiye": "🚒", "itfaiyeci": "🚒", "değişim": "🔄", "değişmek": "🔄", "isyan": "✊", "başkaldırı": "✊", "uyuşturucu": "💊", "hap": "💊", "televizyon": "📺", "tv": "📺", "mutlu": "😊", "mutluluk": "😊", "üzgün": "😞", "korku": "😨", "merak": "🤔", "meraklı": "🤔" } found_emojis = [] words = text.split() for word in words: clean_word = word.lower().strip(".,!?") if clean_word in emoji_mapping: found_emojis.append(emoji_mapping[clean_word]) unique_emojis = list(set(found_emojis)) if unique_emojis: return f"{text} {' '.join(unique_emojis)}" return text # === SABİTLER === BASE_MODEL = "ytu-ce-cosmos/turkish-gpt2-large-750m-instruct-v0.1" PEFT_MODEL = "lordzukoiroh/montaggppt2lora" BOOK_PATH = "fahrenheittt451.txt" QA_PATH = "qa_dataset.jsonl" EMBEDDER_NAME = "paraphrase-multilingual-MiniLM-L12-v2" DEVICE = "cuda" if torch.cuda.is_available() else "cpu" # Model ve tokenizer yükleme print("Modeller yükleniyor...") try: # Temel modeli yükle base_model = AutoModelForCausalLM.from_pretrained( BASE_MODEL, device_map="auto", torch_dtype=torch.float16 if DEVICE == "cuda" else torch.float32 ) # LoRA adaptörünü yükle model = PeftModel.from_pretrained( base_model, PEFT_MODEL, device_map="auto" ) print("LoRA adaptörü başarıyla yüklendi") except Exception as e: print(f"Hata: {e}") raise RuntimeError("Model yüklenemedi, lütfen model yollarını kontrol edin") # Tokenizer'ı yükle tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL) model.eval() # Kitap verisini yükle with open(BOOK_PATH, "r", encoding="utf-8") as f: book_text = f.read() paragraphs = [p.strip() for p in book_text.split("\n") if len(p.strip()) > 100] # Embedder ve FAISS indeksi oluştur embedder = SentenceTransformer(EMBEDDER_NAME) paragraph_embeddings = embedder.encode(paragraphs, convert_to_numpy=True) index = faiss.IndexFlatL2(paragraph_embeddings.shape[1]) index.add(paragraph_embeddings) # === QA KAYIT === def save_feedback(question: str, answer: str, liked: bool, filepath: str = QA_PATH): qa_pair = {"question": question, "answer": answer, "liked": liked} with open(filepath, "a", encoding="utf-8") as f: f.write(json.dumps(qa_pair, ensure_ascii=False) + "\n") # === CEVAP ÜRET === def retrieve_context(question: str, top_k: int = 1) -> str: try: question_vec = embedder.encode([question]) _, indices = index.search(np.array(question_vec).astype("float32"), top_k) return "\n".join([paragraphs[i] for i in indices[0]]) except Exception as e: print(f"Error retrieving context: {e}") return "" def generate_answer(question: str, history: List[Dict] = []) -> str: try: context = retrieve_context(question) prompt = ( f"Kullanıcı: {question}\n\n" f"Bağlam:\n{context}\n\n" "Montag, kendisi bir itfaiyeci olarak, her zaman bilgiye ve fikir özgürlüğüne değer verir. " "Onun için kitaplar ve düşünceler, sistemin dayattığı kurallardan çok daha önemlidir. " "Montag'ın perspektifinden cevap ver:" ) inputs = tokenizer.encode(prompt, return_tensors="pt").to(DEVICE) outputs = model.generate( inputs, max_new_tokens=200, do_sample=True, top_p=0.95, temperature=0.85, repetition_penalty=1.1, pad_token_id=tokenizer.eos_token_id ) response = tokenizer.decode(outputs[0], skip_special_tokens=True) if "Montag:" in response: response = response.split("Montag:")[-1].strip() else: response = response.replace(prompt, "").strip() return add_emojis(response) except Exception as e: print(f"Error generating answer: {e}") return "Üzgünüm, bir hata oluştu. Lütfen tekrar deneyin." # --- Yeni cevap üret --- def regenerate_answer(chat_history: List[Dict]) -> Tuple[str, List[Dict]]: if not chat_history: return "", chat_history last_interaction = None for msg in reversed(chat_history): if msg["role"] == "user": last_interaction = msg["content"] break if last_interaction: new_answer = generate_answer(last_interaction) chat_history.append({"role": "assistant", "content": new_answer}) return "", chat_history # --- Beğenilenleri kaydet --- def save_liked(chat_history: List[Dict]) -> List[Dict]: user_msg = None assistant_msg = None for msg in reversed(chat_history): if msg["role"] == "user" and user_msg is None: user_msg = msg["content"] elif msg["role"] == "assistant" and assistant_msg is None: assistant_msg = msg["content"] if user_msg and assistant_msg: break if user_msg and assistant_msg: save_feedback(user_msg, assistant_msg, liked=True) return chat_history # --- Kullanıcı mesajına yanıt ver --- # === GRADIO ARAYÜZÜ === with gr.Blocks(css=current_css) as demo: gr.Markdown(""" # 📚 Montag Chatbot (Fahrenheit 451) *Ray Bradbury'nin Fahrenheit 451 romanındaki karakter Montag ile sohbet edin* """) chatbot = gr.Chatbot( label="Sohbet Geçmişi", height=500, elem_id="chatbot", type="messages" ) msg = gr.Textbox( label="Montag'a sormak istediğiniz soruyu yazın", placeholder="Kitaplar neden yasaklandı?" ) with gr.Row(): like_btn = gr.Button("👍 Beğendim") dislike_btn = gr.Button("👎 Beğenmedim (Alternatif Cevap)") clear_btn = gr.Button("🧹 Sohbeti Temizle") # Olay bağlantıları msg.submit( respond, inputs=[msg, chatbot], outputs=[msg, chatbot] ) like_btn.click( save_liked, inputs=[chatbot], outputs=[chatbot] ) import gradio as gr from typing import Dict, List def respond(message: str, chat_history: List[Dict[str, str]]) -> Dict[str, str]: """ Düzgün tip tanımlarıyla fonksiyon Args: message: str -> Kullanıcı mesajı chat_history: List[Dict] -> Geçmiş sohbetler Returns: Dict[str, str] -> {'role': 'assistant', 'content': 'cevap'} """ return {"role": "assistant", "content": f"Merhaba! {message}"} def regenerate_answer(chat_history: List[Dict[str, str]]) -> Tuple[str, List[Dict[str, str]]]: # Yeniden cevap oluşturma mantığı return "", chat_history + [{"role": "assistant", "content": "Yeni cevap"}] with gr.Blocks() as demo: chatbot = gr.Chatbot( label="Sohbet", type="messages", value=[] ) msg = gr.Textbox(label="Mesajınız") with gr.Row(): dislike_btn = gr.Button("👎 Beğenmedim") clear_btn = gr.Button("🧹 Temizle") # Mesaj gönderme işlemi msg.submit( fn=respond, inputs=[msg, chatbot], outputs=[chatbot], api_name="respond" ) # Beğenmeme butonu işlemi dislike_btn.click( fn=regenerate_answer, inputs=[chatbot], outputs=[msg, chatbot], api_name="regenerate" ) # Temizle butonu işlemi clear_btn.click( fn=lambda: [], inputs=None, outputs=[chatbot], api_name="clear_chat" ) if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, enable_queue=True, show_api=True )