Spaces:
Runtime error
Runtime error
| """ | |
| Agentic AI Patterns for Scientific Q&A | |
| A comprehensive comparison of different AI reasoning approaches | |
| """ | |
| import gradio as gr | |
| import asyncio | |
| import json | |
| from agentic_patterns import AgenticPatterns, EXAMPLE_QUESTIONS | |
| import os | |
| # Users must provide their own OpenAI API key | |
| DEFAULT_API_KEY = "" | |
| def get_custom_css(): | |
| """Enhanced CSS for beautiful interface""" | |
| return """ | |
| <style> | |
| /* Root variables for theme support */ | |
| :root { | |
| --primary-color: #2563eb; | |
| --secondary-color: #7c3aed; | |
| --success-color: #059669; | |
| --warning-color: #d97706; | |
| --error-color: #dc2626; | |
| --background-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| --card-background: rgba(255, 255, 255, 0.95); | |
| --text-primary: #1f2937; | |
| --text-secondary: #6b7280; | |
| --border-color: #e5e7eb; | |
| --shadow: 0 10px 25px rgba(0, 0, 0, 0.1); | |
| } | |
| .dark { | |
| --card-background: rgba(17, 24, 39, 0.95); | |
| --text-primary: #f9fafb; | |
| --text-secondary: #d1d5db; | |
| --border-color: #374151; | |
| --shadow: 0 10px 25px rgba(0, 0, 0, 0.3); | |
| } | |
| /* Main container styling */ | |
| .gradio-container { | |
| background: var(--background-gradient) !important; | |
| min-height: 100vh; | |
| font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
| } | |
| /* Header styling */ | |
| .main-header { | |
| text-align: center; | |
| padding: 2rem 1rem; | |
| background: var(--card-background); | |
| border-radius: 20px; | |
| margin: 1rem; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid var(--border-color); | |
| } | |
| .main-title { | |
| font-size: 2.5rem; | |
| font-weight: 800; | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 0.5rem; | |
| color: var(--text-primary); /* Fallback for browsers that don't support background-clip */ | |
| } | |
| /* Dark theme title fix */ | |
| .dark .main-title { | |
| background: linear-gradient(135deg, #60a5fa, #a78bfa); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| color: #f9fafb; /* Fallback for dark theme */ | |
| } | |
| .main-subtitle { | |
| font-size: 1.2rem; | |
| color: var(--text-secondary); | |
| margin-bottom: 1rem; | |
| } | |
| /* Input section styling */ | |
| .input-section { | |
| background: var(--card-background); | |
| border-radius: 15px; | |
| padding: 1.5rem; | |
| margin: 1rem; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid var(--border-color); | |
| } | |
| /* Button grid styling */ | |
| .button-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); | |
| gap: 1rem; | |
| margin: 1rem; | |
| } | |
| /* Individual pattern buttons */ | |
| .pattern-button { | |
| background: var(--card-background); | |
| border-radius: 15px; | |
| padding: 1.5rem; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid var(--border-color); | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| text-align: center; | |
| } | |
| .pattern-button:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15); | |
| } | |
| .pattern-title { | |
| font-size: 1.3rem; | |
| font-weight: 700; | |
| color: var(--text-primary); | |
| margin-bottom: 0.5rem; | |
| } | |
| .pattern-description { | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| margin-bottom: 1rem; | |
| line-height: 1.5; | |
| } | |
| /* Pattern-specific colors */ | |
| .pure-llm { border-left: 4px solid #6b7280; } | |
| .reflection { border-left: 4px solid #3b82f6; } | |
| .planning { border-left: 4px solid #10b981; } | |
| .tool-use { border-left: 4px solid #f59e0b; } | |
| .multi-agent { border-left: 4px solid #8b5cf6; } | |
| .chain-thought { border-left: 4px solid #ef4444; } | |
| .compare-all { border-left: 4px solid #ec4899; } | |
| /* Results styling */ | |
| .result-container { | |
| background: var(--card-background); | |
| border-radius: 15px; | |
| padding: 1.5rem; | |
| margin: 1rem; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid var(--border-color); | |
| } | |
| .result-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1rem; | |
| padding-bottom: 0.5rem; | |
| border-bottom: 2px solid var(--border-color); | |
| } | |
| .result-pattern { | |
| font-size: 1.4rem; | |
| font-weight: 700; | |
| color: var(--primary-color); | |
| } | |
| .result-meta { | |
| display: flex; | |
| gap: 1rem; | |
| font-size: 0.9rem; | |
| color: var(--text-secondary); | |
| } | |
| .result-answer { | |
| line-height: 1.7; | |
| color: var(--text-primary); | |
| margin: 1rem 0; | |
| } | |
| .result-steps { | |
| background: rgba(59, 130, 246, 0.1); | |
| border-radius: 10px; | |
| padding: 1rem; | |
| margin: 1rem 0; | |
| } | |
| .result-sources { | |
| background: rgba(16, 185, 129, 0.1); | |
| border-radius: 10px; | |
| padding: 1rem; | |
| margin: 1rem 0; | |
| } | |
| /* Comparison view styling */ | |
| .comparison-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); | |
| gap: 1rem; | |
| margin: 1rem; | |
| } | |
| .comparison-card { | |
| background: var(--card-background); | |
| border-radius: 12px; | |
| padding: 1rem; | |
| box-shadow: var(--shadow); | |
| border: 1px solid var(--border-color); | |
| } | |
| /* Example questions styling */ | |
| .example-questions { | |
| background: var(--card-background); | |
| border-radius: 15px; | |
| padding: 1rem; | |
| margin: 1rem; | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid var(--border-color); | |
| } | |
| .example-question { | |
| background: rgba(59, 130, 246, 0.1); | |
| border-radius: 8px; | |
| padding: 0.8rem; | |
| margin: 0.5rem 0; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| border-left: 3px solid var(--primary-color); | |
| } | |
| .example-question:hover { | |
| background: rgba(59, 130, 246, 0.2); | |
| transform: translateX(5px); | |
| } | |
| /* Loading animation */ | |
| .loading { | |
| display: inline-block; | |
| width: 20px; | |
| height: 20px; | |
| border: 3px solid rgba(59, 130, 246, 0.3); | |
| border-radius: 50%; | |
| border-top-color: var(--primary-color); | |
| animation: spin 1s ease-in-out infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| /* Responsive design */ | |
| @media (max-width: 768px) { | |
| .button-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .comparison-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .main-title { | |
| font-size: 2rem; | |
| } | |
| } | |
| /* Gradio component overrides */ | |
| .gr-textbox textarea, | |
| .gr-textarea textarea { | |
| background: var(--card-background) !important; | |
| color: var(--text-primary) !important; | |
| border: 1px solid var(--border-color) !important; | |
| border-radius: 10px !important; | |
| } | |
| .gr-button { | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)) !important; | |
| border: none !important; | |
| border-radius: 10px !important; | |
| color: white !important; | |
| font-weight: 600 !important; | |
| transition: all 0.3s ease !important; | |
| } | |
| .gr-button:hover { | |
| transform: translateY(-2px) !important; | |
| box-shadow: 0 8px 20px rgba(37, 99, 235, 0.3) !important; | |
| } | |
| </style> | |
| """ | |
| def create_header(): | |
| """Create the main header""" | |
| return """ | |
| <div class="main-header"> | |
| <h1 class="main-title">π€ Agentic AI Patterns</h1> | |
| <p class="main-subtitle">Compare 5 Advanced AI Reasoning Approaches for Scientific Q&A</p> | |
| <p style="color: var(--text-secondary); font-size: 0.9rem;"> | |
| Powered by OpenAI GPT-4o-mini + OpenAlex Scientific Database | |
| </p> | |
| </div> | |
| """ | |
| def create_pattern_info(): | |
| """Create pattern information cards""" | |
| return """ | |
| <div class="button-grid"> | |
| <div class="pattern-button pure-llm"> | |
| <div class="pattern-title">π€ Pure LLM</div> | |
| <div class="pattern-description">Direct response without any enhancement</div> | |
| </div> | |
| <div class="pattern-button reflection"> | |
| <div class="pattern-title">πͺ Reflection</div> | |
| <div class="pattern-description">Agent reviews and improves its own answer</div> | |
| </div> | |
| <div class="pattern-button planning"> | |
| <div class="pattern-title">π Planning</div> | |
| <div class="pattern-description">Creates and follows a systematic research plan</div> | |
| </div> | |
| <div class="pattern-button tool-use"> | |
| <div class="pattern-title">π§ Tool Use</div> | |
| <div class="pattern-description">Uses OpenAlex to find relevant scientific papers</div> | |
| </div> | |
| <div class="pattern-button multi-agent"> | |
| <div class="pattern-title">π₯ Multi-Agent</div> | |
| <div class="pattern-description">Multiple specialized agents collaborate</div> | |
| </div> | |
| <div class="pattern-button chain-thought"> | |
| <div class="pattern-title">π§ Chain of Thought</div> | |
| <div class="pattern-description">Step-by-step logical reasoning process</div> | |
| </div> | |
| <div class="pattern-button compare-all"> | |
| <div class="pattern-title">βοΈ Compare All</div> | |
| <div class="pattern-description">Run all patterns simultaneously for comparison</div> | |
| </div> | |
| </div> | |
| """ | |
| def fill_example_question(question_index): | |
| """Fill an example question""" | |
| if 0 <= question_index < len(EXAMPLE_QUESTIONS): | |
| return EXAMPLE_QUESTIONS[question_index] | |
| return "" | |
| def format_single_result(result): | |
| """Format a single pattern result""" | |
| if not result: | |
| return "No result available" | |
| pattern = result.get("pattern", "Unknown") | |
| answer = result.get("answer", "No answer provided") | |
| processing_time = result.get("processing_time", "N/A") | |
| confidence = result.get("confidence", "N/A") | |
| steps = result.get("steps", []) | |
| sources = result.get("sources", []) | |
| # Create markdown formatted result | |
| markdown_result = f"""# π€ {pattern} | |
| **β±οΈ Processing Time:** {processing_time} | |
| **π― Confidence:** {confidence} | |
| ## Answer: | |
| {answer} | |
| """ | |
| if steps: | |
| markdown_result += f"\n## π Processing Steps:\n" | |
| for i, step in enumerate(steps, 1): | |
| markdown_result += f"{i}. {step}\n" | |
| if sources: | |
| markdown_result += f"\n## π Sources Found ({len(sources)}):\n" | |
| for i, source in enumerate(sources[:3], 1): # Show first 3 sources | |
| title = source.get('title', 'Unknown Title') | |
| year = source.get('year', 'N/A') | |
| citations = source.get('citations', 0) | |
| markdown_result += f"{i}. **{title}** ({year}) - {citations} citations\n" | |
| return markdown_result | |
| def format_comparison_result(result): | |
| """Format comparison result with all patterns""" | |
| if not result.get("comparison_mode"): | |
| return format_single_result(result) | |
| results = result.get("results", {}) | |
| summary = result.get("summary", {}) | |
| total_time = result.get("total_processing_time", "N/A") | |
| # Create summary | |
| markdown_result = f"""# βοΈ Pattern Comparison Results | |
| **β±οΈ Total Processing Time:** {total_time} | |
| ## π Summary: | |
| - **π Fastest:** {summary.get('fastest', 'N/A')} | |
| - **π― Highest Confidence:** {summary.get('highest_confidence', 'N/A')} | |
| - **π Most Sources:** {summary.get('most_sources', 'N/A')} | |
| --- | |
| """ | |
| # Add individual results | |
| for pattern_name, pattern_result in results.items(): | |
| pattern_result['pattern'] = pattern_name | |
| markdown_result += format_single_result(pattern_result) + "\n---\n\n" | |
| return markdown_result | |
| async def process_question(question, api_key, pattern_type): | |
| """Process question with specified pattern""" | |
| if not question.strip(): | |
| return "β οΈ **Input Required**\n\nPlease enter a scientific question first." | |
| if not api_key.strip(): | |
| return """π **API Key Required** | |
| Please provide your OpenAI API key to use this service. | |
| **How to get an API key:** | |
| 1. Visit [OpenAI Platform](https://platform.openai.com/api-keys) | |
| 2. Sign in to your account | |
| 3. Create a new API key | |
| 4. Copy and paste it in the API key field above""" | |
| try: | |
| patterns = AgenticPatterns(api_key) | |
| if pattern_type == "pure_llm": | |
| result = await patterns.pure_llm(question) | |
| elif pattern_type == "reflection": | |
| result = await patterns.reflection_pattern(question) | |
| elif pattern_type == "planning": | |
| result = await patterns.planning_pattern(question) | |
| elif pattern_type == "tool_use": | |
| result = await patterns.tool_use_pattern(question) | |
| elif pattern_type == "multi_agent": | |
| result = await patterns.multi_agent_pattern(question) | |
| elif pattern_type == "chain_of_thought": | |
| result = await patterns.chain_of_thought_pattern(question) | |
| elif pattern_type == "compare_all": | |
| result = await patterns.run_all_patterns(question) | |
| else: | |
| return "Invalid pattern type." | |
| return format_single_result(result) if pattern_type != "compare_all" else format_comparison_result(result) | |
| except Exception as e: | |
| return f""" | |
| <div class="result-container"> | |
| <div class="result-header"> | |
| <div class="result-pattern">β Error</div> | |
| </div> | |
| <div class="result-answer"> | |
| An error occurred: {str(e)} | |
| <br><br> | |
| Please check your API key and try again. | |
| </div> | |
| </div> | |
| """ | |
| # Create Gradio interface | |
| with gr.Blocks(css=get_custom_css(), title="Agentic AI Patterns", theme=gr.themes.Soft()) as app: | |
| # Header | |
| gr.HTML(create_header()) | |
| # Pattern information | |
| gr.HTML(create_pattern_info()) | |
| # Input section | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| question_input = gr.Textbox( | |
| label="π¬ Scientific Question", | |
| placeholder="Ask any scientific question (e.g., How does CRISPR work?)", | |
| lines=3, | |
| max_lines=5 | |
| ) | |
| with gr.Column(scale=1): | |
| api_key_input = gr.Textbox( | |
| label="π OpenAI API Key (Required)", | |
| placeholder="Enter your OpenAI API key (sk-...)", | |
| type="password", | |
| value=DEFAULT_API_KEY | |
| ) | |
| gr.HTML(""" | |
| <div style="background: rgba(239, 68, 68, 0.1); border: 1px solid #ef4444; border-radius: 8px; padding: 0.8rem; margin-top: 0.5rem;"> | |
| <p style="color: #ef4444; font-size: 0.9rem; margin: 0;"> | |
| β οΈ <strong>API Key Required:</strong> You must provide your own OpenAI API key to use this service. | |
| Get yours at <a href="https://platform.openai.com/api-keys" target="_blank" style="color: #ef4444; text-decoration: underline;">OpenAI Platform</a> | |
| </p> | |
| </div> | |
| """) | |
| # Example questions | |
| gr.HTML("<h3 style='text-align: center; margin: 1rem;'>π‘ Example Questions</h3>") | |
| with gr.Row(): | |
| for i, example in enumerate(EXAMPLE_QUESTIONS): | |
| gr.Button( | |
| f"Example {i+1}: {example[:50]}...", | |
| size="sm" | |
| ).click( | |
| lambda i=i: EXAMPLE_QUESTIONS[i], | |
| outputs=question_input | |
| ) | |
| # Processing buttons | |
| gr.HTML("<h3 style='text-align: center; margin: 2rem 1rem 1rem 1rem;'>π Choose Your AI Pattern</h3>") | |
| with gr.Row(): | |
| pure_llm_btn = gr.Button("π€ Pure LLM", variant="secondary", size="lg") | |
| reflection_btn = gr.Button("πͺ Reflection", variant="secondary", size="lg") | |
| planning_btn = gr.Button("π Planning", variant="secondary", size="lg") | |
| with gr.Row(): | |
| tool_use_btn = gr.Button("π§ Tool Use", variant="secondary", size="lg") | |
| multi_agent_btn = gr.Button("π₯ Multi-Agent", variant="secondary", size="lg") | |
| chain_thought_btn = gr.Button("π§ Chain of Thought", variant="secondary", size="lg") | |
| with gr.Row(): | |
| compare_all_btn = gr.Button("βοΈ Compare All Patterns", variant="primary", size="lg") | |
| # Results section | |
| result_output = gr.Markdown(label="Results") | |
| # Button click handlers | |
| pure_llm_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "pure_llm")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| reflection_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "reflection")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| planning_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "planning")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| tool_use_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "tool_use")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| multi_agent_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "multi_agent")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| chain_thought_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "chain_of_thought")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| compare_all_btn.click( | |
| lambda q, k: asyncio.run(process_question(q, k, "compare_all")), | |
| inputs=[question_input, api_key_input], | |
| outputs=result_output | |
| ) | |
| # Footer | |
| gr.HTML(""" | |
| <div style="text-align: center; margin: 2rem; padding: 1rem; background: var(--card-background); border-radius: 15px; box-shadow: var(--shadow);"> | |
| <p style="color: var(--text-secondary); font-size: 0.9rem;"> | |
| π§ͺ Experiment with different AI reasoning patterns β’ π Powered by OpenAlex scientific database | |
| <br> | |
| Compare how different approaches handle complex scientific questions | |
| </p> | |
| </div> | |
| """) | |
| if __name__ == "__main__": | |
| app.launch(server_name="0.0.0.0", server_port=7860, share=True) | |