PaperPilot / app.py
sunbal7's picture
Update app.py
9f2ed7e verified
# app.py
import os
import streamlit as st
import arxiv
import networkx as nx
import matplotlib.pyplot as plt
import datetime
# -------------------------------
# Groq API Client
# -------------------------------
from groq import Groq
client = Groq(
api_key=os.environ.get("GROQ_API_KEY"),
)
# -------------------------------
# Helper Functions (Groq-based)
# -------------------------------
def groq_summarize(text: str) -> str:
"""
Summarize the given text using Groq's chat completion API.
Adjust the prompt or model as needed.
"""
response = client.chat.completions.create(
messages=[
{
"role": "user",
"content": f"Summarize the following text in detail:\n\n{text}"
}
],
model="llama-3.3-70b-versatile",
)
return response.choices[0].message.content.strip()
def groq_generate(text: str) -> str:
"""
Generate text (e.g., research proposals) using Groq's chat completion API.
Adjust the prompt or model as needed.
"""
response = client.chat.completions.create(
messages=[
{
"role": "user",
"content": text
}
],
model="llama-3.3-70b-versatile",
)
return response.choices[0].message.content.strip()
# -------------------------------
# Existing Helper Functions
# -------------------------------
def retrieve_papers(query, max_results=5):
"""Retrieve academic papers from arXiv."""
search = arxiv.Search(query=query, max_results=max_results)
papers = []
for result in search.results():
paper = {
"title": result.title,
"summary": result.summary,
"url": result.pdf_url,
"authors": [author.name for author in result.authors],
"published": result.published
}
papers.append(paper)
return papers
def summarize_text(text):
"""
Wrap the groq_summarize function so it's easy to switch
implementations if needed.
"""
return groq_summarize(text)
def generate_concept_map(papers):
"""Create a concept map (graph) based on author connections."""
G = nx.Graph()
for paper in papers:
G.add_node(paper['title'])
for i in range(len(papers)):
for j in range(i + 1, len(papers)):
if set(papers[i]['authors']) & set(papers[j]['authors']):
G.add_edge(papers[i]['title'], papers[j]['title'])
return G
def generate_citation(paper):
"""Generate APA-style citation for a paper."""
authors = ", ".join(paper['authors'])
if isinstance(paper['published'], datetime.datetime):
year = paper['published'].year
else:
year = "n.d."
return f"{authors} ({year}). {paper['title']}. Retrieved from {paper['url']}"
def generate_proposal_suggestions(text):
"""
Generate novel research proposal suggestions based on text,
wrapping the groq_generate function.
"""
prompt = (
f"Based on this research summary:\n\n{text}\n\n"
"Propose novel research directions:"
)
return groq_generate(prompt)
def get_cached_summary(paper_id, text):
"""
Retrieve or create a cached summary for a given paper.
This ensures each paper's summary is generated only once.
"""
if 'summaries' not in st.session_state:
st.session_state.summaries = {}
if paper_id not in st.session_state.summaries:
st.session_state.summaries[paper_id] = summarize_text(text)
return st.session_state.summaries[paper_id]
# -------------------------------
# Streamlit Interface
# -------------------------------
st.title("πŸ“š PaperPilot – Intelligent Academic Navigator")
# Add the Overview subheading
st.write("""
PaperPilot is an intelligent academic navigator designed to simplify your research workflow.
With a single query, it fetches relevant academic papers and provides you with a
comprehensive toolkit to explore them in depth. You can read a quick summary of each article,
view a visual concept map to see how different papers are interlinked, generate properly
formatted citations, and even receive suggestions for novel research proposals. By integrating
state-of-the-art AI models, PaperPilot streamlines the entire literature review processβ€”making
it easier to stay organized, discover new insights, and advance your academic endeavors.
""")
# ---------------------------------
# Sidebar: Search & Navigation
# ---------------------------------
with st.sidebar:
st.header("πŸ” Search Parameters")
query = st.text_input("Research topic or question:")
if st.button("πŸš€ Find Articles"):
if query.strip():
with st.spinner("Searching arXiv..."):
papers = retrieve_papers(query)
if papers:
st.session_state.papers = papers
st.success(f"Found {len(papers)} papers!")
# Default to showing articles after retrieval
st.session_state.active_section = "articles"
else:
st.error("No papers found. Try different keywords.")
else:
st.warning("Please enter a search query")
# Navigation buttons (only relevant if we have papers in session)
if 'papers' in st.session_state and st.session_state.papers:
st.header("πŸ”€ Navigation")
if st.button("πŸ“‘ Show Articles"):
st.session_state.active_section = "articles"
if st.button("πŸ“š Literature Review & Summary"):
st.session_state.active_section = "review"
if st.button("πŸ” Concept & Visual Graph"):
st.session_state.active_section = "graph"
if st.button("πŸ“ Formatted Citations"):
st.session_state.active_section = "citations"
if st.button("πŸ’‘ Research Proposal"):
st.session_state.active_section = "proposal"
# ---------------------------------
# Main Content Area
# ---------------------------------
if 'active_section' not in st.session_state:
st.session_state.active_section = "none"
if 'papers' in st.session_state and st.session_state.papers:
papers = st.session_state.papers
# ---------------------------------
# 1) Show Articles
# ---------------------------------
if st.session_state.active_section == "articles":
st.header("πŸ“‘ Retrieved Papers")
for idx, paper in enumerate(papers, 1):
with st.expander(f"{idx}. {paper['title']}"):
st.markdown(f"**Authors:** {', '.join(paper['authors'])}")
if isinstance(paper['published'], datetime.datetime):
pub_date = paper['published'].strftime('%Y-%m-%d')
else:
pub_date = "n.d."
st.markdown(f"**Published:** {pub_date}")
st.markdown(f"**Link:** [PDF Link]({paper['url']})")
st.markdown("**Abstract:**")
st.write(paper['summary'])
# ---------------------------------
# 2) Literature Review & Summary
# ---------------------------------
elif st.session_state.active_section == "review":
st.header("πŸ“š Literature Review & Summary")
combined_summary = ""
for idx, paper in enumerate(papers, 1):
with st.expander(f"Summary: {paper['title']}", expanded=False):
with st.spinner(f"Analyzing {paper['title']}..."):
paper_id = f"paper_{idx}"
summary = get_cached_summary(paper_id, paper['summary'])
st.write(summary)
combined_summary += summary + "\n\n"
st.session_state.combined_summary = combined_summary
# ---------------------------------
# 3) Concept & Visual Graph
# ---------------------------------
elif st.session_state.active_section == "graph":
st.header("πŸ” Concept & Visual Graph")
st.write(
"Below is a concept map that visualizes how the authors are "
"connected across the retrieved articles. Each node represents a paper, "
"and edges indicate shared authors."
)
with st.spinner("Generating concept map..."):
G = generate_concept_map(papers)
if G.nodes():
fig, ax = plt.subplots(figsize=(10, 8))
pos = nx.spring_layout(G, k=0.5, seed=42)
nx.draw_networkx_nodes(G, pos, node_color='skyblue', node_size=2000, ax=ax)
nx.draw_networkx_edges(G, pos, edge_color='#666666', ax=ax)
nx.draw_networkx_labels(G, pos, font_size=10, ax=ax)
ax.axis('off')
st.pyplot(fig)
else:
st.info("No significant connections found between papers.")
# ---------------------------------
# 4) Formatted Citations
# ---------------------------------
elif st.session_state.active_section == "citations":
st.header("πŸ“ Formatted Citations (APA Style)")
for paper in papers:
st.markdown(f"- {generate_citation(paper)}")
# ---------------------------------
# 5) Research Proposal
# ---------------------------------
elif st.session_state.active_section == "proposal":
st.header("πŸ’‘ Research Proposal Suggestions")
# Make sure we have a combined summary for the proposals
if 'combined_summary' not in st.session_state:
with st.spinner("Synthesizing research overview..."):
full_text = "\n".join([p['summary'] for p in papers])
st.session_state.combined_summary = summarize_text(full_text)
with st.spinner("Generating innovative ideas..."):
proposal = generate_proposal_suggestions(st.session_state.combined_summary[:2000])
st.write(proposal)
else:
st.info("Please select an option from the sidebar to begin.")
else:
st.info("Enter a query in the sidebar and click 'Find Articles' to get started.")
st.caption("Built with ❀️ using AI")