Upload 14 files
Browse files- agents/__init__.py +7 -0
- agents/future_works_agent.py +93 -0
- agents/intent_agent.py +38 -0
- agents/qa_agent.py +62 -0
- agents/search_agent.py +115 -0
- agents/summarization_agent.py +109 -0
- app.py +276 -276
- config/config.py +13 -0
- imgs/Frontend.png +0 -0
- imgs/Q1.png +0 -0
- imgs/Q2.png +0 -0
- imgs/papers.png +0 -0
- imgs/papers2.png +0 -0
- router.py +24 -0
agents/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agents/__init__.py
|
| 2 |
+
from .search_agent import SearchAgent
|
| 3 |
+
from .qa_agent import QAAgent
|
| 4 |
+
from .future_works_agent import FutureWorksAgent
|
| 5 |
+
from .intent_agent import IntentAgent
|
| 6 |
+
from .summarization_agent import SummarizationAgent
|
| 7 |
+
__all__ = ["IntentAgent" , "SearchAgent", "QAAgent", "FutureWorksAgent" , "SummarizationAgent"]
|
agents/future_works_agent.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain.vectorstores import FAISS
|
| 2 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 3 |
+
import os
|
| 4 |
+
from agents import SearchAgent
|
| 5 |
+
import streamlit as st
|
| 6 |
+
from config.config import model
|
| 7 |
+
|
| 8 |
+
embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
|
| 9 |
+
|
| 10 |
+
class FutureWorksAgent:
|
| 11 |
+
def __init__(self):
|
| 12 |
+
self.model = model
|
| 13 |
+
self.prompt = """Analyze the research context and provide targeted insights based on the specific task type.
|
| 14 |
+
|
| 15 |
+
Previous conversation:
|
| 16 |
+
{chat_history}
|
| 17 |
+
|
| 18 |
+
Current research context:
|
| 19 |
+
{context}
|
| 20 |
+
|
| 21 |
+
Task Type Detection:
|
| 22 |
+
1. Review Paper Future Work:
|
| 23 |
+
If the query involves generating future work for a review paper:
|
| 24 |
+
- Identify emerging trends and unexplored areas
|
| 25 |
+
- Suggest potential research questions
|
| 26 |
+
- Outline methodology gaps
|
| 27 |
+
- Propose innovative approaches
|
| 28 |
+
|
| 29 |
+
2. Structured Review Summary:
|
| 30 |
+
If the query involves creating a review paper summary:
|
| 31 |
+
- Synthesize key findings across papers
|
| 32 |
+
- Identify major research themes
|
| 33 |
+
- Highlight methodological approaches
|
| 34 |
+
- Present conflicting results or debates
|
| 35 |
+
- Suggest future research opportunities
|
| 36 |
+
|
| 37 |
+
3. Improvement Plan:
|
| 38 |
+
If the query involves generating an improvement plan:
|
| 39 |
+
- Analyze existing solutions and their limitations
|
| 40 |
+
- Identify potential enhancements
|
| 41 |
+
- Suggest novel technical contributions
|
| 42 |
+
- Propose validation approaches
|
| 43 |
+
- Outline implementation steps
|
| 44 |
+
|
| 45 |
+
4. Research Direction Synthesis:
|
| 46 |
+
If the query involves combining multiple papers:
|
| 47 |
+
- Identify common themes and patterns
|
| 48 |
+
- Highlight complementary approaches
|
| 49 |
+
- Suggest novel combinations of methods
|
| 50 |
+
- Propose new research directions
|
| 51 |
+
- Outline potential experimental designs
|
| 52 |
+
|
| 53 |
+
Format Guidelines:
|
| 54 |
+
- Begin with identifying the specific task type
|
| 55 |
+
- Provide structured, section-wise response
|
| 56 |
+
- Include specific examples from papers
|
| 57 |
+
- List concrete action items or suggestions
|
| 58 |
+
- Acknowledge limitations and assumptions
|
| 59 |
+
- Suggest validation approaches
|
| 60 |
+
|
| 61 |
+
Note: Focus on providing actionable, specific suggestions rather than general statements.
|
| 62 |
+
Consider both theoretical advances and practical implementations.
|
| 63 |
+
"""
|
| 64 |
+
|
| 65 |
+
self.papers = None
|
| 66 |
+
self.search_agent_response = ""
|
| 67 |
+
|
| 68 |
+
def solve(self, query):
|
| 69 |
+
|
| 70 |
+
# Check if search has been performed
|
| 71 |
+
if not os.path.exists("vector_db"):
|
| 72 |
+
st.warning("No papers loaded. Performing search first...")
|
| 73 |
+
search_agent = SearchAgent()
|
| 74 |
+
self.search_agent_response , self.papers = search_agent.solve(query)
|
| 75 |
+
|
| 76 |
+
# Load vector store
|
| 77 |
+
vector_db = FAISS.load_local("vector_db", embeddings, index_name="base_and_adjacent", allow_dangerous_deserialization=True)
|
| 78 |
+
|
| 79 |
+
# Get chat history
|
| 80 |
+
chat_history = st.session_state.get("chat_history", [])
|
| 81 |
+
chat_history_text = "".join([f"{sender}: {msg}" for sender, msg in chat_history[-5:]])
|
| 82 |
+
|
| 83 |
+
# Get relevant chunks
|
| 84 |
+
retrieved = vector_db.as_retriever().get_relevant_documents(query)
|
| 85 |
+
context = "".join([f"{doc.page_content}\n Source: {doc.metadata['source']}" for doc in retrieved])
|
| 86 |
+
|
| 87 |
+
# Generate response
|
| 88 |
+
full_prompt = self.prompt.format(
|
| 89 |
+
chat_history=chat_history_text,
|
| 90 |
+
context=context
|
| 91 |
+
)
|
| 92 |
+
response = self.model.generate_content(str(self.search_agent_response) + full_prompt)
|
| 93 |
+
return response.text , self.papers
|
agents/intent_agent.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from config.config import model
|
| 2 |
+
|
| 3 |
+
class IntentAgent:
|
| 4 |
+
def __init__(self):
|
| 5 |
+
self.model = model
|
| 6 |
+
self.prompt = """You are an intent classifier for a research paper assistant. Given a user query, classify it into one of these categories:
|
| 7 |
+
|
| 8 |
+
- "search": User wants to find relevant research papers on a topic
|
| 9 |
+
- "qa": User has questions about specific papers or content
|
| 10 |
+
- "future_works": User wants to:
|
| 11 |
+
* Generate future work ideas for a review paper
|
| 12 |
+
* Create a structured review paper summary
|
| 13 |
+
* Generate improvement plans from research works
|
| 14 |
+
* Combine multiple papers for new research directions
|
| 15 |
+
* Review paper generation
|
| 16 |
+
* Synthesize multiple papers
|
| 17 |
+
- "summarize": User wants to:
|
| 18 |
+
* Summarize findings from multiple papers over a given timeframe
|
| 19 |
+
* Extract key information from multiple papers and present it
|
| 20 |
+
|
| 21 |
+
Example queries and their intents:
|
| 22 |
+
"Find papers about machine learning" -> "search"
|
| 23 |
+
"What does the paper say about the methodology?" -> "qa"
|
| 24 |
+
"What future directions can I include in my review?" -> "future_works"
|
| 25 |
+
"Can you help me write a literature review?" -> "future_works"
|
| 26 |
+
"How can I combine these papers into an improvement plan?" -> "future_works"
|
| 27 |
+
"What are the gaps in current research?" -> "future_works"
|
| 28 |
+
"Summarize findings on neural networks from these papers" -> "summarize"
|
| 29 |
+
"Extract key points from these papers" -> "summarize"
|
| 30 |
+
|
| 31 |
+
Respond with just the intent category.
|
| 32 |
+
|
| 33 |
+
Query: {query}"""
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def get_intent(self, query):
|
| 37 |
+
response = self.model.generate_content(self.prompt.format(query=query))
|
| 38 |
+
return response.text.strip().lower()
|
agents/qa_agent.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import streamlit as st
|
| 3 |
+
from agents import SearchAgent
|
| 4 |
+
from langchain.vectorstores import FAISS
|
| 5 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 6 |
+
from config.config import model
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
|
| 12 |
+
|
| 13 |
+
class QAAgent:
|
| 14 |
+
def __init__(self):
|
| 15 |
+
|
| 16 |
+
self.model = model
|
| 17 |
+
self.prompt = """You are a research assistant answering questions about academic papers. Use the following context from papers and chat history to provide accurate, specific answers.
|
| 18 |
+
|
| 19 |
+
Previous conversation:
|
| 20 |
+
{chat_history}
|
| 21 |
+
|
| 22 |
+
Paper context:
|
| 23 |
+
{context}
|
| 24 |
+
|
| 25 |
+
Question: {question}
|
| 26 |
+
|
| 27 |
+
Guidelines:
|
| 28 |
+
1. Reference specific papers when making claims
|
| 29 |
+
2. Use direct quotes when relevant
|
| 30 |
+
3. Acknowledge if information isn't available in the provided context
|
| 31 |
+
4. Maintain academic tone and precision
|
| 32 |
+
"""
|
| 33 |
+
self.papers = None
|
| 34 |
+
self.search_agent_response = ""
|
| 35 |
+
|
| 36 |
+
def solve(self, query):
|
| 37 |
+
# Check if search has been performed
|
| 38 |
+
if not os.path.exists("vector_db"):
|
| 39 |
+
st.warning("No papers loaded. Performing search first...")
|
| 40 |
+
search_agent = SearchAgent()
|
| 41 |
+
self.search_agent_response , self.papers = search_agent.solve(query)
|
| 42 |
+
|
| 43 |
+
# Load vector store
|
| 44 |
+
vector_db = FAISS.load_local("vector_db", embeddings, index_name="base_and_adjacent", allow_dangerous_deserialization=True)
|
| 45 |
+
|
| 46 |
+
# Get chat history
|
| 47 |
+
chat_history = st.session_state.get("chat_history", [])
|
| 48 |
+
chat_history_text = "".join([f"{sender}: {msg}" for sender, msg in chat_history[-5:]]) # Last 5 messages
|
| 49 |
+
|
| 50 |
+
# Get relevant chunks
|
| 51 |
+
retrieved = vector_db.as_retriever().get_relevant_documents(query)
|
| 52 |
+
context = "".join([f"{doc.page_content}\n Source: {doc.metadata['source']}" for doc in retrieved])
|
| 53 |
+
|
| 54 |
+
# Generate response
|
| 55 |
+
full_prompt = self.prompt.format(
|
| 56 |
+
chat_history=chat_history_text,
|
| 57 |
+
context=context,
|
| 58 |
+
question=query
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
response = self.model.generate_content(str(self.search_agent_response) + full_prompt)
|
| 62 |
+
return response.text , self.papers
|
agents/search_agent.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import requests
|
| 3 |
+
import os
|
| 4 |
+
from langchain.document_loaders import PDFMinerLoader
|
| 5 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 6 |
+
from langchain.vectorstores import FAISS
|
| 7 |
+
from langchain_community.document_loaders import ArxivLoader
|
| 8 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 9 |
+
import faiss
|
| 10 |
+
from langchain_community.docstore.in_memory import InMemoryDocstore
|
| 11 |
+
from config.config import model
|
| 12 |
+
import urllib.request as libreq
|
| 13 |
+
import xml.etree.ElementTree as ET
|
| 14 |
+
|
| 15 |
+
os.makedirs("papers", exist_ok=True)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
|
| 19 |
+
index = faiss.IndexFlatL2(len(embeddings.embed_query("dummy query")))
|
| 20 |
+
|
| 21 |
+
text_splitter = RecursiveCharacterTextSplitter(
|
| 22 |
+
chunk_size=700,
|
| 23 |
+
chunk_overlap=0,
|
| 24 |
+
length_function=len
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
class SearchAgent:
|
| 28 |
+
def __init__(self):
|
| 29 |
+
|
| 30 |
+
self.model = model
|
| 31 |
+
self.p = """You are an assistant designed to extract research topics or titles from user queries. When a user asks about a specific topic, identify the central subject of their query and provide a concise, clear title or topic related to that area of research. If the query refers to a particular research paper, include the paper's title, author(s), and publication year.
|
| 32 |
+
Here are the instructions you should follow:
|
| 33 |
+
General Topics: If the query mentions a general topic without referring to a specific paper, identify the primary research area or topic. For example, if the query is "What are the advancements in text-to-SQL models?" your response should be simply "Text-to-SQL Models."
|
| 34 |
+
Specific Research Papers: If the query mentions a particular paper, extract the title, author(s), and year of the paper. For example, if the query is "What did the paper by John Doe in 2022 say about AI in healthcare?" your response should be "AI in Healthcare (John Doe, 2022)."
|
| 35 |
+
Abstract or General Query: If the query is an abstract or general inquiry into a topic, return the main theme or title of that topic. For instance, "What are the advancements in natural language processing?" would result in "Natural Language Processing Advancements."
|
| 36 |
+
Examples:
|
| 37 |
+
User Query: "Tell me about recent advancements in text-to-SQL models." Response: "Text-to-SQL Models."
|
| 38 |
+
User Query: "What does the paper 'Deep Learning for Text-to-SQL by Jane Smith, 2021' cover?" Response: "'Deep Learning for Text-to-SQL' (Jane Smith, 2021)."
|
| 39 |
+
User Query: "Can you summarize the paper by Alice Brown on quantum computing from 2020?" Response: "'Quantum Computing: A New Frontier' (Alice Brown, 2020)." """
|
| 40 |
+
|
| 41 |
+
def solve(self, task):
|
| 42 |
+
print(f"Searching for information on: {task}")
|
| 43 |
+
response = model.generate_content(self.p+task)
|
| 44 |
+
query = response.text.strip()
|
| 45 |
+
|
| 46 |
+
r=query.split(" ")
|
| 47 |
+
query_="%20".join(r)
|
| 48 |
+
|
| 49 |
+
with libreq.urlopen(f'''http://export.arxiv.org/api/query?search_query=all:{query_}&sortBy=relevance&sortOrder=descending&start=0&max_results=5''') as url:
|
| 50 |
+
r = url.read()
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
xml_content = r
|
| 55 |
+
root = ET.fromstring(xml_content)
|
| 56 |
+
ns = {'atom': 'http://www.w3.org/2005/Atom'}
|
| 57 |
+
ids = [entry.find('atom:id', ns).text for entry in root.findall('atom:entry', ns)]
|
| 58 |
+
pdf_urls = [url.replace("abs", "pdf") for url in ids]
|
| 59 |
+
|
| 60 |
+
# Create list to store paper information
|
| 61 |
+
papers = []
|
| 62 |
+
|
| 63 |
+
# Extract information for each paper
|
| 64 |
+
for entry in root.findall('atom:entry', ns):
|
| 65 |
+
paper_info = {}
|
| 66 |
+
|
| 67 |
+
# Get paper title
|
| 68 |
+
title = entry.find('atom:title', ns).text
|
| 69 |
+
paper_info['title'] = title
|
| 70 |
+
|
| 71 |
+
# Get paper ID and create PDF link
|
| 72 |
+
paper_id = entry.find('atom:id', ns).text
|
| 73 |
+
pdf_link = paper_id.replace("abs", "pdf")
|
| 74 |
+
paper_info['link'] = pdf_link
|
| 75 |
+
|
| 76 |
+
# Get publication year from published date
|
| 77 |
+
published = entry.find('atom:published', ns).text
|
| 78 |
+
year = published[:4] # Extract year from date string
|
| 79 |
+
paper_info['year'] = year
|
| 80 |
+
|
| 81 |
+
papers.append(paper_info)
|
| 82 |
+
|
| 83 |
+
all_papers = []
|
| 84 |
+
|
| 85 |
+
def download_pdf_paper_from_url(url):
|
| 86 |
+
paper_number = os.path.basename(url).strip(".pdf")
|
| 87 |
+
res = requests.get(url)
|
| 88 |
+
pdf_path = f"papers/{paper_number}.pdf"
|
| 89 |
+
with open(pdf_path, 'wb') as f:
|
| 90 |
+
f.write(res.content)
|
| 91 |
+
return paper_number
|
| 92 |
+
|
| 93 |
+
for paper in papers:
|
| 94 |
+
paper_number = download_pdf_paper_from_url(paper['link'])
|
| 95 |
+
all_papers.append(paper_number)
|
| 96 |
+
# Add paper number to paper info
|
| 97 |
+
paper['paper_number'] = paper_number
|
| 98 |
+
|
| 99 |
+
vector_db = FAISS(
|
| 100 |
+
embedding_function=embeddings,
|
| 101 |
+
index=index,
|
| 102 |
+
docstore=InMemoryDocstore(),
|
| 103 |
+
index_to_docstore_id={}
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
for pdf_number in all_papers:
|
| 107 |
+
docs = ArxivLoader(query=pdf_number)
|
| 108 |
+
docs = PDFMinerLoader(f"papers/{pdf_number}.pdf").load()
|
| 109 |
+
docs = text_splitter.split_documents(docs)
|
| 110 |
+
vector_db.add_documents(docs)
|
| 111 |
+
|
| 112 |
+
vector_db.save_local("vector_db", index_name="base_and_adjacent")
|
| 113 |
+
|
| 114 |
+
return ["Here are the papers on" + query] , papers # Return the list of paper dictionaries
|
| 115 |
+
|
agents/summarization_agent.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain.vectorstores import FAISS
|
| 2 |
+
from langchain_google_genai import GoogleGenerativeAIEmbeddings
|
| 3 |
+
import os
|
| 4 |
+
import streamlit as st
|
| 5 |
+
from agents import SearchAgent
|
| 6 |
+
from config.config import model
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001")
|
| 11 |
+
|
| 12 |
+
class SummarizationAgent:
|
| 13 |
+
def __init__(self):
|
| 14 |
+
self.model = model
|
| 15 |
+
self.prompt = """You are a research assistant tasked with synthesizing findings from multiple academic papers over time. Your goal is to create a comprehensive summary that highlights key trends, thematic developments, and methodological evolution within a given timeframe.
|
| 16 |
+
|
| 17 |
+
Given the following context, analyze the papers to produce a structured summary:
|
| 18 |
+
|
| 19 |
+
Previous conversation:
|
| 20 |
+
{chat_history}
|
| 21 |
+
|
| 22 |
+
Papers context:
|
| 23 |
+
{context}
|
| 24 |
+
|
| 25 |
+
Guidelines for timeline-based summarization:
|
| 26 |
+
|
| 27 |
+
Key Findings and Trends Over Time
|
| 28 |
+
|
| 29 |
+
Identify major discoveries and conclusions, highlighting how they have developed chronologically.
|
| 30 |
+
Note emerging trends, consensus, and any evolving contradictions across papers, especially in response to new technologies or shifts in the field.
|
| 31 |
+
Present statistical evidence and experimental results in relation to time, pointing out any measurable improvements or declines over the years.
|
| 32 |
+
Methodological Evolution
|
| 33 |
+
|
| 34 |
+
Compare and contrast research approaches across different time periods, emphasizing changes or advances in data collection, analysis techniques, or tools.
|
| 35 |
+
Identify and describe innovative methodological contributions and how these may have impacted research outcomes over time.
|
| 36 |
+
Theoretical Progression
|
| 37 |
+
|
| 38 |
+
Outline the theoretical foundations and highlight their chronological development.
|
| 39 |
+
Connect findings to existing theories, noting how interpretations or theoretical perspectives have evolved.
|
| 40 |
+
Identify theoretical advances, challenges, or shifts and their relationship to the timeline.
|
| 41 |
+
Practical Applications and Temporal Shifts
|
| 42 |
+
|
| 43 |
+
Discuss real-world applications over time, noting how findings have influenced industry practices or technology adoption.
|
| 44 |
+
Highlight evolving practical use cases and how implementation considerations have changed with advances in research.
|
| 45 |
+
Research Gaps and Future Directions
|
| 46 |
+
|
| 47 |
+
Identify limitations in studies across time periods, noting any improvement or persistent gaps.
|
| 48 |
+
Point out unexplored areas and suggest specific future research directions informed by chronological developments in the field.
|
| 49 |
+
Formatting and Style:
|
| 50 |
+
|
| 51 |
+
Organize the summary with clear sections that reflect the temporal progression.
|
| 52 |
+
Maintain an academic tone, using specific examples, dates, and quotes where relevant.
|
| 53 |
+
Clearly identify and label sections to enhance readability, and acknowledge any limitations in the available context.
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
self.papers = None
|
| 57 |
+
self.search_agent_response = ""
|
| 58 |
+
|
| 59 |
+
def solve(self, query):
|
| 60 |
+
# Check if search has been performed
|
| 61 |
+
if not os.path.exists("vector_db"):
|
| 62 |
+
st.warning("No papers loaded. Performing search first...")
|
| 63 |
+
search_agent = SearchAgent()
|
| 64 |
+
self.search_agent_response, self.papers = search_agent.solve(query)
|
| 65 |
+
|
| 66 |
+
# Load vector store
|
| 67 |
+
vector_db = FAISS.load_local("vector_db", embeddings, index_name="base_and_adjacent", allow_dangerous_deserialization=True)
|
| 68 |
+
|
| 69 |
+
# Get chat history
|
| 70 |
+
chat_history = st.session_state.get("chat_history", [])
|
| 71 |
+
chat_history_text = "\n".join([f"{sender}: {msg}" for sender, msg in chat_history[-5:]])
|
| 72 |
+
|
| 73 |
+
# Get relevant chunks from all papers
|
| 74 |
+
retrieved = vector_db.as_retriever(
|
| 75 |
+
search_kwargs={"k": 10} # Increase number of chunks to get broader context
|
| 76 |
+
).get_relevant_documents(query)
|
| 77 |
+
|
| 78 |
+
# Organize context by paper
|
| 79 |
+
context = self._organize_context(retrieved)
|
| 80 |
+
|
| 81 |
+
# Generate summary
|
| 82 |
+
full_prompt = self.prompt.format(
|
| 83 |
+
chat_history=chat_history_text,
|
| 84 |
+
context=context
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
response = self.model.generate_content(str(self.search_agent_response) + full_prompt)
|
| 88 |
+
return response.text, self.papers
|
| 89 |
+
|
| 90 |
+
def _organize_context(self, documents):
|
| 91 |
+
"""
|
| 92 |
+
Organizes retrieved chunks by paper and creates a structured context.
|
| 93 |
+
"""
|
| 94 |
+
# Group chunks by paper
|
| 95 |
+
paper_chunks = {}
|
| 96 |
+
for doc in documents:
|
| 97 |
+
paper_id = doc.metadata.get('source', 'unknown')
|
| 98 |
+
if paper_id not in paper_chunks:
|
| 99 |
+
paper_chunks[paper_id] = []
|
| 100 |
+
paper_chunks[paper_id].append(doc.page_content)
|
| 101 |
+
|
| 102 |
+
# Create structured context
|
| 103 |
+
organized_context = []
|
| 104 |
+
for paper_id, chunks in paper_chunks.items():
|
| 105 |
+
paper_context = f"\nPaper: {paper_id}\n"
|
| 106 |
+
paper_context += "\n".join(chunks)
|
| 107 |
+
organized_context.append(paper_context)
|
| 108 |
+
|
| 109 |
+
return "\n\n".join(organized_context)
|
app.py
CHANGED
|
@@ -1,277 +1,277 @@
|
|
| 1 |
-
import streamlit as st
|
| 2 |
-
import os
|
| 3 |
-
import sys
|
| 4 |
-
from typing import Tuple, List, Dict, Optional
|
| 5 |
-
from router import Router
|
| 6 |
-
|
| 7 |
-
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 8 |
-
|
| 9 |
-
class AcademicResearchAssistant:
|
| 10 |
-
def __init__(self):
|
| 11 |
-
|
| 12 |
-
self.router = Router()
|
| 13 |
-
self.setup_streamlit_config()
|
| 14 |
-
self.initialize_session_state()
|
| 15 |
-
|
| 16 |
-
def setup_streamlit_config(self):
|
| 17 |
-
|
| 18 |
-
st.set_page_config(
|
| 19 |
-
page_title="Academic Research Assistant",
|
| 20 |
-
page_icon="π",
|
| 21 |
-
layout="wide",
|
| 22 |
-
initial_sidebar_state="expanded",
|
| 23 |
-
menu_items={
|
| 24 |
-
'Get Help': 'https://github.com/yourusername/academic-research-assistant',
|
| 25 |
-
'Report a bug': "https://github.com/yourusername/academic-research-assistant/issues",
|
| 26 |
-
'About': "# Academic Research Assistant v1.0\nYour intelligent research companion."
|
| 27 |
-
}
|
| 28 |
-
)
|
| 29 |
-
|
| 30 |
-
# Custom CSS to enhance the UI
|
| 31 |
-
st.markdown("""
|
| 32 |
-
<style>
|
| 33 |
-
.stApp {
|
| 34 |
-
background: linear-gradient(to bottom right, #f5f7fa, #eef2f7);
|
| 35 |
-
}
|
| 36 |
-
.stButton>button {
|
| 37 |
-
background-color: #1f4287;
|
| 38 |
-
color: white;
|
| 39 |
-
border-radius: 5px;
|
| 40 |
-
padding: 0.5rem 1rem;
|
| 41 |
-
}
|
| 42 |
-
.stProgress .st-bo {
|
| 43 |
-
background-color: #1f4287;
|
| 44 |
-
}
|
| 45 |
-
.chat-message {
|
| 46 |
-
padding: 10px;
|
| 47 |
-
border-radius: 5px;
|
| 48 |
-
margin: 5px 0;
|
| 49 |
-
animation: fadeIn 0.5s ease-in;
|
| 50 |
-
}
|
| 51 |
-
.user-message {
|
| 52 |
-
background-color: #e6f3ff;
|
| 53 |
-
}
|
| 54 |
-
.bot-message {
|
| 55 |
-
background-color: #f0f2f6;
|
| 56 |
-
}
|
| 57 |
-
@keyframes fadeIn {
|
| 58 |
-
from {opacity: 0;}
|
| 59 |
-
to {opacity: 1;}
|
| 60 |
-
}
|
| 61 |
-
.paper-card {
|
| 62 |
-
background-color: white;
|
| 63 |
-
padding: 1.5rem;
|
| 64 |
-
border-radius: 10px;
|
| 65 |
-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| 66 |
-
margin-bottom: 1rem;
|
| 67 |
-
}
|
| 68 |
-
.paper-title {
|
| 69 |
-
color: #1f4287;
|
| 70 |
-
font-size: 1.1rem;
|
| 71 |
-
font-weight: bold;
|
| 72 |
-
margin-bottom: 0.5rem;
|
| 73 |
-
}
|
| 74 |
-
.paper-metadata {
|
| 75 |
-
font-size: 0.9rem;
|
| 76 |
-
color: #666;
|
| 77 |
-
margin-bottom: 0.5rem;
|
| 78 |
-
}
|
| 79 |
-
.paper-abstract {
|
| 80 |
-
font-size: 0.95rem;
|
| 81 |
-
line-height: 1.5;
|
| 82 |
-
margin-top: 1rem;
|
| 83 |
-
padding-left: 1rem;
|
| 84 |
-
border-left: 3px solid #1f4287;
|
| 85 |
-
}
|
| 86 |
-
.download-button {
|
| 87 |
-
background-color: #4CAF50;
|
| 88 |
-
color: white;
|
| 89 |
-
padding: 0.5rem 1rem;
|
| 90 |
-
border-radius: 5px;
|
| 91 |
-
text-decoration: none;
|
| 92 |
-
display: inline-block;
|
| 93 |
-
margin-top: 1rem;
|
| 94 |
-
}
|
| 95 |
-
.metric-card {
|
| 96 |
-
background-color: white;
|
| 97 |
-
padding: 1rem;
|
| 98 |
-
border-radius: 8px;
|
| 99 |
-
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
| 100 |
-
text-align: center;
|
| 101 |
-
}
|
| 102 |
-
</style>
|
| 103 |
-
""", unsafe_allow_html=True)
|
| 104 |
-
|
| 105 |
-
def initialize_session_state(self):
|
| 106 |
-
|
| 107 |
-
if "chat_history" not in st.session_state:
|
| 108 |
-
st.session_state.chat_history = []
|
| 109 |
-
if "fetched_papers" not in st.session_state:
|
| 110 |
-
st.session_state.fetched_papers = []
|
| 111 |
-
if "search_count" not in st.session_state:
|
| 112 |
-
st.session_state.search_count = 0
|
| 113 |
-
if "total_searches" not in st.session_state:
|
| 114 |
-
st.session_state.total_searches = 0
|
| 115 |
-
|
| 116 |
-
def display_welcome_message(self):
|
| 117 |
-
|
| 118 |
-
st.title("π Academic Research Paper Assistant")
|
| 119 |
-
|
| 120 |
-
# Create three columns for metrics
|
| 121 |
-
col1, col2, col3, col4 = st.columns([2, 1, 1, 1])
|
| 122 |
-
|
| 123 |
-
with col1:
|
| 124 |
-
st.markdown("""
|
| 125 |
-
Welcome to your intelligent research companion! This tool helps you:
|
| 126 |
-
- π Find relevant academic papers
|
| 127 |
-
- π Analyze research trends
|
| 128 |
-
- π Access paper summaries
|
| 129 |
-
- π₯ Download full papers
|
| 130 |
-
""")
|
| 131 |
-
|
| 132 |
-
# Display metrics in cards
|
| 133 |
-
with col3:
|
| 134 |
-
st.markdown("""
|
| 135 |
-
<div class="metric-card">
|
| 136 |
-
<h3>Papers Found</h3>
|
| 137 |
-
<h2>{}</h2>
|
| 138 |
-
</div>
|
| 139 |
-
""".format(len(st.session_state.fetched_papers)), unsafe_allow_html=True)
|
| 140 |
-
|
| 141 |
-
with col4:
|
| 142 |
-
st.markdown("""
|
| 143 |
-
<div class="metric-card">
|
| 144 |
-
<h3>Total Searches</h3>
|
| 145 |
-
<h2>{}</h2>
|
| 146 |
-
</div>
|
| 147 |
-
""".format(st.session_state.total_searches), unsafe_allow_html=True)
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
def create_chat_interface(self) -> Tuple[str, bool]:
|
| 152 |
-
|
| 153 |
-
with st.container():
|
| 154 |
-
st.write("### π¬ Research Query Interface")
|
| 155 |
-
|
| 156 |
-
# Create columns for better layout
|
| 157 |
-
col1, col2 = st.columns([4, 1])
|
| 158 |
-
|
| 159 |
-
with col1:
|
| 160 |
-
user_input = st.text_input(
|
| 161 |
-
"Enter your research query (e.g., 'Recent advances in quantum computing')",
|
| 162 |
-
key="user_input",
|
| 163 |
-
placeholder="Type your research question here...",
|
| 164 |
-
max_chars=500
|
| 165 |
-
)
|
| 166 |
-
|
| 167 |
-
col3, col4, col5 = st.columns([2, 1, 1])
|
| 168 |
-
with col3:
|
| 169 |
-
send_button = st.button("π Search ", use_container_width=True)
|
| 170 |
-
with col4:
|
| 171 |
-
clear_button = st.button("ποΈ Clear History", use_container_width=True)
|
| 172 |
-
|
| 173 |
-
if clear_button:
|
| 174 |
-
st.session_state.chat_history = []
|
| 175 |
-
st.session_state.fetched_papers = []
|
| 176 |
-
st.session_state.search_count = 0
|
| 177 |
-
st.session_state.total_searches = 0
|
| 178 |
-
st.rerun()
|
| 179 |
-
|
| 180 |
-
return user_input, send_button
|
| 181 |
-
|
| 182 |
-
def process_user_input(self, user_input: str):
|
| 183 |
-
|
| 184 |
-
with st.spinner('π Working on response...'):
|
| 185 |
-
# Update search metrics
|
| 186 |
-
st.session_state.search_count = len(st.session_state.fetched_papers)
|
| 187 |
-
st.session_state.total_searches += 1
|
| 188 |
-
|
| 189 |
-
try:
|
| 190 |
-
# Get response from router
|
| 191 |
-
response, papers = self.router.route_query(user_input)
|
| 192 |
-
|
| 193 |
-
# Update papers in session state
|
| 194 |
-
if papers:
|
| 195 |
-
unique_papers = {paper['paper_number']: paper for paper in papers}
|
| 196 |
-
st.session_state.fetched_papers = list(unique_papers.values())
|
| 197 |
-
|
| 198 |
-
# Add bot response and use message to chat history
|
| 199 |
-
if response:
|
| 200 |
-
st.session_state.chat_history.append(("Bot", response))
|
| 201 |
-
st.session_state.chat_history.append(("User", user_input))
|
| 202 |
-
else:
|
| 203 |
-
st.session_state.chat_history.append(
|
| 204 |
-
("Bot", "I couldn't find relevant papers for your query. Please try rephrasing or use more specific terms.")
|
| 205 |
-
)
|
| 206 |
-
except Exception as e:
|
| 207 |
-
st.session_state.chat_history.append(
|
| 208 |
-
("Bot", f"An error occurred while processing your request: {str(e)}")
|
| 209 |
-
)
|
| 210 |
-
st.error("There was an error processing your request. Please try again.")
|
| 211 |
-
|
| 212 |
-
def display_chat_history(self):
|
| 213 |
-
"""Display the chat history with user and bot messages"""
|
| 214 |
-
for sender, message in reversed(st.session_state.chat_history):
|
| 215 |
-
if sender == "User":
|
| 216 |
-
st.markdown(
|
| 217 |
-
"<div class='chat-message user-message'>"
|
| 218 |
-
f"<strong>π€ You:</strong> {message}"
|
| 219 |
-
"</div>",
|
| 220 |
-
unsafe_allow_html=True
|
| 221 |
-
)
|
| 222 |
-
else:
|
| 223 |
-
st.markdown(
|
| 224 |
-
"<div class='chat-message bot-message'>"
|
| 225 |
-
f"<strong>π€ Assistant:</strong> {message[0]}"
|
| 226 |
-
"</div>",
|
| 227 |
-
unsafe_allow_html=True
|
| 228 |
-
)
|
| 229 |
-
|
| 230 |
-
def display_papers(self):
|
| 231 |
-
"""Display the list of fetched papers with download links"""
|
| 232 |
-
st.write("### π Retrieved Research Papers")
|
| 233 |
-
if st.session_state.fetched_papers:
|
| 234 |
-
for paper in st.session_state.fetched_papers:
|
| 235 |
-
with st.expander(f"π {paper.get('title', 'Untitled Paper')}"):
|
| 236 |
-
st.markdown(
|
| 237 |
-
"<div class='paper-card'>"
|
| 238 |
-
f"<div class='paper-title'>{paper.get('title', '').replace('\n', ' ').strip()}</div>"
|
| 239 |
-
f"<div class='paper-metadata'>Year: {paper.get('year', 'N/A')} | Paper ID: {paper.get('paper_number', 'N/A')}</div>"
|
| 240 |
-
f"""{'<div class="paper-abstract">' + paper.get('abstract', '') + '</div>' if paper.get('abstract') else ''}"""
|
| 241 |
-
"</div>",
|
| 242 |
-
unsafe_allow_html=True
|
| 243 |
-
)
|
| 244 |
-
|
| 245 |
-
download_link = paper.get('link')
|
| 246 |
-
if download_link:
|
| 247 |
-
st.markdown(f"[π₯ Download PDF]({download_link})")
|
| 248 |
-
else:
|
| 249 |
-
st.warning("β οΈ No download link available")
|
| 250 |
-
else:
|
| 251 |
-
st.info("π No papers fetched yet. Start by entering a research query above!")
|
| 252 |
-
|
| 253 |
-
def run(self):
|
| 254 |
-
"""Main method to run the application"""
|
| 255 |
-
self.display_welcome_message()
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
user_input, send_button = self.create_chat_interface()
|
| 259 |
-
|
| 260 |
-
st.markdown("### π¬ Chat History")
|
| 261 |
-
self.display_chat_history()
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
if user_input and send_button:
|
| 265 |
-
self.process_user_input(user_input)
|
| 266 |
-
st.rerun()
|
| 267 |
-
|
| 268 |
-
st.markdown("---")
|
| 269 |
-
self.display_papers()
|
| 270 |
-
|
| 271 |
-
def main():
|
| 272 |
-
|
| 273 |
-
app = AcademicResearchAssistant()
|
| 274 |
-
app.run()
|
| 275 |
-
|
| 276 |
-
if __name__ == "__main__":
|
| 277 |
main()
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
from typing import Tuple, List, Dict, Optional
|
| 5 |
+
from router import Router
|
| 6 |
+
|
| 7 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 8 |
+
|
| 9 |
+
class AcademicResearchAssistant:
|
| 10 |
+
def __init__(self):
|
| 11 |
+
|
| 12 |
+
self.router = Router()
|
| 13 |
+
self.setup_streamlit_config()
|
| 14 |
+
self.initialize_session_state()
|
| 15 |
+
|
| 16 |
+
def setup_streamlit_config(self):
|
| 17 |
+
|
| 18 |
+
st.set_page_config(
|
| 19 |
+
page_title="Academic Research Assistant",
|
| 20 |
+
page_icon="π",
|
| 21 |
+
layout="wide",
|
| 22 |
+
initial_sidebar_state="expanded",
|
| 23 |
+
menu_items={
|
| 24 |
+
'Get Help': 'https://github.com/yourusername/academic-research-assistant',
|
| 25 |
+
'Report a bug': "https://github.com/yourusername/academic-research-assistant/issues",
|
| 26 |
+
'About': "# Academic Research Assistant v1.0\nYour intelligent research companion."
|
| 27 |
+
}
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
# Custom CSS to enhance the UI
|
| 31 |
+
st.markdown("""
|
| 32 |
+
<style>
|
| 33 |
+
.stApp {
|
| 34 |
+
background: linear-gradient(to bottom right, #f5f7fa, #eef2f7);
|
| 35 |
+
}
|
| 36 |
+
.stButton>button {
|
| 37 |
+
background-color: #1f4287;
|
| 38 |
+
color: white;
|
| 39 |
+
border-radius: 5px;
|
| 40 |
+
padding: 0.5rem 1rem;
|
| 41 |
+
}
|
| 42 |
+
.stProgress .st-bo {
|
| 43 |
+
background-color: #1f4287;
|
| 44 |
+
}
|
| 45 |
+
.chat-message {
|
| 46 |
+
padding: 10px;
|
| 47 |
+
border-radius: 5px;
|
| 48 |
+
margin: 5px 0;
|
| 49 |
+
animation: fadeIn 0.5s ease-in;
|
| 50 |
+
}
|
| 51 |
+
.user-message {
|
| 52 |
+
background-color: #e6f3ff;
|
| 53 |
+
}
|
| 54 |
+
.bot-message {
|
| 55 |
+
background-color: #f0f2f6;
|
| 56 |
+
}
|
| 57 |
+
@keyframes fadeIn {
|
| 58 |
+
from {opacity: 0;}
|
| 59 |
+
to {opacity: 1;}
|
| 60 |
+
}
|
| 61 |
+
.paper-card {
|
| 62 |
+
background-color: white;
|
| 63 |
+
padding: 1.5rem;
|
| 64 |
+
border-radius: 10px;
|
| 65 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| 66 |
+
margin-bottom: 1rem;
|
| 67 |
+
}
|
| 68 |
+
.paper-title {
|
| 69 |
+
color: #1f4287;
|
| 70 |
+
font-size: 1.1rem;
|
| 71 |
+
font-weight: bold;
|
| 72 |
+
margin-bottom: 0.5rem;
|
| 73 |
+
}
|
| 74 |
+
.paper-metadata {
|
| 75 |
+
font-size: 0.9rem;
|
| 76 |
+
color: #666;
|
| 77 |
+
margin-bottom: 0.5rem;
|
| 78 |
+
}
|
| 79 |
+
.paper-abstract {
|
| 80 |
+
font-size: 0.95rem;
|
| 81 |
+
line-height: 1.5;
|
| 82 |
+
margin-top: 1rem;
|
| 83 |
+
padding-left: 1rem;
|
| 84 |
+
border-left: 3px solid #1f4287;
|
| 85 |
+
}
|
| 86 |
+
.download-button {
|
| 87 |
+
background-color: #4CAF50;
|
| 88 |
+
color: white;
|
| 89 |
+
padding: 0.5rem 1rem;
|
| 90 |
+
border-radius: 5px;
|
| 91 |
+
text-decoration: none;
|
| 92 |
+
display: inline-block;
|
| 93 |
+
margin-top: 1rem;
|
| 94 |
+
}
|
| 95 |
+
.metric-card {
|
| 96 |
+
background-color: white;
|
| 97 |
+
padding: 1rem;
|
| 98 |
+
border-radius: 8px;
|
| 99 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
| 100 |
+
text-align: center;
|
| 101 |
+
}
|
| 102 |
+
</style>
|
| 103 |
+
""", unsafe_allow_html=True)
|
| 104 |
+
|
| 105 |
+
def initialize_session_state(self):
|
| 106 |
+
|
| 107 |
+
if "chat_history" not in st.session_state:
|
| 108 |
+
st.session_state.chat_history = []
|
| 109 |
+
if "fetched_papers" not in st.session_state:
|
| 110 |
+
st.session_state.fetched_papers = []
|
| 111 |
+
if "search_count" not in st.session_state:
|
| 112 |
+
st.session_state.search_count = 0
|
| 113 |
+
if "total_searches" not in st.session_state:
|
| 114 |
+
st.session_state.total_searches = 0
|
| 115 |
+
|
| 116 |
+
def display_welcome_message(self):
|
| 117 |
+
|
| 118 |
+
st.title("π Academic Research Paper Assistant")
|
| 119 |
+
|
| 120 |
+
# Create three columns for metrics
|
| 121 |
+
col1, col2, col3, col4 = st.columns([2, 1, 1, 1])
|
| 122 |
+
|
| 123 |
+
with col1:
|
| 124 |
+
st.markdown("""
|
| 125 |
+
Welcome to your intelligent research companion! This tool helps you:
|
| 126 |
+
- π Find relevant academic papers
|
| 127 |
+
- π Analyze research trends
|
| 128 |
+
- π Access paper summaries
|
| 129 |
+
- π₯ Download full papers
|
| 130 |
+
""")
|
| 131 |
+
|
| 132 |
+
# Display metrics in cards
|
| 133 |
+
with col3:
|
| 134 |
+
st.markdown("""
|
| 135 |
+
<div class="metric-card">
|
| 136 |
+
<h3>Papers Found</h3>
|
| 137 |
+
<h2>{}</h2>
|
| 138 |
+
</div>
|
| 139 |
+
""".format(len(st.session_state.fetched_papers)), unsafe_allow_html=True)
|
| 140 |
+
|
| 141 |
+
with col4:
|
| 142 |
+
st.markdown("""
|
| 143 |
+
<div class="metric-card">
|
| 144 |
+
<h3>Total Searches</h3>
|
| 145 |
+
<h2>{}</h2>
|
| 146 |
+
</div>
|
| 147 |
+
""".format(st.session_state.total_searches), unsafe_allow_html=True)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def create_chat_interface(self) -> Tuple[str, bool]:
|
| 152 |
+
|
| 153 |
+
with st.container():
|
| 154 |
+
st.write("### π¬ Research Query Interface")
|
| 155 |
+
|
| 156 |
+
# Create columns for better layout
|
| 157 |
+
col1, col2 = st.columns([4, 1])
|
| 158 |
+
|
| 159 |
+
with col1:
|
| 160 |
+
user_input = st.text_input(
|
| 161 |
+
"Enter your research query (e.g., 'Recent advances in quantum computing')",
|
| 162 |
+
key="user_input",
|
| 163 |
+
placeholder="Type your research question here...",
|
| 164 |
+
max_chars=500
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
col3, col4, col5 = st.columns([2, 1, 1])
|
| 168 |
+
with col3:
|
| 169 |
+
send_button = st.button("π Search ", use_container_width=True)
|
| 170 |
+
with col4:
|
| 171 |
+
clear_button = st.button("ποΈ Clear History", use_container_width=True)
|
| 172 |
+
|
| 173 |
+
if clear_button:
|
| 174 |
+
st.session_state.chat_history = []
|
| 175 |
+
st.session_state.fetched_papers = []
|
| 176 |
+
st.session_state.search_count = 0
|
| 177 |
+
st.session_state.total_searches = 0
|
| 178 |
+
st.rerun()
|
| 179 |
+
|
| 180 |
+
return user_input, send_button
|
| 181 |
+
|
| 182 |
+
def process_user_input(self, user_input: str):
|
| 183 |
+
|
| 184 |
+
with st.spinner('π Working on response...'):
|
| 185 |
+
# Update search metrics
|
| 186 |
+
st.session_state.search_count = len(st.session_state.fetched_papers)
|
| 187 |
+
st.session_state.total_searches += 1
|
| 188 |
+
|
| 189 |
+
try:
|
| 190 |
+
# Get response from router
|
| 191 |
+
response, papers = self.router.route_query(user_input)
|
| 192 |
+
|
| 193 |
+
# Update papers in session state
|
| 194 |
+
if papers:
|
| 195 |
+
unique_papers = {paper['paper_number']: paper for paper in papers}
|
| 196 |
+
st.session_state.fetched_papers = list(unique_papers.values())
|
| 197 |
+
|
| 198 |
+
# Add bot response and use message to chat history
|
| 199 |
+
if response:
|
| 200 |
+
st.session_state.chat_history.append(("Bot", response))
|
| 201 |
+
st.session_state.chat_history.append(("User", user_input))
|
| 202 |
+
else:
|
| 203 |
+
st.session_state.chat_history.append(
|
| 204 |
+
("Bot", "I couldn't find relevant papers for your query. Please try rephrasing or use more specific terms.")
|
| 205 |
+
)
|
| 206 |
+
except Exception as e:
|
| 207 |
+
st.session_state.chat_history.append(
|
| 208 |
+
("Bot", f"An error occurred while processing your request: {str(e)}")
|
| 209 |
+
)
|
| 210 |
+
st.error("There was an error processing your request. Please try again.")
|
| 211 |
+
|
| 212 |
+
def display_chat_history(self):
|
| 213 |
+
"""Display the chat history with user and bot messages"""
|
| 214 |
+
for sender, message in reversed(st.session_state.chat_history):
|
| 215 |
+
if sender == "User":
|
| 216 |
+
st.markdown(
|
| 217 |
+
"<div class='chat-message user-message'>"
|
| 218 |
+
f"<strong>π€ You:</strong> {message}"
|
| 219 |
+
"</div>",
|
| 220 |
+
unsafe_allow_html=True
|
| 221 |
+
)
|
| 222 |
+
else:
|
| 223 |
+
st.markdown(
|
| 224 |
+
"<div class='chat-message bot-message'>"
|
| 225 |
+
f"<strong>π€ Assistant:</strong> {message[0]}"
|
| 226 |
+
"</div>",
|
| 227 |
+
unsafe_allow_html=True
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
def display_papers(self):
|
| 231 |
+
"""Display the list of fetched papers with download links"""
|
| 232 |
+
st.write("### π Retrieved Research Papers")
|
| 233 |
+
if st.session_state.fetched_papers:
|
| 234 |
+
for paper in st.session_state.fetched_papers:
|
| 235 |
+
with st.expander(f"π {paper.get('title', 'Untitled Paper')}"):
|
| 236 |
+
st.markdown(
|
| 237 |
+
"<div class='paper-card'>"
|
| 238 |
+
f"<div class='paper-title'>{paper.get('title', '').replace('\n', ' ').strip()}</div>"
|
| 239 |
+
f"<div class='paper-metadata'>Year: {paper.get('year', 'N/A')} | Paper ID: {paper.get('paper_number', 'N/A')}</div>"
|
| 240 |
+
f"""{'<div class="paper-abstract">' + paper.get('abstract', '') + '</div>' if paper.get('abstract') else ''}"""
|
| 241 |
+
"</div>",
|
| 242 |
+
unsafe_allow_html=True
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
download_link = paper.get('link')
|
| 246 |
+
if download_link:
|
| 247 |
+
st.markdown(f"[π₯ Download PDF]({download_link})")
|
| 248 |
+
else:
|
| 249 |
+
st.warning("β οΈ No download link available")
|
| 250 |
+
else:
|
| 251 |
+
st.info("π No papers fetched yet. Start by entering a research query above!")
|
| 252 |
+
|
| 253 |
+
def run(self):
|
| 254 |
+
"""Main method to run the application"""
|
| 255 |
+
self.display_welcome_message()
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
user_input, send_button = self.create_chat_interface()
|
| 259 |
+
|
| 260 |
+
st.markdown("### π¬ Chat History")
|
| 261 |
+
self.display_chat_history()
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
if user_input and send_button:
|
| 265 |
+
self.process_user_input(user_input)
|
| 266 |
+
st.rerun()
|
| 267 |
+
|
| 268 |
+
st.markdown("---")
|
| 269 |
+
self.display_papers()
|
| 270 |
+
|
| 271 |
+
def main():
|
| 272 |
+
|
| 273 |
+
app = AcademicResearchAssistant()
|
| 274 |
+
app.run()
|
| 275 |
+
|
| 276 |
+
if __name__ == "__main__":
|
| 277 |
main()
|
config/config.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import google.generativeai as genai
|
| 2 |
+
import os
|
| 3 |
+
GEMINI_API_KEY = "AIzaSyD6OXS89hHRqzGCY1klK9A8qNlG0sJEvAU"
|
| 4 |
+
|
| 5 |
+
genai.configure(api_key=GEMINI_API_KEY)
|
| 6 |
+
|
| 7 |
+
if "GOOGLE_API_KEY" not in os.environ:
|
| 8 |
+
os.environ["GOOGLE_API_KEY"] = GEMINI_API_KEY
|
| 9 |
+
|
| 10 |
+
model = genai.GenerativeModel(model_name="gemini-1.5-flash")
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
imgs/Frontend.png
ADDED
|
imgs/Q1.png
ADDED
|
imgs/Q2.png
ADDED
|
imgs/papers.png
ADDED
|
imgs/papers2.png
ADDED
|
router.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from agents import IntentAgent, SearchAgent, QAAgent, FutureWorksAgent , SummarizationAgent
|
| 2 |
+
import streamlit as st
|
| 3 |
+
class Router:
|
| 4 |
+
def __init__(self):
|
| 5 |
+
self.intent_agent = IntentAgent()
|
| 6 |
+
self.agents = {
|
| 7 |
+
"search": SearchAgent(),
|
| 8 |
+
"qa": QAAgent(),
|
| 9 |
+
"future_works": FutureWorksAgent(),
|
| 10 |
+
"summarize": SummarizationAgent()
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
def route_query(self, query):
|
| 14 |
+
|
| 15 |
+
intent = self.intent_agent.get_intent(query)
|
| 16 |
+
agent = self.agents.get(intent)
|
| 17 |
+
st.write(f"Using {intent} agent...")
|
| 18 |
+
if agent:
|
| 19 |
+
if intent == "search":
|
| 20 |
+
ans , d = agent.solve(query)
|
| 21 |
+
return ans , d
|
| 22 |
+
return agent.solve(query) , None
|
| 23 |
+
else:
|
| 24 |
+
return "Sorry, I couldn't understand your query. Please give valid question" , None
|