Spaces:
Running
Running
File size: 10,112 Bytes
fbec6c3 aee8230 fbec6c3 9f2ed7e fbec6c3 9f2ed7e fbec6c3 9f2ed7e fbec6c3 9f2ed7e fbec6c3 9f2ed7e fbec6c3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# 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")
|