|
|
|
|
|
import os |
|
|
import shutil |
|
|
import textwrap |
|
|
import streamlit as st |
|
|
from huggingface_hub import hf_hub_download |
|
|
|
|
|
from rag_pipeline import ( |
|
|
load_vectorstore, |
|
|
search_chunks, |
|
|
generate_answer, |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VSTORE_DIR = "./vectorstore" |
|
|
NEEDED = ["index.faiss", "meta.jsonl"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ensure_vectorstore(vstore_dir: str = VSTORE_DIR) -> None: |
|
|
os.makedirs(vstore_dir, exist_ok=True) |
|
|
|
|
|
missing = [f for f in NEEDED if not os.path.exists(os.path.join(vstore_dir, f))] |
|
|
if not missing: |
|
|
return |
|
|
|
|
|
|
|
|
space_id = os.getenv("SPACE_ID") |
|
|
if not space_id: |
|
|
|
|
|
|
|
|
return |
|
|
|
|
|
for fname in missing: |
|
|
repo_path = f"vectorstore/{fname}" |
|
|
try: |
|
|
downloaded = hf_hub_download( |
|
|
repo_id=space_id, |
|
|
filename=repo_path, |
|
|
repo_type="space", |
|
|
) |
|
|
shutil.copyfile(downloaded, os.path.join(vstore_dir, fname)) |
|
|
except Exception as e: |
|
|
|
|
|
raise FileNotFoundError( |
|
|
f"'{repo_path}' indirilemedi veya bulunamadı. " |
|
|
f"Lütfen bu dosyayı Space deposunda 'vectorstore/' klasörüne yükleyin." |
|
|
) from e |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.set_page_config( |
|
|
page_title="Turkish Wikipedia Q&A (Gemini RAG)", |
|
|
page_icon="🧠", |
|
|
layout="centered", |
|
|
) |
|
|
|
|
|
@st.cache_resource(show_spinner=False) |
|
|
def _load_vdb(): |
|
|
|
|
|
ensure_vectorstore(VSTORE_DIR) |
|
|
|
|
|
return load_vectorstore(VSTORE_DIR) |
|
|
|
|
|
st.title("🧠 Turkish Wikipedia Q&A") |
|
|
|
|
|
with st.expander("⚙️ Ayarlar", expanded=False): |
|
|
top_k = st.slider("Top K (kaç pasaj getirilsin?)", 2, 8, 5) |
|
|
show_passages = st.checkbox("Getirilen pasaj özetini göster", value=True) |
|
|
has_gemini = bool(os.getenv("GOOGLE_API_KEY") or st.secrets.get("GOOGLE_API_KEY", None)) |
|
|
st.info(f"LLM: {'Gemini ✅' if has_gemini else 'Yapılandırılmadı ❌'}") |
|
|
|
|
|
query = st.text_input("📝 Sorunuzu yazın (ör. “Türkiye'nin ilk kadın pilotu kimdir?”)") |
|
|
|
|
|
if st.button("Cevabı Getir", type="primary", use_container_width=True) and query.strip(): |
|
|
try: |
|
|
with st.spinner("Aranıyor ve cevap oluşturuluyor..."): |
|
|
index, records = _load_vdb() |
|
|
answer = generate_answer(query.strip(), index, records, top_k=top_k) |
|
|
hits = search_chunks(query.strip(), index, records, top_k=top_k) |
|
|
|
|
|
st.subheader("✅ Yanıt") |
|
|
st.write(answer if answer else "_Cevap üretilemedi._") |
|
|
|
|
|
st.subheader("🔎 Kaynaklar") |
|
|
if hits: |
|
|
for i, h in enumerate(hits, 1): |
|
|
title = h.get("title") or "(başlık yok)" |
|
|
url = h.get("source") or "" |
|
|
score = float(h.get("score_rerank", h.get("score_boosted", 0.0))) |
|
|
lead = textwrap.shorten((h.get("text") or "").replace("\n", " "), width=220, placeholder="…") |
|
|
|
|
|
if url: |
|
|
st.markdown(f"**{i}.** [{title}]({url}) \nRerank skoru: `{score:.3f}`") |
|
|
else: |
|
|
st.markdown(f"**{i}.** {title} \nRerank skoru: `{score:.3f}`") |
|
|
|
|
|
if show_passages and lead: |
|
|
st.caption(lead) |
|
|
st.markdown("---") |
|
|
else: |
|
|
st.write("_Kaynak bulunamadı._") |
|
|
|
|
|
except FileNotFoundError as e: |
|
|
st.error( |
|
|
"Vektör deposu bulunamadı. `vectorstore/index.faiss` ve `vectorstore/meta.jsonl` " |
|
|
"dosyalarının Space'in kökünde `vectorstore/` klasöründe olduğundan emin olun." |
|
|
) |
|
|
st.code(str(e)) |
|
|
except Exception as e: |
|
|
st.error("Bir hata oluştu.") |
|
|
st.exception(e) |