import gradio as gr
import json
import pandas as pd
from typing import List, Any
import database
import agent
import config
import spaces
database.init_db()
@spaces.GPU(duration=5)
def _dummy_gpu_warmup():
return True
def handle_chat_submit(user_message: str, history: List[Any], api_key: str, provider: str, model: str):
"""Sohbet girdisini işler ve Gradio 5/6 'messages' formatında yanıt ile logları günceller."""
if history is None:
history = []
if not user_message.strip():
return "", history, "", get_library_dataframe()
chat_history_dicts = []
for item in history:
if isinstance(item, dict):
role = str(item.get("role", "user"))
raw_content = item.get("content", "")
if isinstance(raw_content, list):
text_parts = []
for part in raw_content:
if isinstance(part, dict) and "text" in part:
text_parts.append(str(part["text"]))
elif hasattr(part, "text"):
text_parts.append(str(part.text))
else:
text_parts.append(str(part))
content_str = "\n".join(text_parts)
else:
content_str = str(raw_content)
if role in ["user", "assistant"] and content_str.strip():
chat_history_dicts.append({"role": role, "content": content_str})
elif isinstance(item, (list, tuple)) and len(item) == 2:
u_msg, b_msg = item
if u_msg:
chat_history_dicts.append({"role": "user", "content": str(u_msg)})
if b_msg:
chat_history_dicts.append({"role": "assistant", "content": str(b_msg)})
response_text, logs = agent.process_user_query(
user_message=user_message,
chat_history=chat_history_dicts,
api_key=api_key,
provider=provider,
model_name=model
)
updated_history = []
for msg in chat_history_dicts:
updated_history.append({"role": msg["role"], "content": str(msg["content"])})
updated_history.append({"role": "user", "content": str(user_message)})
updated_history.append({"role": "assistant", "content": str(response_text or "")})
logs_formatted = json.dumps(logs, indent=2, ensure_ascii=False)
df_lib = get_library_dataframe()
return "", updated_history, logs_formatted, df_lib
def get_library_dataframe(status_filter: str = "hepsi", query: str = ""):
"""SQLite veritabanındaki makaleleri Pandas DataFrame olarak döner."""
papers = database.get_saved_papers(status_filter=status_filter, query=query)
if not papers:
return pd.DataFrame(columns=["ID", "Makale Kimliği", "Başlık", "Yazarlar", "Yıl", "Durum", "Notlar", "Etiketler", "Kaynak"])
df = pd.DataFrame(papers)
cols_map = {
"id": "ID",
"paper_id": "Makale Kimliği",
"title": "Başlık",
"authors": "Yazarlar",
"published_year": "Yıl",
"status": "Durum",
"notes": "Notlar",
"tags": "Etiketler",
"source": "Kaynak",
"url": "Bağlantı"
}
df = df.rename(columns=cols_map)
existing_cols = [c for c in ["ID", "Makale Kimliği", "Başlık", "Yazarlar", "Yıl", "Durum", "Notlar", "Etiketler", "Kaynak", "Bağlantı"] if c in df.columns]
return df[existing_cols]
def clear_execution_logs():
agent.EXECUTION_LOGS.clear()
return "[]"
custom_css = """
.container { max-width: 1200px; margin: 0 auto; }
.header-box { text-align: center; padding: 20px; background: linear-gradient(135deg, #1e293b, #0f172a); border-radius: 12px; margin-bottom: 20px; color: white; }
.header-box h1 { font-size: 2.2rem; font-weight: 700; margin-bottom: 8px; color: #38bdf8; }
.header-box p { font-size: 1.05rem; opacity: 0.9; }
.log-box textarea { font-family: 'Courier New', Courier, monospace; font-size: 0.85rem; background-color: #0d1117; color: #7ee787; }
"""
with gr.Blocks(title="Tool-Calling Akademik Araştırma Asistanı") as demo:
with gr.Column(elem_classes="container"):
gr.HTML("""
""")
with gr.Tabs() as tabs:
with gr.TabItem("💬 Akademik Asistan", id=0):
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(height=480)
with gr.Row():
msg_input = gr.Textbox(
placeholder="Örn: 'Quantum machine learning alanındaki makaleleri ara' veya 'Kütüphanemdeki makaleleri göster'...",
show_label=False,
scale=8
)
send_btn = gr.Button("Gönder 🚀", variant="primary", scale=2)
clear_btn = gr.Button("Temizle 🗑️", scale=1)
gr.Markdown("### 💡 Örnek Hızlı Sorular")
with gr.Row():
ex1 = gr.Button("🔍 'LLM Tool Calling' makalelerini ara")
ex2 = gr.Button("📚 Kayıtlı kütüphanemi getir")
ex3 = gr.Button("💾 Örnek makaleyi kütüphaneme ekle")
ex4 = gr.Button("📝 Makale okuma durumunu 'completed' yap")
with gr.Column(scale=2):
gr.Markdown("### ⚡ Anlık Tool-Call Tetiklenme Özeti")
quick_log_view = gr.Code(
label="Son Fonksiyon Çağrısı (Tool Call Output)",
language="json",
value="[]",
lines=18
)
with gr.TabItem("📊 Tool-Call Canlı Loglar", id=1):
gr.Markdown("""
### 🛠️ Arka Plan Fonksiyon Çağrı (Tool-Call) Logları
Bu panel, dil modelinin kullanıcı isteği doğrultusunda **hangi fonksiyonları çağırdığını**,
gönderilen **parametreleri** ve dış API/SQLite veritabanından dönen **gerçek JSON çıktılarını** anlık gösterir.
*(Ödev teslimindeki ekran görüntüsü gereksinimi için burayı kullanabilirsiniz).*
""")
full_log_view = gr.Code(
label="Tüm Fonksiyon Çağrı Geçmişi (Full JSON Trace Log)",
language="json",
value="[]",
lines=20
)
clear_log_btn = gr.Button("Logları Temizle", variant="secondary")
with gr.TabItem("📚 Kişisel Kütüphanem (SQLite DB)", id=2):
gr.Markdown("### 🗄️ SQLite Veritabanı Canlı Makale Tablosu (`academic_library.db`)")
with gr.Row():
status_filter_ui = gr.Dropdown(
choices=["hepsi", "unread", "reading", "completed"],
value="hepsi",
label="Durum Filtresi"
)
search_query_ui = gr.Textbox(placeholder="Tablo içinde ara...", label="Arama")
refresh_db_btn = gr.Button("🔄 Tabloyu Yenile", variant="secondary")
library_table = gr.Dataframe(
value=get_library_dataframe(),
interactive=False,
wrap=True
)
with gr.TabItem("⚙️ Model & Cloud API Ayarları", id=3):
gr.Markdown("""
### ☁️ Bulut LLM ve API Yapılandırması
Yerel bilgisayarınıza **hiçbir ağırlık veya model dosyası indirmenize gerek yoktur**.
Ücretsiz Groq, OpenRouter, OpenAI API anahtarınızı girebilir veya varsayılan akıllı yönlendiriciyi kullanabilirsiniz.
""")
with gr.Row():
provider_dropdown = gr.Dropdown(
choices=["Groq", "OpenRouter", "Ollama (Remote/Local)", "OpenAI"],
value=config.DEFAULT_PROVIDER,
label="Model Sağlayıcı (Provider)"
)
model_input = gr.Textbox(
value=config.DEFAULT_MODEL,
label="Model Adı (Model Name)"
)
api_key_input = gr.Textbox(
type="password",
label="API Anahtarı (Groq / OpenRouter / OpenAI API Key)",
placeholder="gsk_... veya sk-or-v1-..."
)
gr.Markdown("💡 **İpucu:** Groq API anahtarı tamamen ücretsizdir ve çok hızlı Tool-Calling desteği sunar (groq.com adresinden 1 dakikada alınabilir). API Key girilmediğinde sistem otomatik akıllı Tool-Call yönlendiricisini çalıştırır.")
msg_input.submit(
handle_chat_submit,
inputs=[msg_input, chatbot, api_key_input, provider_dropdown, model_input],
outputs=[msg_input, chatbot, quick_log_view, library_table]
).then(
lambda logs: logs, inputs=[quick_log_view], outputs=[full_log_view]
)
send_btn.click(
handle_chat_submit,
inputs=[msg_input, chatbot, api_key_input, provider_dropdown, model_input],
outputs=[msg_input, chatbot, quick_log_view, library_table]
).then(
lambda logs: logs, inputs=[quick_log_view], outputs=[full_log_view]
)
clear_btn.click(lambda: ([], "[]"), None, [chatbot, quick_log_view])
clear_log_btn.click(clear_execution_logs, None, [full_log_view])
refresh_db_btn.click(get_library_dataframe, inputs=[status_filter_ui, search_query_ui], outputs=[library_table])
status_filter_ui.change(get_library_dataframe, inputs=[status_filter_ui, search_query_ui], outputs=[library_table])
search_query_ui.change(get_library_dataframe, inputs=[status_filter_ui, search_query_ui], outputs=[library_table])
ex1.click(lambda: "LLM Tool Calling alanındaki makaleleri ara", None, msg_input)
ex2.click(lambda: "Kütüphanemdeki kayıtlı makaleleri listele", None, msg_input)
ex3.click(lambda: "Arama sonucunda bulunan makaleyi kütüphaneme kaydet", None, msg_input)
ex4.click(lambda: "Kütüphanemdeki makalenin durumunu 'completed' olarak güncelle", None, msg_input)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
css=custom_css,
theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="cyan")
)