my_rag_app / app.py
ssenaay's picture
Update app.py
70a948a verified
Raw
History Blame Contribute Delete
7.95 kB
import gradio as gr
import PyPDF2
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.llms import HuggingFacePipeline
from transformers import pipeline, AutoTokenizer, GPT2LMHeadModel, BitsAndBytesConfig
import os
import torch
# --- 0. Global Değişkenler ve Ayarlar ---
PDF_PATH = "mevzuat.pdf"
CHUNK_SIZE = 400
CHUNK_OVERLAP = 100
EMBEDDING_MODEL_NAME = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
LLM_MODEL_NAME = "ytu-ce-cosmos/turkish-gpt2-medium"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
# GPT-2'nin maksimum token uzunluğu (genellikle 1024)
MODEL_MAX_LENGTH = 1024
# Üretilecek maksimum yeni token sayısı
MAX_NEW_TOKENS = 200 # Global olarak tanımlandı
# --- 1. PDF'i İşle ve Vektör Veritabanı Oluştur ---
def create_vector_db_from_pdf(pdf_path):
print(f"PDF okunuyor: {pdf_path}")
text = ""
try:
with open(pdf_path, "rb") as file:
reader = PyPDF2.PdfReader(file)
for page_num, page in enumerate(reader.pages):
page_text = page.extract_text()
if page_text:
text += f"Sayfa {page_num + 1}:\n" + page_text + "\n\n"
except Exception as e:
print(f"PDF okunurken hata oluştu: {e}")
return None
if not text:
print("PDF'ten metin çıkarılamadı.")
return None
print(f"Metin toplam {len(text)} karakter.")
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=CHUNK_SIZE,
chunk_overlap=CHUNK_OVERLAP,
length_function=len,
)
chunks = text_splitter.split_text(text)
print(f"Metin {len(chunks)} parçaya ayrıldı.")
print(f"Embedding modeli yükleniyor: {EMBEDDING_MODEL_NAME}")
embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
print("FAISS vektör veritabanı oluşturuluyor...")
db = FAISS.from_texts(chunks, embeddings)
print("Vektör veritabanı başarıyla oluşturuldu.")
return db, embeddings
vector_db, embeddings_model = None, None
if os.path.exists(PDF_PATH):
vector_db, embeddings_model = create_vector_db_from_pdf(PDF_PATH)
else:
print(f"Hata: {PDF_PATH} bulunamadı. Lütfen PDF dosyasını projenizin kök dizinine yükleyin.")
print(f"LLM modeli yükleniyor: {LLM_MODEL_NAME} - Cihaz: {DEVICE}")
tokenizer = None
llm = None
try:
tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_NAME)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
if DEVICE == "cuda":
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
model = GPT2LMHeadModel.from_pretrained(LLM_MODEL_NAME,
quantization_config=quantization_config,
device_map="auto")
else:
model = GPT2LMHeadModel.from_pretrained(LLM_MODEL_NAME).to(DEVICE)
text_generation_pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens=MAX_NEW_TOKENS, # Global MAX_NEW_TOKENS kullanıldı
temperature=0.7,
do_sample=True,
top_k=50,
num_return_sequences=1,
device=0 if DEVICE == "cuda" else -1,
pad_token_id=tokenizer.pad_token_id,
return_full_text=False
)
llm = HuggingFacePipeline(pipeline=text_generation_pipeline)
print("LLM modeli başarıyla yüklendi.")
except Exception as e:
print(f"LLM modeli yüklenirken hata oluştu: {e}")
llm = None
# --- 2. Gradio Arayüzü İçin Soru Cevaplama Fonksiyonu ---
def answer_question(question, chat_history):
global tokenizer
if vector_db is None or llm is None or tokenizer is None:
return "", chat_history + [[question, "Üzgünüm, PDF, LLM veya Tokenizer yüklenemediği için şu an sorularınızı cevaplayamıyorum. Lütfen logları kontrol edin."]]
print(f"Gelen soru: {question}")
retrieved_docs = vector_db.similarity_search(question, k=2)
context = "\n\n".join([doc.page_content for doc in retrieved_docs])
print(f"Bağlam için {len(retrieved_docs)} belge bulundu. İlk 200 karakter:\n{context[:200]}...")
prompt = f"""Aşağıdaki bağlamı kullanarak soruyu cevaplayın. Bağlamda yoksa uydurma yapmayın. Cevabı madde madde yazın ve en sonda kullandığınız kaynakları (varsa 'Sayfa X' gibi belirtin) listeleyin.
Bağlam:
{context}
Soru: {question}
Cevap:
"""
print("LLM'e gönderilen prompt'ın başlangıcı:", prompt[:500])
# --- Prompt uzunluğunu MODEL_MAX_LENGTH - MAX_NEW_TOKENS ile sınırlayalım ---
# Modelin içine girecek token sayısı (MODEL_MAX_LENGTH - MAX_NEW_TOKENS) olmalı
max_input_tokens = MODEL_MAX_LENGTH - MAX_NEW_TOKENS
# Prompt'u token'lara ayır ve uzunluğunu kontrol et
prompt_tokens = tokenizer.encode(prompt, return_tensors='pt')[0]
tokenized_prompt_length = prompt_tokens.shape[0]
print(f"Oluşturulan prompt'un token uzunluğu: {tokenized_prompt_length}")
if tokenized_prompt_length > max_input_tokens:
print(f"UYARI: Prompt'un token uzunluğu ({tokenized_prompt_length}) modelin kabul edebileceği maksimum girdi uzunluğunu ({max_input_tokens}) aşıyor! Kısaltılıyor...")
prompt_tokens = prompt_tokens[:max_input_tokens]
prompt = tokenizer.decode(prompt_tokens, skip_special_tokens=True)
print(f"Prompt kısaltıldı. Yeni token uzunluğu: {len(tokenizer.encode(prompt))}")
print("Kısaltılmış prompt'ın başlangıcı:", prompt[:500])
try:
response_data = llm(prompt)
if isinstance(response_data, list) and len(response_data) > 0 and 'generated_text' in response_data[0]:
final_answer = response_data[0]['generated_text'].strip()
else:
final_answer = str(response_data).strip()
if not final_answer:
final_answer = "Sorunuzla ilgili bağlamda yeterli bilgi bulunamadı."
if final_answer.lower().startswith(prompt.lower()):
final_answer = final_answer[len(prompt):].strip()
if "Cevap:" in final_answer:
final_answer = final_answer.split("Cevap:", 1)[-1].strip()
if final_answer.lower().startswith("aşağıdaki bağlamı kullanarak"):
final_answer = final_answer.split("Cevap:", 1)[-1].strip() if "Cevap:" in final_answer else final_answer.strip()
final_answer = "..." + final_answer
except Exception as e:
final_answer = f"Cevap üretilirken bir hata oluştu: {e}"
print(final_answer)
chat_history.append((question, final_answer))
return "", chat_history
# --- 3. Gradio Arayüz Tanımı ---
with gr.Blocks() as demo:
gr.Markdown(
"""
# Fırat Üniversitesi Mini RAG Botu
Fırat Üniversitesi mevzuat.firat.edu.tr adresinden alınan PDF dosyası üzerinde soru-cevap yapın.
Sorularınıza belgedeki bilgilere dayanarak cevaplar verilecektir.
Bağlamda bilgi yoksa, bot uydurma yapmayacaktır.
"""
)
chatbot = gr.Chatbot(height=400, label="Sohbet")
msg = gr.Textbox(label="Sorunuzu buraya yazın:", placeholder="Örn: 'Belgede tez jürisi kuralı ne?'")
with gr.Row():
submit_btn = gr.Button("Gönder")
clear_btn = gr.Button("Sohbeti Temizle")
msg.submit(answer_question, [msg, chatbot], [msg, chatbot])
submit_btn.click(answer_question, [msg, chatbot], [msg, chatbot])
clear_btn.click(lambda: (None, []), outputs=[msg, chatbot])
if __name__ == "__main__":
demo.launch()