""" Gradio UI wrapper for the Academic Recommendation API """ import gradio as gr import requests import json import subprocess import time import threading # Start FastAPI server in background def start_fastapi(): subprocess.Popen([ "uvicorn", "api_server:app", "--host", "0.0.0.0", "--port", "8000" ]) # Start server in background thread threading.Thread(target=start_fastapi, daemon=True).start() time.sleep(10) # Wait for API to start API_URL = "http://localhost:8000" def get_recommendations(query, top_k=10): """Get recommendations from the API.""" try: response = requests.post( f"{API_URL}/recommend", json={"query": query, "top_k": int(top_k)}, timeout=30 ) if response.status_code == 200: data = response.json() # Format output nicely output = f"**Query:** {data['query']}\n\n" output += f"**Found {data['total_results']} papers** (in {data['execution_time_ms']:.2f}ms)\n\n" output += "---\n\n" for paper in data['recommendations']: output += f"### {paper['rank']}. {paper['title']}\n\n" output += f"**Authors:** {', '.join(paper['metadata']['authors'][:3])}\n\n" output += f"**Year:** {paper['metadata']['published'][:4]} | " output += f"**Citations:** {paper['metadata']['citationCount']} | " output += f"**Category:** {paper['metadata']['primary_category']}\n\n" output += f"**Scores:** Similarity: {paper['scores']['similarity']:.3f}, " output += f"Impact: {paper['scores']['impact_normalized']:.3f}, " output += f"Recency: {paper['scores']['recency']:.3f}\n\n" output += f"**Abstract:** {paper['abstract'][:300]}...\n\n" output += f"[View on arXiv]({paper['metadata']['url']})\n\n" output += "---\n\n" return output else: return f"❌ Error: {response.status_code} - {response.text}" except Exception as e: return f"❌ Error: {str(e)}" def check_health(): """Check API health.""" try: response = requests.get(f"{API_URL}/health", timeout=5) if response.status_code == 200: data = response.json() return f"✅ **Status:** {data['status']}\n**Device:** {data['device']}\n**Corpus loaded:** {data['corpus_loaded']} items" else: return f"❌ API returned status {response.status_code}" except Exception as e: return f"❌ API not responding: {str(e)}" # Create Gradio interface with gr.Blocks(title="Academic Paper Recommender") as demo: gr.Markdown( """ # 📚 Academic Paper Recommendation System LLM-powered recommendation system using SPECTER2 embeddings for semantic search. **Features:** - Semantic similarity matching using SPECTER2 - Multi-signal ranking (relevance + citations + recency) - 6,436 physics papers from arXiv """ ) with gr.Tab("Search Papers"): with gr.Row(): query_input = gr.Textbox( label="Search Query", placeholder="e.g., quantum entanglement, machine learning, gravitational waves", lines=2 ) top_k_input = gr.Slider( minimum=5, maximum=20, value=10, step=1, label="Number of Results" ) search_button = gr.Button("🔍 Search", variant="primary") output = gr.Markdown(label="Results") search_button.click( fn=get_recommendations, inputs=[query_input, top_k_input], outputs=output ) # Examples gr.Examples( examples=[ ["quantum entanglement", 10], ["machine learning neural networks", 10], ["gravitational wave detection", 10], ["topological insulators", 5], ["quantum computing error correction", 10] ], inputs=[query_input, top_k_input] ) with gr.Tab("API Health"): health_button = gr.Button("Check API Status") health_output = gr.Markdown() health_button.click( fn=check_health, outputs=health_output ) # Launch if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)