Research_Forge / app.py
Amna2568's picture
Clean folder structure, main app in root
457df67
import streamlit as st
import asyncio
import pandas as pd
from typing import List
import os
import json
from datetime import datetime
from dotenv import load_dotenv
from multi_agent_system import MultiAgentSystem, SearchResult
from paper_writer import ResearchPaperWriter
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
import io
# Load environment variables
load_dotenv()
# Configure page settings
st.set_page_config(
page_title="Research Assistant",
page_icon="πŸ”",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS for improved UI
st.markdown("""
<style>
/* Main app styling */
.main {
background-color: #0E1117;
}
/* Headers */
h1 {
color: #FFFFFF !important;
font-family: 'Segoe UI', sans-serif;
font-weight: 700;
letter-spacing: -0.5px;
padding-bottom: 10px;
}
h2 {
color: #E0E0E0 !important;
font-family: 'Segoe UI', sans-serif;
font-weight: 600;
padding-top: 20px;
padding-bottom: 10px;
}
h3 {
color: #B0B0B0 !important;
font-family: 'Segoe UI', sans-serif;
font-weight: 500;
}
/* Paragraphs and text */
p, li {
font-size: 15px;
line-height: 1.7;
color: #D0D0D0;
}
/* Buttons */
.stButton>button {
border-radius: 8px;
font-weight: 600;
font-size: 16px;
padding: 12px 24px;
transition: all 0.3s ease;
border: none;
}
.stButton>button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(103, 126, 234, 0.4);
}
/* Input fields */
.stTextInput>div>div>input {
border-radius: 8px;
border: 2px solid #667eea;
padding: 12px;
font-size: 15px;
background-color: #1E1E1E;
color: #FFFFFF;
}
.stTextInput>div>div>input:focus {
border-color: #764ba2;
box-shadow: 0 0 0 2px rgba(118, 75, 162, 0.2);
}
/* Metrics */
[data-testid="stMetricValue"] {
font-size: 28px;
font-weight: 700;
color: #667eea;
}
[data-testid="stMetricLabel"] {
font-size: 14px;
font-weight: 500;
color: #B0B0B0;
}
/* Tabs */
.stTabs [data-baseweb="tab-list"] {
gap: 8px;
background-color: #1A1A1A;
padding: 10px;
border-radius: 10px;
}
.stTabs [data-baseweb="tab"] {
border-radius: 8px;
padding: 12px 20px;
font-weight: 600;
font-size: 15px;
background-color: #2A2A2A;
color: #B0B0B0;
}
.stTabs [aria-selected="true"] {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
/* Expanders */
.streamlit-expanderHeader {
background-color: #1E1E1E;
border-radius: 8px;
font-weight: 600;
color: #E0E0E0;
border-left: 4px solid #667eea;
}
.streamlit-expanderHeader:hover {
background-color: #2A2A2A;
}
/* Dataframes */
.dataframe {
border-radius: 8px;
overflow: hidden;
}
/* Progress bar */
.stProgress > div > div > div > div {
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
}
/* Success/Info/Warning/Error boxes */
.stSuccess, .stInfo, .stWarning, .stError {
border-radius: 8px;
padding: 15px;
border-left: 4px solid;
}
/* Sidebar */
section[data-testid="stSidebar"] {
background-color: #0A0A0A;
}
/* Download buttons */
.stDownloadButton>button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
}
/* Dividers */
hr {
border-color: #2A2A2A;
margin: 30px 0;
}
</style>
""", unsafe_allow_html=True)
def init_session_state():
"""Initialize session state variables"""
if 'search_history' not in st.session_state:
st.session_state.search_history = []
if 'analysis_progress' not in st.session_state:
st.session_state.analysis_progress = 0
def get_score_badge(score, label):
"""Generate color-coded badge for scores"""
try:
score_val = float(score)
if score_val >= 8:
color = "#00C853" # Green
emoji = "🟒"
elif score_val >= 6:
color = "#FFA726" # Orange
emoji = "🟑"
else:
color = "#EF5350" # Red
emoji = "πŸ”΄"
return f"""
<div style="display: inline-block; background-color: {color}; color: white; padding: 5px 12px;
border-radius: 15px; margin: 3px; font-weight: bold; font-size: 14px;">
{emoji} {label}: {score_val:.1f}/10
</div>
"""
except:
return f"<span>{label}: {score}</span>"
def parse_literature_review(review_text):
"""Parse literature review into collapsible sections"""
sections = {}
current_section = "Introduction"
current_content = []
lines = review_text.split('\n')
for line in lines:
# Detect section headers
if line.startswith('##'):
# Save previous section
if current_content:
sections[current_section] = '\n'.join(current_content)
# Start new section
current_section = line.replace('#', '').strip()
current_content = []
else:
current_content.append(line)
# Save last section
if current_content:
sections[current_section] = '\n'.join(current_content)
return sections if sections else {"Full Review": review_text}
def convert_markdown_to_docx(markdown_text: str, title: str = "Research Paper") -> bytes:
"""Convert markdown text to Word document (.docx) format"""
try:
doc = Document()
# Set document margins
sections = doc.sections
for section in sections:
section.top_margin = Inches(1)
section.bottom_margin = Inches(1)
section.left_margin = Inches(1)
section.right_margin = Inches(1)
# Split markdown into lines
lines = markdown_text.split('\n')
for line in lines:
line = line.strip()
if not line:
continue
# Handle headers
if line.startswith('# '):
# Title (H1)
p = doc.add_heading(line[2:], level=1)
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
elif line.startswith('## '):
# Section (H2)
doc.add_heading(line[3:], level=2)
elif line.startswith('### '):
# Subsection (H3)
doc.add_heading(line[4:], level=3)
elif line.startswith('#### '):
# Sub-subsection (H4)
doc.add_heading(line[5:], level=4)
elif line.startswith('- ') or line.startswith('* '):
# Bullet point
doc.add_paragraph(line[2:], style='List Bullet')
elif line.startswith('> '):
# Block quote
p = doc.add_paragraph(line[2:])
p.style = 'Intense Quote'
else:
# Regular paragraph
doc.add_paragraph(line)
# Save to bytes
doc_bytes = io.BytesIO()
doc.save(doc_bytes)
doc_bytes.seek(0)
return doc_bytes.getvalue()
except Exception as e:
st.error(f"Error converting to Word: {str(e)}")
return None
async def run_async_operations(system, search_query, max_results=3):
"""Handle async complete analysis operation"""
# Always run full pipeline: Paper Collection β†’ Literature Review β†’ Gap Analysis β†’ Hypothesis Generation
complete_results = await system.run_complete_analysis(search_query)
return {"type": "complete", "data": complete_results}
def main():
"""Main application function"""
st.markdown("""
<div style="text-align: center; padding: 30px 20px; margin-bottom: 20px;
background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
border-radius: 12px; border: 1px solid rgba(255,255,255,0.1);">
<h1 style="font-size: 42px; margin-bottom: 8px; color: #ffffff; font-weight: 700; letter-spacing: 0.5px;">
ResearchForge
</h1>
<p style="font-size: 16px; color: #a0aec0; font-weight: 500; margin-bottom: 15px;">
Autonomous AI Research Assistant
</p>
<p style="font-size: 14px; color: #cbd5e0; font-weight: 400; line-height: 1.8;">
Automated Literature Review β€’ Gap Analysis β€’ Hypothesis Generation<br/>
Experiment Design β€’ Dataset Recommendations β€’ AI Research Paper Writer
</p>
</div>
""", unsafe_allow_html=True)
init_session_state()
if 'system' not in st.session_state:
with st.spinner("πŸ”„ Initializing Research Assistant... Please wait..."):
st.session_state.system = MultiAgentSystem()
st.success("βœ… System initialized! Models will load when needed.")
system = st.session_state.system
# Sidebar configuration
with st.sidebar:
st.markdown("""
<div style="background: linear-gradient(135deg, #2c5364 0%, #203a43 100%);
padding: 18px; border-radius: 8px; margin-bottom: 20px; border: 1px solid rgba(255,255,255,0.1);">
<h2 style="color: white; margin: 0; text-align: center; font-size: 20px; font-weight: 600;">Configuration</h2>
</div>
""", unsafe_allow_html=True)
st.markdown("### Analysis Pipeline")
st.markdown("""
<div style="background-color: #1e293b; padding: 15px; border-radius: 8px; border-left: 3px solid #3b82f6;">
<p style="color: #e2e8f0; font-size: 14px; margin-bottom: 10px; font-weight: 600;">What happens when you search:</p>
<p style="color: #cbd5e0; margin: 6px 0; font-size: 13px;">1. πŸ“„ Collect 10-15 research papers</p>
<p style="color: #cbd5e0; margin: 6px 0; font-size: 13px;">2. πŸ“š Literature Review (GPT-3.5)</p>
<p style="color: #cbd5e0; margin: 6px 0; font-size: 13px;">3. πŸ” Gap Analysis (GPT-4)</p>
<p style="color: #cbd5e0; margin: 6px 0; font-size: 13px;">4. πŸ’‘ Hypothesis Generation (GPT-4)</p>
</div>
""", unsafe_allow_html=True)
st.markdown("")
# API Status
st.markdown("### API Status")
if os.getenv('OPENAI_API_KEY') and os.getenv('GOOGLE_SEARCH_ENGINE_ID'):
st.markdown("""
<div style="background-color: #064e3b; padding: 12px; border-radius: 8px; border-left: 3px solid #10b981;">
<p style="color: #d1fae5; margin: 0; font-weight: 600; font-size: 14px;">βœ… All APIs configured</p>
</div>
""", unsafe_allow_html=True)
else:
st.markdown("""
<div style="background-color: #7f1d1d; padding: 12px; border-radius: 8px; border-left: 3px solid #ef4444;">
<p style="color: #fecaca; margin: 0; font-weight: 600; font-size: 14px;">❌ APIs not configured. Please check .env file</p>
</div>
""", unsafe_allow_html=True)
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("---")
st.markdown("""
<div style="background-color: #1e293b; padding: 15px; border-radius: 8px;">
<p style="color: #60a5fa; font-weight: 600; margin-bottom: 10px; font-size: 14px;">Powered by:</p>
<p style="color: #e2e8f0; margin: 5px 0; padding-left: 10px; font-size: 13px;">β€’ OpenAI GPT-4 & GPT-3.5</p>
<p style="color: #e2e8f0; margin: 5px 0; padding-left: 10px; font-size: 13px;">β€’ Sentence-BERT</p>
</div>
""", unsafe_allow_html=True)
# Add info about model loading
st.markdown("<br>", unsafe_allow_html=True)
st.markdown("""
<div style="background-color: #134e4a; padding: 12px; border-radius: 8px; border-left: 3px solid #14b8a6;">
<p style="color: #5eead4; margin: 0; font-size: 13px;">πŸ’‘ <b>Note:</b> Heavy AI models load on first use. Subsequent uses are instant!</p>
</div>
""", unsafe_allow_html=True)
# Main search interface
st.markdown("")
st.markdown("")
# Show current analysis status
if st.session_state.get('complete_data'):
current_topic = st.session_state.get('search_query', 'Unknown')
st.markdown(f"""
<div style="background-color: rgba(16, 185, 129, 0.1); padding: 12px 20px; border-radius: 6px;
border-left: 3px solid #10b981; margin-bottom: 20px;">
<p style="color: #6ee7b7; margin: 0; font-size: 14px; font-weight: 500;">
βœ“ Analysis completed for: <span style="color: #d1fae5;">{current_topic}</span>
</p>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns([3, 1])
with col2:
if st.button("πŸ”„ New Analysis", type="secondary", use_container_width=True):
# Clear all session state
for key in ['complete_data', 'search_query', 'selected_hypothesis', 'selected_gap',
'experiment_results', 'selected_experiment', 'generated_paper']:
if key in st.session_state:
del st.session_state[key]
st.rerun()
# Clean, minimal search input
st.markdown("""
<p style="color: #cbd5e0; font-size: 15px; font-weight: 500; margin-bottom: 10px;">
πŸ” Enter Your Research Topic
</p>
""", unsafe_allow_html=True)
search_query = st.text_input(
"Research Topic",
placeholder="e.g., machine learning for drug discovery, quantum computing applications...",
label_visibility="collapsed",
key="search_input"
)
search_button = st.button("πŸš€ Start Analysis", type="primary", use_container_width=True)
st.markdown("<br>", unsafe_allow_html=True)
# Handle search
if search_button and search_query:
# Create progress bar
progress_bar = st.progress(0)
status_text = st.empty()
try:
# Phase 1: Paper Collection
status_text.markdown("""
<div style="padding: 10px 15px; border-left: 3px solid #3b82f6; background-color: rgba(59, 130, 246, 0.1);">
<p style="color: #93c5fd; margin: 0; font-size: 14px;">πŸ“„ Phase 1/4: Collecting research papers...</p>
</div>
""", unsafe_allow_html=True)
progress_bar.progress(10)
system = MultiAgentSystem()
# Phase 2: Literature Review
status_text.markdown("""
<div style="padding: 10px 15px; border-left: 3px solid #10b981; background-color: rgba(16, 185, 129, 0.1);">
<p style="color: #6ee7b7; margin: 0; font-size: 14px;">πŸ“š Phase 2/4: Analyzing literature...</p>
</div>
""", unsafe_allow_html=True)
progress_bar.progress(30)
# Run analysis (this includes all phases)
result = asyncio.run(run_async_operations(
system,
search_query,
max_results=5
))
# Phase 3: Gap Analysis
status_text.markdown("""
<div style="padding: 10px 15px; border-left: 3px solid #f59e0b; background-color: rgba(245, 158, 11, 0.1);">
<p style="color: #fcd34d; margin: 0; font-size: 14px;">πŸ” Phase 3/4: Identifying research gaps...</p>
</div>
""", unsafe_allow_html=True)
progress_bar.progress(65)
# Phase 4: Hypothesis Generation
status_text.markdown("""
<div style="padding: 10px 15px; border-left: 3px solid #8b5cf6; background-color: rgba(139, 92, 246, 0.1);">
<p style="color: #c4b5fd; margin: 0; font-size: 14px;">πŸ’‘ Phase 4/4: Generating hypotheses...</p>
</div>
""", unsafe_allow_html=True)
progress_bar.progress(90)
# Complete
complete_data = result["data"]
st.session_state['complete_data'] = complete_data
st.session_state['search_query'] = search_query
progress_bar.progress(100)
status_text.markdown("""
<div style="padding: 12px 20px; border-left: 3px solid #10b981; background-color: rgba(16, 185, 129, 0.15);">
<p style="color: #6ee7b7; margin: 0; font-size: 15px; font-weight: 600;">
βœ“ Analysis Complete
</p>
</div>
""", unsafe_allow_html=True)
st.balloons()
except Exception as e:
st.error(f"An error occurred: {str(e)}")
st.error(f"Error details: {type(e).__name__}")
# Display tabs if we have complete data in session state
if st.session_state.get('complete_data'):
complete_data = st.session_state['complete_data']
search_query = st.session_state.get('search_query', '')
# Create tabs for different sections
tab1, tab2, tab3, tab4, tab5 = st.tabs([
"πŸ“š Literature Review",
"πŸ” Gap Analysis",
"πŸ’‘ Hypotheses",
"πŸ§ͺ Experiment Design",
"πŸ“ AI Paper Writer"
])
with tab1:
st.header("Literature Review")
# Show papers collected
papers = complete_data.get("papers", [])
if papers:
col1, col2, col3 = st.columns(3)
with col1:
st.metric("πŸ“„ Papers Found", len(papers))
with col2:
arxiv_count = sum(1 for p in papers if hasattr(p, 'arxiv_url') and p.arxiv_url)
st.metric("πŸ“š arXiv Papers", arxiv_count)
with col3:
google_count = len(papers) - arxiv_count
st.metric("πŸ” Google Scholar", google_count)
st.markdown("---")
# Show literature review with collapsible sections
if complete_data.get("literature_review"):
review_text = complete_data["literature_review"]
# Download button for literature review
col1, col2 = st.columns([3, 1])
with col2:
st.download_button(
label="πŸ“₯ Download as TXT",
data=review_text,
file_name=f"literature_review_{datetime.now().strftime('%Y%m%d')}.txt",
mime="text/plain",
use_container_width=True
)
# Parse into sections
sections = parse_literature_review(review_text)
if len(sections) > 1:
st.markdown("### πŸ“– Review Sections (Click to Expand)")
for section_name, section_content in sections.items():
with st.expander(f"πŸ“‘ {section_name}", expanded=(section_name == "Introduction" or section_name == "Full Review")):
st.markdown(section_content)
else:
st.markdown(review_text)
else:
st.warning("No literature review available")
# Display collected papers with links
if papers:
st.markdown("---")
st.subheader("πŸ“š Research Papers Analyzed")
st.info(f"πŸ’‘ {len(papers)} papers were collected and analyzed for this review")
for i, paper in enumerate(papers, 1):
with st.expander(f"πŸ“„ Paper {i}: {paper.title}", expanded=False):
if hasattr(paper, 'authors') and paper.authors:
st.markdown(f"**✍️ Authors:** {', '.join(paper.authors[:3])}{'...' if len(paper.authors) > 3 else ''}")
if hasattr(paper, 'published') and paper.published:
st.markdown(f"**πŸ“… Published:** {paper.published}")
if hasattr(paper, 'abstract') and paper.abstract:
st.markdown(f"**πŸ“ Abstract:**")
st.markdown(paper.abstract[:500] + "..." if len(paper.abstract) > 500 else paper.abstract)
elif hasattr(paper, 'snippet') and paper.snippet:
st.markdown(f"**πŸ“ Summary:**")
st.markdown(paper.snippet)
# Links
links = []
if hasattr(paper, 'arxiv_url') and paper.arxiv_url:
links.append(f"[πŸ“„ arXiv]({paper.arxiv_url})")
if hasattr(paper, 'pdf_url') and paper.pdf_url:
links.append(f"[πŸ“₯ PDF]({paper.pdf_url})")
if hasattr(paper, 'link') and paper.link:
links.append(f"[πŸ”— Source]({paper.link})")
if links:
st.markdown("**πŸ”— Links:** " + " | ".join(links))
else:
st.warning("No papers were collected for this analysis")
with tab2:
st.header("Research Gap Analysis")
gap_data = complete_data.get("gap_analysis", {})
# Show which model was used
gaps_dict = gap_data.get("gaps", {})
if gaps_dict.get("source"):
if "Combined" in gaps_dict["source"]:
st.success(f"πŸ€– Analysis by: {gaps_dict['source']}")
elif "GPT-4" in gaps_dict["source"]:
st.info(f"πŸ€– Analysis by: {gaps_dict['source']}")
else:
st.success(f"πŸ€– Analysis by: {gaps_dict['source']}")
# Show summary metrics
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Papers Analyzed", gap_data.get("papers_analyzed", 0))
with col2:
total_gaps = sum(len(gaps_dict.get(k, [])) for k in ["knowledge_gaps", "methodological_gaps", "dataset_gaps", "temporal_gaps"])
st.metric("Total Gaps Found", total_gaps)
with col3:
st.metric("Categories", 4)
with col4:
# Download button
gap_text = gap_data.get("formatted_output", "No gap analysis available")
st.download_button(
label="πŸ“₯ Download",
data=gap_text,
file_name=f"gap_analysis_{datetime.now().strftime('%Y%m%d')}.txt",
mime="text/plain",
use_container_width=True
)
# Display formatted gap analysis
st.markdown(gap_data.get("formatted_output", "No gap analysis available"))
with tab3:
st.header("Research Hypotheses")
hyp_data = complete_data.get("hypotheses", {})
if hyp_data.get("hypotheses"):
hypotheses_list = hyp_data.get("hypotheses", [])
# Show summary metrics
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Hypotheses Generated", len(hypotheses_list))
with col2:
avg_score = sum(h.get("overall_score", 0) for h in hypotheses_list) / max(len(hypotheses_list), 1)
st.metric("Avg Overall Score", f"{avg_score:.2f}")
with col3:
avg_novelty = sum(h.get("novelty_score", 0) for h in hypotheses_list) / max(len(hypotheses_list), 1)
st.metric("Avg Novelty Score", f"{avg_novelty:.2f}")
st.markdown("---")
# Side-by-side comparison table
st.markdown("### πŸ“Š Hypothesis Comparison Table")
comparison_data = []
for idx, hyp in enumerate(hypotheses_list, 1):
comparison_data.append({
"#": idx,
"Title": hyp.get('title', 'Untitled')[:50] + '...' if len(hyp.get('title', '')) > 50 else hyp.get('title', 'Untitled'),
"Overall": f"{hyp.get('overall_score', 0):.1f}",
"Novelty": f"{hyp.get('novelty_score', 0):.1f}",
"Impact": f"{hyp.get('impact_score', 0):.1f}",
"Feasibility": f"{hyp.get('feasibility_score', 0):.1f}",
"Gap": hyp.get('gap_addressed', 'N/A')[:40] + '...' if len(hyp.get('gap_addressed', '')) > 40 else hyp.get('gap_addressed', 'N/A')
})
comparison_df = pd.DataFrame(comparison_data)
st.dataframe(comparison_df, use_container_width=True, hide_index=True)
# Download CSV button
csv = comparison_df.to_csv(index=False)
st.download_button(
label="πŸ“₯ Download Comparison as CSV",
data=csv,
file_name=f"hypothesis_comparison_{datetime.now().strftime('%Y%m%d')}.csv",
mime="text/csv",
use_container_width=True
)
st.markdown("---")
# Display hypotheses with selection and color-coded badges
st.markdown("### πŸ’‘ Detailed Hypotheses (Click to Expand)")
for idx, hyp in enumerate(hypotheses_list, 1):
with st.expander(f"{'πŸ”΄' if hyp.get('priority') == 'HIGH' else '🟑'} Hypothesis {idx}: {hyp.get('title', 'Untitled')}", expanded=(idx==1)):
# Color-coded score badges
st.markdown("**πŸ“Š Performance Scores:**", unsafe_allow_html=True)
badges_html = ""
badges_html += get_score_badge(hyp.get('overall_score', 0), 'Overall')
badges_html += get_score_badge(hyp.get('novelty_score', 0), 'Novelty')
badges_html += get_score_badge(hyp.get('impact_score', 0), 'Impact')
badges_html += get_score_badge(hyp.get('feasibility_score', 0), 'Feasibility')
st.markdown(badges_html, unsafe_allow_html=True)
st.markdown("")
if hyp.get('gap_addressed'):
st.markdown(f"**🎯 Gap Addressed:** {hyp['gap_addressed']}")
if hyp.get('problem_statement'):
st.markdown(f"**❓ Problem Statement:** {hyp['problem_statement']}")
if hyp.get('proposed_solution'):
st.markdown(f"**πŸ’‘ Proposed Solution:** {hyp['proposed_solution']}")
if hyp.get('expected_impact'):
st.markdown(f"**πŸš€ Expected Impact:** {hyp['expected_impact']}")
else:
st.warning("No hypotheses generated")
with tab4:
st.header("πŸ§ͺ Experiment Design")
# Check if we have hypotheses to work with
if complete_data.get('hypotheses'):
hypotheses = complete_data['hypotheses'].get('hypotheses', [])
if hypotheses:
# Hypothesis selection
st.subheader("Select a Hypothesis")
hypothesis_options = [f"Hypothesis {h.get('hypothesis_id', i+1)}: {h.get('title', 'Untitled')}"
for i, h in enumerate(hypotheses)]
selected_index = st.selectbox(
"Choose a hypothesis to generate experiments for:",
range(len(hypothesis_options)),
format_func=lambda x: hypothesis_options[x],
key="hypothesis_selector"
)
selected_hypothesis = hypotheses[selected_index]
# Store selected hypothesis and its gap in session state
st.session_state['selected_hypothesis'] = selected_hypothesis
st.session_state['selected_gap'] = selected_hypothesis.get('gap_addressed', 'Not specified')
# Show selected hypothesis details
with st.expander("πŸ“‹ Selected Hypothesis Details", expanded=False):
st.write(f"**Title:** {selected_hypothesis.get('title', 'N/A')}")
st.write(f"**Gap Addressed:** {selected_hypothesis.get('gap_addressed', 'N/A')}")
st.write(f"**Problem Statement:** {selected_hypothesis.get('problem_statement', 'N/A')}")
st.write(f"**Proposed Solution:** {selected_hypothesis.get('proposed_solution', 'N/A')}")
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Novelty Score", f"{selected_hypothesis.get('novelty_score', 'N/A')}/10")
with col2:
st.metric("Impact Score", f"{selected_hypothesis.get('impact_score', 'N/A')}/10")
with col3:
st.metric("Feasibility Score", f"{selected_hypothesis.get('feasibility_score', 'N/A')}/10")
# Generate Experiments Button
if st.button("πŸš€ Generate Experiments & Datasets", key="generate_experiments"):
with st.spinner("πŸ§ͺ Generating experiments, datasets, and metrics..."):
try:
experiment_results = asyncio.run(
system.generate_experiments_for_hypothesis(
selected_hypothesis,
search_query
)
)
st.session_state['experiment_results'] = experiment_results
st.session_state['selected_experiment'] = None # Reset selection
st.success("βœ… Experiments generated successfully!")
except Exception as e:
st.error(f"❌ Error generating experiments: {str(e)}")
# Display experiment results
if st.session_state.get('experiment_results'):
st.markdown("---")
display_experiment_results(st.session_state['experiment_results'])
else:
st.warning("⚠️ No hypotheses available. Please run the complete analysis first.")
else:
st.info("πŸ‘ˆ Run a complete analysis first to generate hypotheses.")
with tab5:
st.header("πŸ“ AI Research Paper Writer")
st.markdown("*Generate a complete, publication-ready research paper in Word format*")
# Check if all required data is selected
selected_hypothesis = st.session_state.get('selected_hypothesis')
selected_experiment = st.session_state.get('selected_experiment')
selected_gap = st.session_state.get('selected_gap', 'Not specified')
if selected_hypothesis and selected_experiment:
# Show ready status
st.success("βœ… All required components selected! Ready to generate your paper.")
st.markdown("---")
# Show selected data summary in card-like layout
st.markdown("### πŸ“‹ Your Research Paper Components:")
col1, col2 = st.columns(2)
with col1:
with st.container():
st.markdown("**πŸ“Š Research Topic**")
st.info(complete_data.get('topic', 'Unknown'))
st.markdown("**πŸ’‘ Hypothesis**")
st.info(selected_hypothesis.get('title', 'Unknown'))
with col2:
with st.container():
st.markdown("**πŸ§ͺ Experiment**")
st.info(f"{selected_experiment.get('title', 'Unknown')}")
st.markdown("**πŸ” Gap Addressed**")
st.info(selected_gap)
st.markdown("---")
# Show what will be included
with st.expander("πŸ“„ What's included in your paper?", expanded=False):
col_a, col_b = st.columns(2)
with col_a:
st.markdown("""
**Title & Abstract**
- Title: 10-12 words based on your hypothesis
- Abstract: ~200 words summarizing the paper
**Introduction** (~550 words, 4 paragraphs)
- Background on the research topic
- Problem statement from hypothesis
- Research objectives and contributions
- Paper structure overview
**Literature Review** (~700 words, 4-5 paragraphs)
- Analysis of collected research papers
- Current state of the art
- Research gaps identified
- Positioning of your work
**Methodology** (~800 words, 5-6 paragraphs)
- Complete experimental design
- Step-by-step procedures from selected experiment
- Datasets, metrics, and evaluation approach
- Implementation details
""")
with col_b:
st.markdown("""
**Expected Results** (~550 words, 4 paragraphs)
- Anticipated experimental outcomes
- Tables and figures templates
- Performance metrics
- Analysis framework
**Discussion** (~600 words, 4-5 paragraphs)
- Interpretation of expected results
- Comparison with baselines
- Implications of findings
- Limitations and strengths
**Conclusion** (~300 words, 3 paragraphs)
- Summary of contributions
- Key findings
- Future work directions
**References**
- Formatted citations (APA style)
- All collected research papers
**Total: ~3,500 words (4-5 pages)**
""")
st.markdown("---")
# Initialize paper writer
writer = ResearchPaperWriter()
# Context for generation
paper_context = {
'topic': complete_data.get('topic', ''),
'hypothesis': selected_hypothesis,
'gap': selected_gap,
'experiment': selected_experiment,
'papers': complete_data.get('papers', []),
'literature_review': complete_data.get('literature_review', ''),
'gaps': complete_data.get('gap_analysis', {}).get('gaps', {})
}
# Generate Paper Button
st.markdown("### πŸš€ Generate Complete Research Paper")
st.info("πŸ’‘ Click the button below to generate a full research paper template. This will take 2-3 minutes.")
if st.button("πŸ“ Generate Research Paper Template", type="primary", use_container_width=True, key="generate_paper"):
with st.spinner("πŸ€– AI is writing your complete research paper... Please wait 2-3 minutes"):
try:
# Generate complete paper
complete_paper_md = writer.generate_complete_paper(paper_context)
# Store in session state
st.session_state['generated_paper'] = complete_paper_md
st.success("βœ… Research paper generated successfully!")
st.rerun()
except Exception as e:
st.error(f"❌ Error generating paper: {str(e)}")
# Display and download generated paper
if st.session_state.get('generated_paper'):
st.markdown("---")
st.markdown("### πŸ“„ Your Generated Research Paper")
# Paper stats
paper_text = st.session_state['generated_paper']
word_count = len(paper_text.split())
pages = word_count // 250
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total Words", f"{word_count:,}")
with col2:
st.metric("Est. Pages", f"~{pages}")
with col3:
st.metric("Sections", "8")
with col4:
st.metric("Status", "βœ… Ready")
st.markdown("")
# Preview
with st.expander("πŸ‘οΈ Preview Paper Content", expanded=False):
st.markdown(paper_text[:3000] + "..." if len(paper_text) > 3000 else paper_text)
st.markdown("---")
st.markdown("### πŸ“₯ Download Your Research Paper")
st.info("πŸ’‘ Your paper will be downloaded as a Microsoft Word document (.docx) ready for editing and submission!")
# Convert to Word document
try:
paper_title = selected_hypothesis.get('title', 'Research Paper')
doc_bytes = convert_markdown_to_docx(paper_text, paper_title)
if doc_bytes:
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.download_button(
label="πŸ“„ Download as Word Document (.docx)",
data=doc_bytes,
file_name=f"research_paper_{datetime.now().strftime('%Y%m%d_%H%M%S')}.docx",
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
use_container_width=True,
type="primary"
)
else:
st.error("Error converting paper to Word format. Please try again.")
except Exception as e:
st.error(f"Error creating Word document: {str(e)}")
st.info("πŸ’‘ Tip: Make sure python-docx is installed: pip install python-docx")
st.markdown("")
with st.expander("ℹ️ Next Steps - How to Use Your Paper"):
st.markdown("""
### πŸ“ Your Research Paper Template is Ready!
**What's Included:**
- βœ… Title and Abstract
- βœ… Introduction with background
- βœ… Literature Review from collected papers
- βœ… Complete Methodology from your selected experiment
- βœ… Expected Results section (fill with actual results)
- βœ… Discussion framework
- βœ… Conclusion
- βœ… Formatted References
**How to Complete Your Paper:**
1. **Download** the Markdown or Text version
2. **Open** in Word, Google Docs, or any text editor
3. **Run** your experiment and collect results
4. **Add** actual results, figures, and tables to Section 4
5. **Update** discussion based on real findings
6. **Proofread** and format for your target journal
7. **Submit** your completed paper!
**File Formats:**
- **Markdown (.md)**: Best for converting to PDF/LaTeX via Pandoc or Overleaf
- **Text (.txt)**: Universal format, open in any editor
- **JSON**: Contains paper + metadata, machine-readable
**πŸ’‘ Pro Tip:** The paper is written in academic style using GPT-4 with all your collected research context!
""")
# Clear button
st.markdown("---")
if st.button("πŸ—‘οΈ Clear and Generate New Paper", type="secondary"):
st.session_state['generated_paper'] = None
st.success("βœ… Cleared! Click 'Generate' button above to create a new paper.")
st.rerun()
elif selected_hypothesis and not selected_experiment:
st.warning("""
### ⚠️ Please Select an Experiment
You have selected a hypothesis, but no experiment yet.
**Steps:**
1. Go to **Tab 4** (Experiment Design)
2. Click **"Generate Experiments & Datasets"** if not done
3. **Select ONE experiment** by clicking "βœ… Select This Experiment"
4. Return to this tab to generate your paper
""")
else:
st.info("""
### πŸ‘ˆ Complete Previous Steps First
To generate a research paper template, you need to:
1. **Tab 1-2**: Run complete analysis to collect papers and identify gaps
2. **Tab 3**: Review and select a hypothesis
3. **Tab 4**: Generate experiments and **select ONE experiment**
4. **Tab 5** (Here): Generate your complete research paper!
The AI will create a professional academic paper including:
- Title, Abstract, Introduction
- Literature Review with citations
- Methodology from your experiment
- Expected Results section (for you to fill)
- Discussion and Conclusion
- Properly formatted References
""")
# Show search history
if st.session_state.search_history:
st.header("Search History")
history_df = pd.DataFrame(st.session_state.search_history)
st.dataframe(
history_df,
hide_index=True,
column_config={
"timestamp": st.column_config.DatetimeColumn(
"Time",
format="D MMM, YYYY, HH:mm"
)
}
)
def display_experiment_results(results: dict):
"""Display the experiment generation results in a structured format"""
st.header("πŸ§ͺ Detailed Experiment Plans")
# Experiments Section
if results.get('experiments'):
st.subheader("πŸ”¬ Select an Experiment for Your Research Paper")
st.info("πŸ‘‡ Each experiment contains EVERYTHING you need: introduction, methodology, datasets, metrics, models, and challenges. Choose ONE to use in your paper.")
# Experiment selection
for i, exp in enumerate(results['experiments']):
with st.expander(f"βš—οΈ Experiment {exp['id']}: {exp['title']}", expanded=(i==0)):
# Header with difficulty and time
col1, col2, col3 = st.columns([2, 1, 1])
with col1:
st.markdown(f"### πŸ“‹ {exp['title']}")
with col2:
difficulty_color = {"Easy": "🟒", "Medium": "🟑", "Hard": "πŸ”΄"}
diff = exp.get('difficulty', 'Medium')
st.metric("Difficulty", f"{difficulty_color.get(diff, 'βšͺ')} {diff}")
with col3:
st.metric("Estimated Time", exp.get('estimated_time', '2-3 months'))
st.markdown("---")
# 1. Introduction
if exp.get('introduction'):
st.markdown("**πŸ“– 1. Introduction & Background**")
st.markdown(exp['introduction'])
st.markdown("")
# 2. Description
st.markdown("**🎯 2. Experiment Overview**")
st.markdown(exp['description'])
st.markdown("")
# 3. Detailed Methodology Steps
if exp.get('steps'):
st.markdown("**πŸ”¬ 3. Detailed Methodology (Step-by-Step)**")
for j, step in enumerate(exp['steps'], 1):
st.markdown(f"**Step {j}:** {step}")
st.markdown("")
# 4. Datasets (from results dict, not just experiment)
st.markdown("**πŸ“Š 4. Recommended Datasets**")
if results.get('datasets'):
datasets = results['datasets']
# Check if it's a list (new format) or dict (old format)
if isinstance(datasets, list):
# New format: simple list
if datasets:
for idx, dataset in enumerate(datasets[:2], 1): # Show top 2
st.markdown(f"**{idx}. {dataset['name']}**")
st.markdown(f" - πŸ“¦ Size: {dataset.get('size', 'N/A')}")
# Show downloads if available
if dataset.get('downloads'):
downloads = dataset.get('downloads')
if isinstance(downloads, int):
st.markdown(f" - πŸ’Ύ Downloads: {downloads:,}")
else:
st.markdown(f" - πŸ’Ύ Downloads: {downloads}")
# Show usability if available
if dataset.get('usability'):
st.markdown(f" - ⭐ Usability: {dataset['usability']:.1f}/10")
# Description
desc = dataset.get('description', '')
if len(desc) > 150:
st.markdown(f" - {desc[:150]}...")
else:
st.markdown(f" - {desc}")
# Link
if dataset.get('url'):
source = dataset.get('source', 'Kaggle')
st.markdown(f" - [πŸ“₯ **Access Dataset**]({dataset['url']})")
st.markdown("")
else:
st.markdown("β€’ Custom dataset required (see methodology)")
else:
# Old format fallback: dict with kaggle/huggingface keys
kaggle_datasets = datasets.get('kaggle', [])
hf_datasets = datasets.get('huggingface', [])
all_datasets = kaggle_datasets + hf_datasets
if all_datasets:
for idx, dataset in enumerate(all_datasets[:2], 1):
st.markdown(f"**{idx}. {dataset['name']}**")
st.markdown(f" - {dataset.get('description', '')[:150]}")
if dataset.get('url'):
st.markdown(f" - [πŸ“₯ **Access Dataset**]({dataset['url']})")
st.markdown("")
else:
st.markdown("β€’ Custom dataset required (see methodology)")
else:
st.markdown("β€’ Dataset recommendations will be generated based on your topic")
st.markdown("")
# 5. Evaluation Metrics
if results.get('metrics'):
st.markdown("**πŸ“ˆ 5. Evaluation Metrics**")
for metric in results['metrics'][:4]: # Top 4 metrics
st.markdown(f"β€’ **{metric['name']}**: {metric['description']}")
if metric.get('range'):
st.markdown(f" - Range: {metric['range']}")
st.markdown("")
# 6. Model Architectures
if results.get('architectures'):
st.markdown("**πŸ—οΈ 6. Suggested Model Architectures**")
for arch in results['architectures'][:3]: # Top 3 architectures
st.markdown(f"β€’ **{arch['name']}**")
st.markdown(f" - {arch['description']}")
if arch.get('parameters'):
st.markdown(f" - Parameters: {arch['parameters']}")
st.markdown("")
# 7. Baseline Models
if results.get('baselines'):
st.markdown("**πŸ“Š 7. Baseline Models for Comparison**")
for baseline in results['baselines'][:3]:
st.markdown(f"β€’ **{baseline['name']}**: {baseline['description']}")
if baseline.get('expected_performance'):
st.markdown(f" - Expected Performance: {baseline['expected_performance']}")
st.markdown("")
# 8. Expected Outcomes
if results.get('expected_outcomes'):
st.markdown("**🎯 8. Expected Outcomes**")
outcomes = results['expected_outcomes']
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Target Accuracy", outcomes.get('accuracy_range', '85-92%'))
with col2:
st.metric("Training Time", outcomes.get('training_time', '4-6 hours'))
with col3:
st.metric("Model Size", outcomes.get('model_size', '50-100MB'))
with col4:
st.metric("Inference Speed", outcomes.get('inference_speed', '10-20ms'))
st.markdown("")
# 9. Challenges & Solutions
if results.get('challenges'):
st.markdown("**⚠️ 9. Potential Challenges & Mitigation**")
for challenge in results['challenges'][:4]:
st.markdown(f"β€’ {challenge}")
st.markdown("")
# 10. Required Resources
if exp.get('required_resources'):
st.markdown("**πŸ’» 10. Required Resources**")
for resource in exp['required_resources']:
st.markdown(f"β€’ {resource}")
st.markdown("")
# Selection button - prominent
st.markdown("---")
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
if st.button(f"βœ“ Select This Experiment for Paper", key=f"select_exp_{exp['id']}", use_container_width=True, type="primary"):
st.session_state['selected_experiment'] = exp
st.success(f"βœ“ Selected: {exp['title']}")
st.info("β†’ Go to Tab 5 to generate your research paper!")
# Show currently selected experiment
if st.session_state.get('selected_experiment'):
selected = st.session_state['selected_experiment']
st.markdown("---")
st.success(f"🎯 **Currently Selected:** Experiment {selected['id']} - {selected['title']}")
st.caption("Go to Tab 5 'AI Paper Writer' to generate your complete research paper template!")
# Download complete experiment plan as JSON
st.markdown("---")
st.subheader("πŸ’Ύ Export Complete Experiment Plan")
json_str = json.dumps(results, indent=2)
st.download_button(
label="πŸ“₯ Download All Experiments as JSON",
data=json_str,
file_name=f"experiment_plan_{results.get('metadata', {}).get('hypothesis_id', 'unknown')}.json",
mime="application/json",
help="Download all experiment details including datasets, metrics, and models"
)
def render_footer():
"""Render footer on all pages"""
st.markdown("<br><br>", unsafe_allow_html=True)
st.markdown("---")
st.markdown("""
<div style="text-align: center; padding: 25px; background-color: #1e293b;
border-radius: 8px; margin-top: 30px; border-top: 2px solid #3b82f6;">
<p style="color: #60a5fa; font-size: 13px; font-weight: 600; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 1.5px;">Development Team</p>
<p style="color: #cbd5e0; font-size: 15px; margin: 8px 0; line-height: 1.6;">
Made by <span style="color: #f1f5f9; font-weight: 600;">Radia Riaz</span>,
<span style="color: #f1f5f9; font-weight: 600;">Amna Alvie</span>,
<span style="color: #f1f5f9; font-weight: 600;">Emaan Riaz</span>,
<span style="color: #f1f5f9; font-weight: 600;">Maheen Alvie</span>
</p>
<p style="color: #94a3b8; font-size: 12px; margin-top: 10px;">
Gen AI Hackathon 2025
</p>
</div>
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()
render_footer()