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("""

🔬 Tool-Calling Akademik Araştırma Asistanı

ArXiv & Semantic Scholar API Entegrasyonlu | SQLite Veritabanı | Bulut LLM Destekli

""") 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") )