import gradio as gr from pathlib import Path import base64 # Basic paths ROOT = Path(__file__).resolve().parent # Hardcoded logo as base64 (cannot be downloaded) LOGO_BASE64 = None try: with open(ROOT / "paper2agent_logo.txt", "rb") as f: LOGO_BASE64 = f.read().decode() except: pass # ===================== # Gradio UI Layout Only # ===================== with gr.Blocks(title="Paper2Agent") as iface: # Logo at top left (hardcoded, cannot be downloaded) if LOGO_BASE64: gr.HTML(f'') gr.Markdown(""" [Paper](https://arxiv.org/abs/2509.06917) | [GitHub](https://github.com/jmiao24/Paper2Agent) **TL;DR:** Upload your paper code repo and get an auto-generated mcp. Please be patient โ€” takes about 20โ€“30 minutes to process. """, elem_id="intro-md") # -------- Input/Output Layout -------- with gr.Row(): # ========== LEFT: INPUT ========== with gr.Column(scale=1): with gr.Accordion("Input", open=True): github_in = gr.Textbox( label="๐Ÿ“˜ GitHub Repo URL", placeholder="https://github.com/google-deepmind/alphagenome" ) key_in = gr.Textbox( label="๐Ÿ”‘ Claude API Key", placeholder="sk-ant-...", type="password" ) repo_key_in = gr.Textbox( label="๐Ÿ” API Key (optional, for repositories requiring authentication)", placeholder="Enter API key for private repositories", type="password" ) tutorials_in = gr.Textbox( label="๐Ÿ“š Tutorials (optional)", placeholder="Filter tutorials by title or URL" ) run_btn = gr.Button("๐Ÿš€ Run", variant="primary") example_btn = gr.Button("๐Ÿ“ Use Example Values", variant="secondary") # Example values info gr.Markdown("""
๐Ÿ’ก Example Values
GitHub URL:
https://github.com/google-deepmind/alphagenome
Claude API Key:
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
Repo API Key:
AIzaSyDZ-IxStzMSUElDGWS7U9v6BIDr_0WMoO8
""", elem_id="example-section") # ========== RIGHT: OUTPUT ========== with gr.Column(scale=1): with gr.Accordion("Output", open=True): # Logs with scrolling enabled logs_out = gr.Textbox( label="๐Ÿงพ Logs", lines=20, max_lines=20, autoscroll=False ) # Downloads with gr.Row(): zip_out = gr.File( label="๐Ÿ“ฆ Download Results (.zip)", interactive=False, visible=True, scale=1 ) overleaf_out = gr.HTML(label="Open in Overleaf") # Fill example values def fill_example(): return ( "https://github.com/google-deepmind/alphagenome", "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", "AIzaSyDZ-IxStzMSUElDGWS7U9v6BIDr_0WMoO8", "" ) # Button click handler def run_pipeline(github_url, repo_api_key, claude_api_key, tutorials_filter): """ Run the Paper2Agent pipeline with the provided inputs. """ import subprocess import os ui_logs = [] # Simplified logs for UI try: # Validate inputs if not github_url or not github_url.strip(): ui_logs.append("โŒ Error: GitHub Repo URL is required") return "\n".join(ui_logs), None, "" if not claude_api_key or not claude_api_key.strip(): ui_logs.append("โŒ Error: Claude API Key is required") return "\n".join(ui_logs), None, "" # Create Results folder results_path = ROOT / "Results" results_path.mkdir(parents=True, exist_ok=True) ui_logs.append(f"๐Ÿš€ Starting Paper2Agent pipeline...") ui_logs.append(f"๐Ÿ“˜ GitHub Repo: {github_url}") ui_logs.append(f"๐Ÿ”‘ Claude API Key: {'*' * (len(claude_api_key) - 4)}{claude_api_key[-4:]}") if tutorials_filter: ui_logs.append(f"๐Ÿ“š Tutorial Filter: {tutorials_filter}") ui_logs.append(f"\n๐Ÿ“ Detailed logs will be saved to: Results/log.log") ui_logs.append("\n" + "="*70) yield "\n".join(ui_logs), None, "" # Set environment variable for Claude API key (for SDK initialization) env = os.environ.copy() env['ANTHROPIC_API_KEY'] = claude_api_key env['PYTHONUNBUFFERED'] = '1' # Build command with unbuffered Python cmd = [ "python", "-u", "test.py", "--github_url", github_url ] # Add repo API key if provided (for repository authentication) if repo_api_key and repo_api_key.strip(): cmd.extend(["--api", repo_api_key]) if tutorials_filter and tutorials_filter.strip(): cmd.extend(["--tutorials", tutorials_filter]) # Run test.py and capture stdout for UI process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=0, env=env ) # Stream output to UI for line in iter(process.stdout.readline, ''): if line: stripped_line = line.strip() if stripped_line: ui_logs.append(stripped_line) yield "\n".join(ui_logs), None, "" process.wait() if process.returncode == 0: ui_logs.append("\n" + "="*70) ui_logs.append("โœ… Pipeline completed successfully!") ui_logs.append("="*70) # Create zip file from Results folder zip_file = None ui_logs.append("\n๐Ÿ“ฆ Creating zip archive from Results folder...") if results_path.exists(): import shutil # Create zip file with timestamp zip_base_name = f"Results" zip_file_path = ROOT / zip_base_name try: # Create zip archive of the entire Results folder shutil.make_archive( str(zip_file_path), 'zip', ROOT, 'Results' ) zip_file = str(zip_file_path) + ".zip" ui_logs.append(f"โœ… Created zip file: {zip_file}") ui_logs.append(f"๐Ÿ“ฅ Ready for download!") ui_logs.append(f"\n๐Ÿ“ Full logs saved to: Results/log.log") yield "\n".join(ui_logs), zip_file, "" except Exception as e: ui_logs.append(f"โš ๏ธ Failed to create zip file: {str(e)}") yield "\n".join(ui_logs), None, "" else: ui_logs.append(f"โš ๏ธ Results folder not found at: {results_path}") yield "\n".join(ui_logs), None, "" else: ui_logs.append("\n" + "="*70) ui_logs.append(f"โŒ Pipeline failed with exit code {process.returncode}") ui_logs.append(f"๐Ÿ“ Check logs for details: Results/log.log") ui_logs.append("="*70) yield "\n".join(ui_logs), None, "" except Exception as e: ui_logs.append(f"\nโŒ Error: {str(e)}") ui_logs.append(f"๐Ÿ“ Check logs for details: Results/log.log") yield "\n".join(ui_logs), None, "" # Connect example button example_btn.click( fn=fill_example, inputs=[], outputs=[github_in, key_in, repo_key_in, tutorials_in] ) # Connect run button run_btn.click( fn=run_pipeline, inputs=[github_in, repo_key_in, key_in, tutorials_in], outputs=[logs_out, zip_out, overleaf_out] ) if __name__ == "__main__": iface.launch(server_name="0.0.0.0", server_port=7860)