|
import streamlit as st
|
|
import torch
|
|
from pinecone import Pinecone
|
|
from transformers import AutoTokenizer, AutoModel
|
|
import time
|
|
import requests
|
|
import json
|
|
|
|
|
|
st.set_page_config(
|
|
page_title="Hukuki Döküman Arama (Detaylı Özet)",
|
|
page_icon="⚖️",
|
|
layout="wide",
|
|
initial_sidebar_state="expanded"
|
|
)
|
|
|
|
|
|
st.title("⚖️ Hukuki Döküman Semantik Arama Detaylı Özet")
|
|
st.markdown("Bu uygulama, 10.000 hukuki dökümanı içeren bir veritabanında semantik arama yapmanızı sağlar.")
|
|
|
|
|
|
@st.cache_resource
|
|
def initialize_pinecone():
|
|
pinecone_client = Pinecone(api_key="pcsk_5s8hcC_2zwJTQthP5PSWE992iXmbRx6ykNQbnEWLhj3fDuR1Cw9eKRn31i2zsRyyCxCmgW")
|
|
return pinecone_client.Index("etikos2")
|
|
|
|
|
|
@st.cache_resource
|
|
def load_model():
|
|
model_name = "intfloat/multilingual-e5-large"
|
|
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
|
model = AutoModel.from_pretrained(model_name)
|
|
|
|
|
|
device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
model = model.to(device)
|
|
|
|
return tokenizer, model, device
|
|
|
|
|
|
def get_query_embedding(query_text, tokenizer, model):
|
|
|
|
prefix = "query: "
|
|
query_text = prefix + query_text
|
|
|
|
|
|
inputs = tokenizer(
|
|
query_text,
|
|
padding=True,
|
|
truncation=True,
|
|
return_tensors="pt",
|
|
max_length=1024
|
|
).to(model.device)
|
|
|
|
|
|
with torch.no_grad():
|
|
model_output = model(**inputs)
|
|
|
|
|
|
attention_mask = inputs['attention_mask']
|
|
token_embeddings = model_output[0]
|
|
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
|
|
embeddings = torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
|
|
|
|
|
|
embeddings = torch.nn.functional.normalize(embeddings, p=2, dim=1)
|
|
|
|
|
|
embedding = embeddings[0].cpu().numpy().tolist()
|
|
return embedding
|
|
|
|
|
|
def get_text_preview(text, max_chars=1000):
|
|
if not text:
|
|
return "İçerik mevcut değil."
|
|
|
|
if len(text) <= max_chars:
|
|
return text
|
|
|
|
return text[:max_chars] + "..."
|
|
|
|
|
|
def process_with_dify(query):
|
|
|
|
dify_api_key = "app-0UV1vRHHnChGssQ2Kc5UK9gg"
|
|
dify_api_endpoint = "https://api.dify.ai/v1/chat-messages"
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {dify_api_key}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
payload = {
|
|
"inputs": {},
|
|
"query": f"{query}",
|
|
"response_mode": "blocking",
|
|
"user": "user"
|
|
}
|
|
|
|
try:
|
|
response = requests.post(dify_api_endpoint, headers=headers, json=payload)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
return data.get("answer", "")
|
|
else:
|
|
st.warning(f"Dify AI ile iletişim kurulurken hata oluştu: {response.status_code}")
|
|
return ""
|
|
except Exception as e:
|
|
st.warning(f"Dify AI işlemi sırasında hata: {str(e)}")
|
|
return ""
|
|
|
|
|
|
st.sidebar.header("Arama Ayarları")
|
|
top_k = st.sidebar.slider("Gösterilecek sonuç sayısı:", 1, 30, 5)
|
|
preview_length = st.sidebar.slider("Ön izleme uzunluğu (karakter):", 500, 3000, 1000)
|
|
use_dify = st.sidebar.checkbox("Dify AI ile sorgu zenginleştirme", value=True)
|
|
|
|
|
|
with st.sidebar:
|
|
st.subheader("Sistem Durumu")
|
|
|
|
with st.status("Pinecone bağlantısı kuruluyor...", expanded=True) as status:
|
|
try:
|
|
index = initialize_pinecone()
|
|
status.update(label="Pinecone bağlantısı kuruldu ✅", state="complete", expanded=False)
|
|
except Exception as e:
|
|
status.update(label=f"Pinecone bağlantı hatası ❌: {str(e)}", state="error", expanded=True)
|
|
st.error("Veritabanına bağlanılamadı. Lütfen daha sonra tekrar deneyin.")
|
|
st.stop()
|
|
|
|
with st.status("Model yükleniyor...", expanded=True) as status:
|
|
try:
|
|
tokenizer, model, device = load_model()
|
|
status.update(label=f"Model yüklendi ✅ ({device.upper()} kullanılıyor)", state="complete", expanded=False)
|
|
except Exception as e:
|
|
status.update(label=f"Model yükleme hatası ❌: {str(e)}", state="error", expanded=True)
|
|
st.error("Model yüklenemedi. Lütfen daha sonra tekrar deneyin.")
|
|
st.stop()
|
|
|
|
|
|
query = st.text_area("Aramak istediğiniz konuyu yazın:", height=100,
|
|
placeholder="Örnek: Mülkiyet hakkı ile ilgili davalar")
|
|
|
|
|
|
search_button = st.button("🔍 Ara", type="primary", use_container_width=True)
|
|
|
|
|
|
if search_button and query:
|
|
enhanced_query = query
|
|
|
|
|
|
if use_dify:
|
|
with st.spinner("Sorgunuz Dify AI ile analiz ediliyor..."):
|
|
dify_output = process_with_dify(query)
|
|
|
|
if dify_output:
|
|
|
|
enhanced_query = f"{query} {dify_output}"
|
|
|
|
|
|
with st.expander("Zenginleştirilmiş Sorgu", expanded=False):
|
|
st.write("Orijinal sorgu:")
|
|
st.info(query)
|
|
st.write("Dify AI ile zenginleştirilmiş sorgu:")
|
|
st.info(dify_output)
|
|
st.write("Birleştirilmiş sorgu:")
|
|
st.success(enhanced_query)
|
|
|
|
|
|
with st.spinner("Arama yapılıyor..."):
|
|
try:
|
|
|
|
start_time = time.time()
|
|
query_embedding = get_query_embedding(enhanced_query, tokenizer, model)
|
|
|
|
|
|
search_results = index.query(
|
|
vector=query_embedding,
|
|
top_k=top_k,
|
|
include_metadata=True
|
|
)
|
|
|
|
elapsed_time = time.time() - start_time
|
|
|
|
|
|
st.success(f"Arama tamamlandı! ({elapsed_time:.2f} saniye)")
|
|
|
|
if not search_results.matches:
|
|
st.info("Aramanıza uygun sonuç bulunamadı.")
|
|
else:
|
|
st.subheader(f"Arama Sonuçları ({len(search_results.matches)} döküman)")
|
|
|
|
|
|
for i, match in enumerate(search_results.matches):
|
|
with st.container():
|
|
col1, col2 = st.columns([4, 1])
|
|
|
|
with col1:
|
|
st.markdown(f"### {i+1}. {match.metadata.get('daire', 'Bilinmeyen Daire')}")
|
|
|
|
with col2:
|
|
st.metric(label="Benzerlik", value=f"{match.score*100:.1f}%")
|
|
|
|
st.markdown("**Döküman Bilgileri:**")
|
|
st.markdown(f"""
|
|
- **Karar No:** {match.metadata.get('karar_no', 'Belirtilmemiş')}
|
|
- **Esas No:** {match.metadata.get('esas_no', 'Belirtilmemiş')}
|
|
- **Tarih:** {match.metadata.get('tarih', 'Belirtilmemiş')}
|
|
""")
|
|
|
|
|
|
text_content = match.metadata.get('text', match.metadata.get('text_snippet', ''))
|
|
|
|
|
|
with st.expander("Döküman İçeriği", expanded=True):
|
|
st.markdown(get_text_preview(text_content, preview_length))
|
|
|
|
|
|
if text_content:
|
|
st.download_button(
|
|
label="Tam Metni İndir",
|
|
data=text_content,
|
|
file_name=f"karar_{match.metadata.get('karar_no', 'bilinmeyen')}.txt",
|
|
mime="text/plain"
|
|
)
|
|
|
|
st.divider()
|
|
|
|
except Exception as e:
|
|
st.error(f"Arama sırasında bir hata oluştu: {str(e)}")
|
|
|
|
|
|
st.sidebar.markdown("---")
|
|
st.sidebar.caption("© 2023 Hukuki Döküman Arama") |