nguyenthanhasia's picture
Upload app.py with huggingface_hub
fd9fbc6 verified
"""
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)