aysemutluay commited on
Commit
2d15f15
·
verified ·
1 Parent(s): 29a6a3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -81
app.py CHANGED
@@ -7,22 +7,18 @@ from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM
7
  import os
8
  import torch
9
 
10
- # --- 0. Global Değişkenler ve Ayarlar ---
11
  PDF_PATH = "mevzuat.pdf"
12
  CHUNK_SIZE = 1000
13
  CHUNK_OVERLAP = 150
14
  EMBEDDING_MODEL_NAME = "intfloat/multilingual-e5-base"
15
-
16
- # Önerilen model (senin isteğin üzerine)
17
  LLM_MODEL_NAME = "cerebras/btlm-3b-8k-base"
18
 
19
- # Token limitler (modelin desteklediği maksimum input token'a göre ayarla)
20
- # Bu model 4096 token destekliyorsa; yoksa modeli 2048/4096 gibi değerlere göre güncelle.
21
  MODEL_MAX_INPUT_TOKENS = 4096
22
- MAX_NEW_TOKENS = 256 # Üretilecek maksimum token
23
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
24
 
25
- # --- 1. PDF'i İşle ve Vektör Veritabanı Oluştur ---
26
  def create_vector_db_from_pdf(pdf_path):
27
  print(f"PDF okunuyor: {pdf_path}")
28
  text = ""
@@ -32,7 +28,7 @@ def create_vector_db_from_pdf(pdf_path):
32
  for page_num, page in enumerate(reader.pages):
33
  page_text = page.extract_text()
34
  if page_text:
35
- text += f"Sayfa {page_num + 1}:\n" + page_text + "\n\n"
36
  except Exception as e:
37
  print(f"PDF okunurken hata oluştu: {e}")
38
  return None, None
@@ -42,145 +38,111 @@ def create_vector_db_from_pdf(pdf_path):
42
  return None, None
43
 
44
  print(f"Metin toplam {len(text)} karakter.")
45
-
46
  text_splitter = RecursiveCharacterTextSplitter(
47
- chunk_size=CHUNK_SIZE,
48
- chunk_overlap=CHUNK_OVERLAP,
49
- length_function=len,
50
  )
51
  chunks = text_splitter.split_text(text)
52
  print(f"Metin {len(chunks)} parçaya ayrıldı.")
53
 
54
  print(f"Embedding modeli yükleniyor: {EMBEDDING_MODEL_NAME}")
55
  embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
56
-
57
  print("FAISS vektör veritabanı oluşturuluyor...")
58
  db = FAISS.from_texts(chunks, embeddings)
59
  print("Vektör veritabanı başarıyla oluşturuldu.")
60
  return db, embeddings
61
 
 
62
  vector_db, embeddings_model = None, None
63
  if os.path.exists(PDF_PATH):
64
  vector_db, embeddings_model = create_vector_db_from_pdf(PDF_PATH)
65
  else:
66
- print(f"Hata: {PDF_PATH} bulunamadı. Lütfen PDF dosyasını projenizin kök dizinine yükleyin.")
67
 
68
- # --- 2. LLM Modelini ve Pipeline'ı Yükle ---
69
- tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_NAME, trust_remote_code=True)
70
  text_generation_pipeline = None
71
  try:
72
- print(f"Tokenizer ve model yükleniyor: {LLM_MODEL_NAME} -> Cihaz: {DEVICE}")
73
- tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_NAME, use_fast=True)
74
-
75
  model = AutoModelForCausalLM.from_pretrained(
76
- LLM_MODEL_NAME,
77
- torch_dtype=torch.float16 if DEVICE=="cuda" else torch.float32,
78
- trust_remote_code=True
79
- )
 
 
80
 
81
- # pipeline
82
- device_arg = 0 if DEVICE == "cuda" else -1
83
  text_generation_pipeline = pipeline(
84
  "text-generation",
85
  model=model,
86
  tokenizer=tokenizer,
87
- device=device_arg,
88
  max_new_tokens=MAX_NEW_TOKENS,
89
- do_sample=False, # mevzuat gibi resmi kaynaklarda daha deterministik sonuç için False önerilir
90
  temperature=0.0,
91
  top_k=50,
92
  pad_token_id=tokenizer.eos_token_id
93
  )
94
  print("LLM pipeline başarıyla oluşturuldu.")
95
 
96
-
97
  except Exception as e:
98
  print(f"LLM yüklenirken hata oluştu: {e}")
99
  text_generation_pipeline = None
100
 
101
  # --- 3. Soru-Cevap Fonksiyonu ---
102
  def answer_question(question, chat_history):
103
- if vector_db is None or text_generation_pipeline is None or tokenizer is None:
104
- err_msg = "Üzgünüm, PDF veya model yüklenemedi (logları kontrol edin)."
105
- return "", chat_history + [[question, err_msg]]
106
 
107
  print(f"Gelen soru: {question}")
108
-
109
- # Retrieval: en benzer k parça
110
  k = 2
111
  retrieved_docs = vector_db.similarity_search(question, k=k)
 
112
  if not retrieved_docs:
113
- return "", chat_history + [[question, "İlgili bağlam bulunamadı."]]
114
 
115
- # Bağlamı birleştir
116
- docs_texts = [doc.page_content for doc in retrieved_docs]
117
- context = "\n\n".join(docs_texts)
118
 
119
- # Token bazlı güvenli kırpma:
120
- # Maksimum izin verilen input token sayısı = MODEL_MAX_INPUT_TOKENS - MAX_NEW_TOKENS - bir güvenlik payı
121
- safety_margin = 32
122
- max_context_tokens = MODEL_MAX_INPUT_TOKENS - MAX_NEW_TOKENS - safety_margin
123
- # tokenize et ve gerekirse kısalt (son kısımları tutmak genelde daha iyi)
124
  context_tokens = tokenizer.encode(context, truncation=False)
125
  if len(context_tokens) > max_context_tokens:
126
- print(f"Bağlam token sayısı ({len(context_tokens)}) limit aşıyor ({max_context_tokens}). Kısaltılıyor.")
127
- # son max_context_tokens token'ı al
128
- truncated_tokens = context_tokens[-max_context_tokens:]
129
- context = tokenizer.decode(truncated_tokens, skip_special_tokens=True)
130
 
131
- # Prompt oluştur
132
  prompt = (
133
- "Aşağıdaki bağlamı kullanarak soruyu cevaplayın. Bağlamda yoksa uydurma yapmayın.\n"
134
- "Cevabı madde madde yazın ve en sonda kaynakları 'Sayfa X' biçiminde belirtin.\n\n"
 
135
  f"Bağlam:\n{context}\n\n"
136
- f"Soru: {question}\n\n"
137
- "Cevap:\n"
138
  )
139
 
140
- print("Prompt oluşturuldu. Token sayısı:", len(tokenizer.encode(prompt)))
141
- try:
142
- gen = text_generation_pipeline(prompt)
143
- # pipeline returns a list of dicts with 'generated_text'
144
- if isinstance(gen, list) and len(gen) > 0 and "generated_text" in gen[0]:
145
- raw = gen[0]["generated_text"]
146
- # pipeline çıktı olarak prompt'ı tekrar edebilir, onu ayıklayalım
147
- if prompt in raw:
148
- final_answer = raw.split(prompt, 1)[-1].strip()
149
- else:
150
- final_answer = raw.strip()
151
- else:
152
- # fallback
153
- final_answer = str(gen)
154
-
155
- if not final_answer:
156
- final_answer = "Sorunuzla ilgili bağlamda yeterli bilgi bulunamadı."
157
 
 
 
 
 
158
  except Exception as e:
159
  print("Cevap üretilirken hata:", e)
160
- final_answer = f"Cevap üretilirken bir hata oluştu: {e}"
161
 
162
- chat_history.append((question, final_answer))
163
  return "", chat_history
164
 
165
  # --- 4. Gradio Arayüzü ---
166
  with gr.Blocks() as demo:
167
- gr.Markdown(
168
- """
169
- # Fırat Üniversitesi Mini RAG Botu (Optimizasyonlu)
170
- PDF'teki mevzuat üzerinde Türkçe soru-cevap. Bağlamda bilgi yoksa uydurma yapılmayacaktır.
171
- """
172
- )
173
-
174
- chatbot = gr.Chatbot(height=400, label="Sohbet")
175
- msg = gr.Textbox(label="Sorunuzu buraya yazın:", placeholder="Örn: 'Belgede tez jürisi kuralı ne?'")
176
 
177
  with gr.Row():
178
  submit_btn = gr.Button("Gönder")
179
- clear_btn = gr.Button("Sohbeti Temizle")
180
 
181
  msg.submit(answer_question, [msg, chatbot], [msg, chatbot])
182
  submit_btn.click(answer_question, [msg, chatbot], [msg, chatbot])
183
  clear_btn.click(lambda: (None, []), outputs=[msg, chatbot])
184
 
185
  if __name__ == "__main__":
186
- demo.launch()
 
7
  import os
8
  import torch
9
 
10
+ # --- 0. Global Ayarlar ---
11
  PDF_PATH = "mevzuat.pdf"
12
  CHUNK_SIZE = 1000
13
  CHUNK_OVERLAP = 150
14
  EMBEDDING_MODEL_NAME = "intfloat/multilingual-e5-base"
 
 
15
  LLM_MODEL_NAME = "cerebras/btlm-3b-8k-base"
16
 
 
 
17
  MODEL_MAX_INPUT_TOKENS = 4096
18
+ MAX_NEW_TOKENS = 256
19
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
20
 
21
+ # --- 1. PDF'ten Vektör Veritabanı Oluştur ---
22
  def create_vector_db_from_pdf(pdf_path):
23
  print(f"PDF okunuyor: {pdf_path}")
24
  text = ""
 
28
  for page_num, page in enumerate(reader.pages):
29
  page_text = page.extract_text()
30
  if page_text:
31
+ text += f"Sayfa {page_num + 1}:\n{page_text}\n\n"
32
  except Exception as e:
33
  print(f"PDF okunurken hata oluştu: {e}")
34
  return None, None
 
38
  return None, None
39
 
40
  print(f"Metin toplam {len(text)} karakter.")
 
41
  text_splitter = RecursiveCharacterTextSplitter(
42
+ chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP, length_function=len
 
 
43
  )
44
  chunks = text_splitter.split_text(text)
45
  print(f"Metin {len(chunks)} parçaya ayrıldı.")
46
 
47
  print(f"Embedding modeli yükleniyor: {EMBEDDING_MODEL_NAME}")
48
  embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
 
49
  print("FAISS vektör veritabanı oluşturuluyor...")
50
  db = FAISS.from_texts(chunks, embeddings)
51
  print("Vektör veritabanı başarıyla oluşturuldu.")
52
  return db, embeddings
53
 
54
+
55
  vector_db, embeddings_model = None, None
56
  if os.path.exists(PDF_PATH):
57
  vector_db, embeddings_model = create_vector_db_from_pdf(PDF_PATH)
58
  else:
59
+ print(f"Hata: {PDF_PATH} bulunamadı. Lütfen PDF dosyasını yükleyin.")
60
 
61
+ # --- 2. LLM Yükleme ---
 
62
  text_generation_pipeline = None
63
  try:
64
+ print(f"Model yükleniyor: {LLM_MODEL_NAME} -> Cihaz: {DEVICE}")
65
+ tokenizer = AutoTokenizer.from_pretrained(LLM_MODEL_NAME)
 
66
  model = AutoModelForCausalLM.from_pretrained(
67
+ LLM_MODEL_NAME,
68
+ torch_dtype=torch.float32, # CPU uyumlu
69
+ low_cpu_mem_usage=True
70
+ )
71
+
72
+ model.to(DEVICE)
73
 
 
 
74
  text_generation_pipeline = pipeline(
75
  "text-generation",
76
  model=model,
77
  tokenizer=tokenizer,
78
+ device=-1, # CPU'da bu değer -1 olmalı
79
  max_new_tokens=MAX_NEW_TOKENS,
80
+ do_sample=False,
81
  temperature=0.0,
82
  top_k=50,
83
  pad_token_id=tokenizer.eos_token_id
84
  )
85
  print("LLM pipeline başarıyla oluşturuldu.")
86
 
 
87
  except Exception as e:
88
  print(f"LLM yüklenirken hata oluştu: {e}")
89
  text_generation_pipeline = None
90
 
91
  # --- 3. Soru-Cevap Fonksiyonu ---
92
  def answer_question(question, chat_history):
93
+ if vector_db is None or text_generation_pipeline is None:
94
+ err = "Model veya PDF yüklenemedi. Lütfen logları kontrol edin."
95
+ return "", chat_history + [{"role": "assistant", "content": err}]
96
 
97
  print(f"Gelen soru: {question}")
 
 
98
  k = 2
99
  retrieved_docs = vector_db.similarity_search(question, k=k)
100
+
101
  if not retrieved_docs:
102
+ return "", chat_history + [{"role": "assistant", "content": "İlgili bilgi bulunamadı."}]
103
 
104
+ context = "\n\n".join([doc.page_content for doc in retrieved_docs])
 
 
105
 
106
+ # Token güvenliği
107
+ max_context_tokens = MODEL_MAX_INPUT_TOKENS - MAX_NEW_TOKENS - 32
 
 
 
108
  context_tokens = tokenizer.encode(context, truncation=False)
109
  if len(context_tokens) > max_context_tokens:
110
+ context = tokenizer.decode(context_tokens[-max_context_tokens:], skip_special_tokens=True)
 
 
 
111
 
 
112
  prompt = (
113
+ "Aşağıdaki bağlamı kullanarak soruyu yanıtlayın. "
114
+ "Bağlamda olmayan bilgileri uydurmayın.\n"
115
+ "Cevabı madde madde ve 'Sayfa X' şeklinde kaynak vererek yazın.\n\n"
116
  f"Bağlam:\n{context}\n\n"
117
+ f"Soru: {question}\n\nCevap:\n"
 
118
  )
119
 
120
+ print(f"Prompt token sayısı: {len(tokenizer.encode(prompt))}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
+ try:
123
+ outputs = text_generation_pipeline(prompt)
124
+ generated_text = outputs[0]["generated_text"]
125
+ final_answer = generated_text.replace(prompt, "").strip()
126
  except Exception as e:
127
  print("Cevap üretilirken hata:", e)
128
+ final_answer = f"Cevap üretilemedi: {e}"
129
 
130
+ chat_history.append({"role": "assistant", "content": final_answer})
131
  return "", chat_history
132
 
133
  # --- 4. Gradio Arayüzü ---
134
  with gr.Blocks() as demo:
135
+ gr.Markdown("# 📘 Fırat Üniversitesi Mevzuat Asistanı")
136
+ chatbot = gr.Chatbot(height=400, label="Sohbet", type="messages")
137
+ msg = gr.Textbox(label="Sorunuzu yazın:", placeholder="Örn: MADDE 1’i özetle")
 
 
 
 
 
 
138
 
139
  with gr.Row():
140
  submit_btn = gr.Button("Gönder")
141
+ clear_btn = gr.Button("Temizle")
142
 
143
  msg.submit(answer_question, [msg, chatbot], [msg, chatbot])
144
  submit_btn.click(answer_question, [msg, chatbot], [msg, chatbot])
145
  clear_btn.click(lambda: (None, []), outputs=[msg, chatbot])
146
 
147
  if __name__ == "__main__":
148
+ demo.launch()