mhuseyina commited on
Commit
5477294
·
verified ·
1 Parent(s): 16cbcf1

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +142 -252
  2. requirements.txt +1 -2
app.py CHANGED
@@ -1,110 +1,73 @@
1
- # RAG Temelli Eğitim Chatbot (EğitBot)
2
  import os
3
-
4
- # Hugging Face cache klasörlerini uygulama dizini içine yönlendir
5
- os.environ["HF_HOME"] = "./cache"
6
- os.environ["HF_DATASETS_CACHE"] = "./cache/hf_datasets"
7
- os.environ["TRANSFORMERS_CACHE"] = "./cache/transformers"
8
- os.environ["SENTENCE_TRANSFORMERS_HOME"] = "./cache/sentence_transformers"
9
-
10
- # Gerekli kütüphaneleri ekliyoruz.
11
- import os
12
- import requests
13
- import streamlit as st
14
  from datasets import load_dataset
15
  from langchain_huggingface import HuggingFaceEmbeddings
16
  from langchain.text_splitter import TokenTextSplitter
17
  from langchain_community.vectorstores import FAISS
18
- from langchain.text_splitter import CharacterTextSplitter
19
  from langchain.chains import RetrievalQA
20
  from langchain.prompts import PromptTemplate
21
  from langchain_google_genai import ChatGoogleGenerativeAI
22
- import datetime
23
 
24
- # Streamlit secrets üzerinden API anahtarını al
 
 
 
 
 
 
25
  GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
26
  HUGGINGFACEHUB_API_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN")
27
-
28
  MODEL_NAME = "models/gemini-2.5-pro"
29
 
30
- # -----------------------------
31
- # 📄 VERİ SETİ & VEKTÖR VERİTABANI HAZIRLAMA
32
- # -----------------------------
33
- # Veri hazırlama işlemi de sadece bir kez yapılır.
34
- # Burda 4 farklı veri seti ekliyoruz.
35
- # Veri setlerinden math_word problem tarzı sorular için
36
- # math_hard daha derin işlemler için
37
- # edu eğitim temalı genel soru-cevap için
38
- # wiki_sum bu veri setide tarih ve fen alanında daha verimli cevaplar için kullanılmıştır.
39
- @st.cache_resource
40
  def prepare_retriever():
41
- try:
42
- dataset_math_word = load_dataset("duxx/orca-math-word-problems-tr", split="train[:2000]")
43
- dataset_math_hard = load_dataset("Karayel-DDI/Turkce_Lighteval_MATH-Hard", split="train[:2000]")
44
- dataset_edu = load_dataset("korkmazemin1/turkish-education-dataset", split="train[:2000]")
45
- dataset_wiki_sum = load_dataset("musabg/wikipedia-tr-summarization", split="train[:2000]")
46
-
47
-
48
- documents = []
49
- # 1. Orca Math Word Problems
50
- for item in dataset_math_word:
51
- question = item.get("question", "").strip()
52
- answer = item.get("answer", "").strip()
53
- if question and answer:
54
- documents.append(f"Soru: {question}\nCevap: {answer}")
55
-
56
- # 2. Karayel-DDI Math Hard
57
- for item in dataset_math_hard:
58
- question = item.get("question", "").strip()
59
- answer = item.get("solution", "").strip()
60
- if question and answer:
61
- documents.append(f"Soru: {question}\nCevap: {answer}")
62
-
63
- # 3. Korkmazemin1 Turkish Education Dataset
64
- for item in dataset_edu:
65
- question = item.get("soru", "").strip()
66
- answer = item.get("cevap", "").strip()
67
- if question and answer:
68
- documents.append(f"Soru: {question}\nCevap: {answer}")
69
-
70
- # 4. Musabg Wikipedia Turkish Summarization Dataset
71
- for item in dataset_wiki_sum:
72
- text = item.get("text", "").strip()
73
- summary = item.get("summary", "").strip()
74
- if text and summary:
75
- documents.append(f"Metin: {text}\nÖzet: {summary}")
76
-
77
- # Metinleri parçalara ayıralım
78
- text_splitter = TokenTextSplitter(chunk_size=1000, chunk_overlap=100)
79
- docs = text_splitter.create_documents(documents)
80
-
81
- # Embedding modeli
82
- embedding_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
83
-
84
- # FAISS dizini
85
- FAISS_PATH = "faiss_index"
86
-
87
- # Daha önce kayıtlı FAISS varsa onu yükle
88
- if os.path.exists(FAISS_PATH):
89
- vectorstore = FAISS.load_local(FAISS_PATH, embedding_model, allow_dangerous_deserialization=True)
90
- else:
91
- vectorstore = FAISS.from_documents(docs, embedding_model)
92
- vectorstore.save_local(FAISS_PATH)
93
-
94
- return vectorstore.as_retriever(search_kwargs={"k": 3})
95
 
96
- except Exception as e:
97
- st.error(f"Veri seti hazırlanırken hata oluştu: {e}")
98
- return None
99
- # Eğer retriever None dönerse uygulamayı durdurabilirsin
100
  retriever = prepare_retriever()
101
- if retriever is None:
102
- st.stop()
103
 
104
- # -----------------------------
105
- # 🔗 ÖZEL PROMPT OLUŞTURMA
106
- # -----------------------------
107
- # Burada modelden gelen bilgiyi nasıl kullanacağını söylüyoruz.
108
  prompt_template = """
109
  Sadece sorulan soruya net ve kısa cevap ver. Gereksiz ek açıklama yapma.
110
  Sadece yukarıdaki soruya cevap ver. Başka konulara girmeyin veya yeni sorular sormayın.
@@ -123,18 +86,11 @@ PROMPT = PromptTemplate(
123
  input_variables=["context", "question"]
124
  )
125
 
126
- # -----------------------------
127
- # 🔗 Gemini LLM (LangChain üzerinden)
128
- # -----------------------------
129
  llm = ChatGoogleGenerativeAI(
130
  model=MODEL_NAME,
131
  google_api_key=GOOGLE_API_KEY
132
  )
133
 
134
- # -----------------------------
135
- # 🔗 LangChain QA Zinciri Kurulumu
136
- # -----------------------------
137
- # LLM ve retriever’ı bağlayarak "Soru-Cevap" zinciri oluşturuyoruz.
138
  qa_chain = RetrievalQA.from_chain_type(
139
  llm=llm,
140
  retriever=retriever,
@@ -143,26 +99,7 @@ qa_chain = RetrievalQA.from_chain_type(
143
  chain_type_kwargs={"prompt": PROMPT}
144
  )
145
 
146
- # -----------------------------
147
- # 🖥️ Streamlit Arayüzü (EğitBot)
148
- # -----------------------------
149
- # Sayfa başlığı, simgesi ve genişlik ayarlandı
150
- st.set_page_config(page_title="📘 EğitBot - Eğitim Asistanı", page_icon="🎓", layout="wide")
151
-
152
- # -----------------------------
153
- # 👤 Oturum Durumu: Sohbet Geçmişi ve İstatistikler Başlatma
154
- # -----------------------------
155
- # Streamlit session_state ile kalıcı sohbet geçmişi ve sayaçları tutuyoruz.
156
- if "chat_history" not in st.session_state:
157
- st.session_state.chat_history = []
158
-
159
- if "total_questions" not in st.session_state:
160
- st.session_state.total_questions = 0
161
-
162
- if "total_answers" not in st.session_state:
163
- st.session_state.total_answers = 0
164
-
165
- # Örnek sorular veri yapısı
166
  EXAMPLE_QUESTIONS = {
167
  "İlkokul": {
168
  "Matematik": [
@@ -256,139 +193,92 @@ EXAMPLE_QUESTIONS = {
256
  }
257
  }
258
 
259
- # -----------------------------
260
- # 📚 Sidebar - İstatistikler, Butonlar ve Örnek Sorular
261
- # -----------------------------
262
- with st.sidebar:
263
- st.title("📚 Örnek Sorular & Kontroller")
264
-
265
- # İstatistikler
266
- st.markdown(f"- Toplam Sorulan Soru: **{st.session_state.get('total_questions', 0)}**")
267
- st.markdown(f"- Toplam Alınan Cevap: **{st.session_state.get('total_answers', 0)}**")
268
- st.markdown("---")
269
-
270
- # "Geçmişi Temizle" butonu, tıklanınca tüm sohbeti ve sayacı sıfırlıyor
271
- if st.button("♻️ Geçmişi Temizle", key="clear_history"):
272
- st.session_state.chat_history = []
273
- st.session_state.total_questions = 0
274
- st.session_state.total_answers = 0
275
-
276
- # Sohbet geçmişini dosya olarak kaydetmek için fonksiyon
277
- def save_chat_history():
278
- now = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
279
- filename = f"chat_history_{now}.txt"
280
- with open(filename, "w", encoding="utf-8") as f:
281
- for sender, msg in st.session_state.get("chat_history", []):
282
- f.write(f"{'Kullanıcı' if sender == 'user' else 'Bot'}: {msg}\n")
283
- return filename
284
-
285
- # "Sohbeti Kaydet" butonuna basıldığında sohbet dosyasını oluşturup indirilebilir yapıyoruz
286
- if st.button("💾 Sohbeti Kaydet", key="save_chat"):
287
- filename = save_chat_history()
288
- with open(filename, "rb") as f:
289
- st.download_button(
290
- label="⬇️ Dosyayı İndir",
291
- data=f,
292
- file_name=filename,
293
- mime="text/plain"
294
- )
295
-
296
- # Örnek sorular için seçimler
297
- grade = st.selectbox("Sınıf Seviyesi Seçiniz:", options=list(EXAMPLE_QUESTIONS.keys()), key="grade_select")
298
- subjects = list(EXAMPLE_QUESTIONS[grade].keys())
299
- subject = st.selectbox("Konu Seçiniz:", options=subjects, key="subject_select")
300
-
301
- # Liste olarak örnek soruları göster
302
- example_questions = EXAMPLE_QUESTIONS[grade][subject]
303
- st.markdown("### Örnek Sorular:")
304
- for idx, question in enumerate(example_questions, 1):
305
- st.markdown(f"{idx}. {question}")
306
-
307
- # Ana sayfa başlığı
308
- st.title("📘 EğitBot - Eğitim Asistanı")
309
-
310
- # Kullanıcının sorusunu al
311
- user_question = st.text_input("Sorunuzu buraya yazınız veya yukarıdaki örnek sorulardan birini yazabilirsiniz:", key="user_question_input")
312
-
313
- # Gönder butonu
314
- if st.button("Gönder", key="send_question"):
315
- if user_question.strip() == "":
316
- st.warning("Lütfen bir soru yazınız veya örnek sorulardan birini kullanınız.")
317
- else:
318
- with st.spinner("Cevap aranıyor..."):
319
- try:
320
- answer = qa_chain.run(user_question)
321
- st.session_state.chat_history.append(("user", user_question))
322
- st.session_state.chat_history.append(("bot", answer))
323
- st.session_state.total_questions += 1
324
- st.session_state.total_answers += 1
325
- except Exception as e:
326
- st.error(f"Cevap alınırken hata oluştu: {e}")
327
-
328
- # Sohbet geçmişi balonlar halinde gösterimi
329
- def render_message(sender, message):
330
- if sender == "user":
331
- color = "#DCF8C6" # Açık yeşil (Kullanıcı için)
332
- align = "flex-end"
333
- border_radius = "15px 15px 0 15px"
334
- else:
335
- color = "#EAEAEA" # Açık gri (Bot için)
336
- align = "flex-start"
337
- border_radius = "15px 15px 15px 0"
338
- st.markdown(
339
- f"""
340
- <div style="
341
- display: flex;
342
- justify-content: {align};
343
- margin: 5px 0;
344
- ">
345
- <div style="
346
- background-color: {color};
347
- padding: 10px 15px;
348
- border-radius: {border_radius};
349
- max-width: 70%;
350
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
351
- ">
352
- {message}
353
- </div>
354
  </div>
355
- """,
356
- unsafe_allow_html=True
357
- )
358
-
359
- if st.session_state.chat_history:
360
- st.markdown("---")
361
- st.subheader("💬 Sohbet Geçmişi")
362
- for sender, message in reversed(st.session_state.chat_history):
363
- if sender == "user":
364
- st.markdown(
365
- f"""
366
- <div style="
367
- background-color: #A3C4F3; /* Soft mavi */
368
- padding: 12px;
369
- border-radius: 15px;
370
- margin: 5px 0px;
371
- max-width: 80%;
372
- color: black; /* Yazı siyah */
373
- ">
374
- <b>Kullanıcı:</b> {message}
375
- </div>
376
- """,
377
- unsafe_allow_html=True
378
- )
379
- else:
380
- st.markdown(
381
- f"""
382
- <div style="
383
- background-color: #8FBC8F; /* Soft yeşil */
384
- padding: 12px;
385
- border-radius: 15px;
386
- margin: 5px 0px;
387
- max-width: 80%;
388
- color: black; /* Yazı siyah */
389
- ">
390
- <b>Bot:</b> {message}
391
- </div>
392
- """,
393
- unsafe_allow_html=True
394
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ import datetime
3
+ import gradio as gr
 
 
 
 
 
 
 
 
 
4
  from datasets import load_dataset
5
  from langchain_huggingface import HuggingFaceEmbeddings
6
  from langchain.text_splitter import TokenTextSplitter
7
  from langchain_community.vectorstores import FAISS
 
8
  from langchain.chains import RetrievalQA
9
  from langchain.prompts import PromptTemplate
10
  from langchain_google_genai import ChatGoogleGenerativeAI
 
11
 
12
+ # Cache klasör ayarları
13
+ os.environ["HF_HOME"] = "./cache"
14
+ os.environ["HF_DATASETS_CACHE"] = "./cache/hf_datasets"
15
+ os.environ["TRANSFORMERS_CACHE"] = "./cache/transformers"
16
+ os.environ["SENTENCE_TRANSFORMERS_HOME"] = "./cache/sentence_transformers"
17
+
18
+ # API anahtarları ortam değişkenlerinden alınmalı
19
  GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
20
  HUGGINGFACEHUB_API_TOKEN = os.getenv("HUGGINGFACEHUB_API_TOKEN")
 
21
  MODEL_NAME = "models/gemini-2.5-pro"
22
 
23
+ # Veri hazırlama fonksiyonu (aynı)
 
 
 
 
 
 
 
 
 
24
  def prepare_retriever():
25
+ dataset_math_word = load_dataset("duxx/orca-math-word-problems-tr", split="train[:2000]")
26
+ dataset_math_hard = load_dataset("Karayel-DDI/Turkce_Lighteval_MATH-Hard", split="train[:2000]")
27
+ dataset_edu = load_dataset("korkmazemin1/turkish-education-dataset", split="train[:2000]")
28
+ dataset_wiki_sum = load_dataset("musabg/wikipedia-tr-summarization", split="train[:2000]")
29
+
30
+ documents = []
31
+ for item in dataset_math_word:
32
+ question = item.get("question", "").strip()
33
+ answer = item.get("answer", "").strip()
34
+ if question and answer:
35
+ documents.append(f"Soru: {question}\nCevap: {answer}")
36
+
37
+ for item in dataset_math_hard:
38
+ question = item.get("question", "").strip()
39
+ answer = item.get("solution", "").strip()
40
+ if question and answer:
41
+ documents.append(f"Soru: {question}\nCevap: {answer}")
42
+
43
+ for item in dataset_edu:
44
+ question = item.get("soru", "").strip()
45
+ answer = item.get("cevap", "").strip()
46
+ if question and answer:
47
+ documents.append(f"Soru: {question}\nCevap: {answer}")
48
+
49
+ for item in dataset_wiki_sum:
50
+ text = item.get("text", "").strip()
51
+ summary = item.get("summary", "").strip()
52
+ if text and summary:
53
+ documents.append(f"Metin: {text}\nÖzet: {summary}")
54
+
55
+ text_splitter = TokenTextSplitter(chunk_size=1000, chunk_overlap=100)
56
+ docs = text_splitter.create_documents(documents)
57
+
58
+ embedding_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
59
+
60
+ FAISS_PATH = "faiss_index"
61
+ if os.path.exists(FAISS_PATH):
62
+ vectorstore = FAISS.load_local(FAISS_PATH, embedding_model, allow_dangerous_deserialization=True)
63
+ else:
64
+ vectorstore = FAISS.from_documents(docs, embedding_model)
65
+ vectorstore.save_local(FAISS_PATH)
66
+
67
+ return vectorstore.as_retriever(search_kwargs={"k": 3})
 
 
 
 
 
 
 
 
 
 
 
68
 
 
 
 
 
69
  retriever = prepare_retriever()
 
 
70
 
 
 
 
 
71
  prompt_template = """
72
  Sadece sorulan soruya net ve kısa cevap ver. Gereksiz ek açıklama yapma.
73
  Sadece yukarıdaki soruya cevap ver. Başka konulara girmeyin veya yeni sorular sormayın.
 
86
  input_variables=["context", "question"]
87
  )
88
 
 
 
 
89
  llm = ChatGoogleGenerativeAI(
90
  model=MODEL_NAME,
91
  google_api_key=GOOGLE_API_KEY
92
  )
93
 
 
 
 
 
94
  qa_chain = RetrievalQA.from_chain_type(
95
  llm=llm,
96
  retriever=retriever,
 
99
  chain_type_kwargs={"prompt": PROMPT}
100
  )
101
 
102
+ # Örnek sorular yapısı
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  EXAMPLE_QUESTIONS = {
104
  "İlkokul": {
105
  "Matematik": [
 
193
  }
194
  }
195
 
196
+ # Fonksiyon: sohbeti cevapla ve geçmişi güncelle
197
+ def respond(user_question, chat_history):
198
+ if not user_question.strip():
199
+ return chat_history, ""
200
+ try:
201
+ answer = qa_chain.run(user_question)
202
+ chat_history = chat_history + [(user_question, answer)]
203
+ except Exception as e:
204
+ answer = f"Hata: {e}"
205
+ return chat_history, ""
206
+
207
+ # Sohbet geçmişini HTML ile biçimlendir
208
+ def format_chat(chat_history):
209
+ chat_html = ""
210
+ for user_q, bot_a in chat_history[-10:]:
211
+ chat_html += f"""
212
+ <div style="background-color:#A3C4F3; padding:10px; border-radius:15px; margin:5px 0; max-width: 80%; color:black;">
213
+ <b>Kullanıcı:</b> {user_q}
214
+ </div>
215
+ <div style="background-color:#8FBC8F; padding:10px; border-radius:15px; margin:5px 0; max-width: 80%; color:black;">
216
+ <b>Bot:</b> {bot_a}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  </div>
218
+ """
219
+ return chat_html
220
+
221
+ # Örnek sorular seçimi için fonksiyon
222
+ def get_subjects(grade):
223
+ return list(EXAMPLE_QUESTIONS[grade].keys())
224
+
225
+ def get_example_questions(grade, subject):
226
+ return EXAMPLE_QUESTIONS[grade][subject]
227
+
228
+ # Sohbet geçmişini dosyaya kaydet
229
+ def save_chat(chat_history):
230
+ now = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
231
+ filename = f"chat_history_{now}.txt"
232
+ with open(filename, "w", encoding="utf-8") as f:
233
+ for user_q, bot_a in chat_history:
234
+ f.write(f"Kullanıcı: {user_q}\nBot: {bot_a}\n\n")
235
+ return filename
236
+
237
+ with gr.Blocks() as demo:
238
+ gr.Markdown("# 📘 EğitBot - Eğitim Asistanı")
239
+
240
+ with gr.Row():
241
+ with gr.Column(scale=3):
242
+ chatbox = gr.HTML(value="", label="Sohbet Geçmişi")
243
+ user_input = gr.Textbox(placeholder="Sorunuzu buraya yazınız...", label="Soru")
244
+ send_btn = gr.Button("Gönder")
245
+
246
+ # Örnek sorular dropdownları
247
+ grade_dropdown = gr.Dropdown(list(EXAMPLE_QUESTIONS.keys()), label="Sınıf Seviyesi")
248
+ subject_dropdown = gr.Dropdown(choices=[], label="Konu")
249
+ example_question_dropdown = gr.Dropdown(choices=[], label="Örnek Sorular")
250
+
251
+ # Seçilen örnek soruyu user_input'a yaz
252
+ def set_example_question(question):
253
+ return question
254
+ example_question_dropdown.change(set_example_question, inputs=example_question_dropdown, outputs=user_input)
255
+
256
+ # Sınıf seçildiğinde konuları güncelle
257
+ def update_subjects(grade):
258
+ return gr.Dropdown.update(choices=get_subjects(grade))
259
+ grade_dropdown.change(update_subjects, inputs=grade_dropdown, outputs=subject_dropdown)
260
+
261
+ # Konu seçildiğinde örnek soruları güncelle
262
+ def update_example_questions(subject, grade):
263
+ if grade is None or subject is None:
264
+ return gr.Dropdown.update(choices=[])
265
+ return gr.Dropdown.update(choices=get_example_questions(grade, subject))
266
+ subject_dropdown.change(update_example_questions, inputs=[subject_dropdown, grade_dropdown], outputs=example_question_dropdown)
267
+
268
+ # Sohbet geçmişi ve temizleme butonu
269
+ clear_btn = gr.Button("♻️ Geçmişi Temizle")
270
+ save_btn = gr.Button("💾 Sohbeti Kaydet")
271
+ download_file = gr.File()
272
+
273
+ with gr.Column(scale=2):
274
+ gr.Markdown("### İstatistikler")
275
+ total_q = gr.Number(value=0, label="Toplam Sorulan Soru", interactive=False)
276
+ total_a = gr.Number(value=0, label="Toplam Alınan Cevap", interactive=False)
277
+
278
+ # State tutuyoruz
279
+ state = gr.State([]) # chat_history listesi
280
+ stats = gr.State({"questions": 0, "answers": 0})
281
+
282
+ # Buton basıldığında sohbeti güncelle
283
+ def on_send(user_question, chat_history, stats):
284
+
requirements.txt CHANGED
@@ -1,5 +1,4 @@
1
- pip
2
- streamlit
3
  python-dotenv
4
  langchain
5
  langchain-community
 
1
+ gradio
 
2
  python-dotenv
3
  langchain
4
  langchain-community