Spaces:
Sleeping
Sleeping
Commit
·
58c21ea
1
Parent(s):
a213258
Enhance paper loading and searching functionality by adding filename normalization, improved matching logic, and structured summaries. The system now prioritizes full paper content in responses and includes detailed sections like abstract, introduction, methodology, results, and conclusions in summaries. Updated user prompts to reflect new capabilities.
Browse files- IMPROVEMENTS.md +77 -0
- __pycache__/app.cpython-313.pyc +0 -0
- app.py +184 -21
- test_functionality.py +85 -0
IMPROVEMENTS.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Paperbot Improvements Summary
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
Enhanced the AI Research Paper Chatbot to better connect filenames from the abstracts database to the corresponding full text files in the Papers folder, enabling retrieval of comprehensive information from complete papers rather than just abstracts.
|
| 5 |
+
|
| 6 |
+
## Key Improvements
|
| 7 |
+
|
| 8 |
+
### 1. Enhanced Filename Matching System
|
| 9 |
+
- **Added `normalize_filename()` function**: Normalizes filenames by removing special characters, converting to lowercase, and standardizing spacing
|
| 10 |
+
- **Added `find_matching_paper_file()` function**: Uses sophisticated matching algorithms to find the best matching paper file based on query terms
|
| 11 |
+
- **Improved search relevance**: Better scoring system that prioritizes exact matches and word overlaps
|
| 12 |
+
|
| 13 |
+
### 2. Improved Paper Content Retrieval
|
| 14 |
+
- **Enhanced `search_papers()` function**: Now returns up to 5 most relevant papers instead of 3, with better relevance scoring
|
| 15 |
+
- **Better content truncation**: Provides more content (up to 12,000 characters) for full paper requests
|
| 16 |
+
- **Improved title extraction**: Properly handles filename to title conversion
|
| 17 |
+
|
| 18 |
+
### 3. New Paper Summary Functionality
|
| 19 |
+
- **Added `get_paper_summary()` function**: Extracts and structures key sections of papers including:
|
| 20 |
+
- Abstract
|
| 21 |
+
- Introduction
|
| 22 |
+
- Methodology
|
| 23 |
+
- Results
|
| 24 |
+
- Conclusions
|
| 25 |
+
- **Structured output**: Provides organized summaries when users request paper summaries
|
| 26 |
+
|
| 27 |
+
### 4. Enhanced System Prompt
|
| 28 |
+
- **Updated instructions**: Added guidance for using full paper content instead of just abstracts
|
| 29 |
+
- **Better context**: System now prioritizes full paper content when available
|
| 30 |
+
- **New capabilities**: Supports both full paper retrieval and structured summaries
|
| 31 |
+
|
| 32 |
+
### 5. Improved User Experience
|
| 33 |
+
- **Better example queries**: Added new example button for testing summary functionality
|
| 34 |
+
- **Enhanced error handling**: Better handling of missing files and edge cases
|
| 35 |
+
- **More informative responses**: Shows relevance scores and better content organization
|
| 36 |
+
|
| 37 |
+
## Technical Details
|
| 38 |
+
|
| 39 |
+
### Filename Matching Algorithm
|
| 40 |
+
The system now uses a multi-stage matching approach:
|
| 41 |
+
1. **Exact matching**: Checks for exact substring matches in normalized filenames
|
| 42 |
+
2. **Word overlap**: Counts overlapping words between query and filename
|
| 43 |
+
3. **Partial matching**: Checks for partial word matches
|
| 44 |
+
4. **Scoring**: Assigns scores based on match quality and prioritizes best matches
|
| 45 |
+
|
| 46 |
+
### Content Retrieval Strategy
|
| 47 |
+
- **Full paper requests**: Provides up to 12,000 characters of content
|
| 48 |
+
- **Summary requests**: Extracts and structures key sections
|
| 49 |
+
- **General queries**: Provides up to 3,000 characters for context
|
| 50 |
+
- **Conclusion requests**: Extracts conclusion sections specifically
|
| 51 |
+
|
| 52 |
+
### Data Structure
|
| 53 |
+
- **Papers dictionary**: Now uses filenames as keys for better matching
|
| 54 |
+
- **Content mapping**: Direct connection between abstracts filenames and full text files
|
| 55 |
+
- **Metadata preservation**: Maintains original filenames while providing clean titles
|
| 56 |
+
|
| 57 |
+
## Testing Results
|
| 58 |
+
The system successfully:
|
| 59 |
+
- Loads 54 papers from the Papers folder
|
| 60 |
+
- Correctly matches queries to appropriate paper files
|
| 61 |
+
- Normalizes filenames for better matching
|
| 62 |
+
- Provides relevant content based on user queries
|
| 63 |
+
|
| 64 |
+
## Usage Examples
|
| 65 |
+
Users can now:
|
| 66 |
+
1. **Search for specific papers**: "Show me the paper about pigs"
|
| 67 |
+
2. **Request full content**: "Show me the full paper about AI companions"
|
| 68 |
+
3. **Get structured summaries**: "Summarize the paper about labor market effects"
|
| 69 |
+
4. **Find conclusions**: "What's the conclusion of the pig disease paper?"
|
| 70 |
+
5. **General queries**: "Find papers about transformer architecture"
|
| 71 |
+
|
| 72 |
+
## Benefits
|
| 73 |
+
1. **More comprehensive information**: Access to full paper content instead of just abstracts
|
| 74 |
+
2. **Better accuracy**: Direct quotes and detailed information from complete papers
|
| 75 |
+
3. **Improved relevance**: Better matching between user queries and paper content
|
| 76 |
+
4. **Structured responses**: Organized summaries with key sections clearly identified
|
| 77 |
+
5. **Enhanced user experience**: More informative and helpful responses
|
__pycache__/app.cpython-313.pyc
ADDED
|
Binary file (28.9 kB). View file
|
|
|
app.py
CHANGED
|
@@ -21,27 +21,74 @@ def load_abstracts_content():
|
|
| 21 |
|
| 22 |
# Load full paper texts
|
| 23 |
def load_paper_texts():
|
| 24 |
-
"""Load all paper texts from the Papers directory."""
|
| 25 |
papers = {}
|
| 26 |
papers_dir = "Papers"
|
| 27 |
|
| 28 |
if not os.path.exists(papers_dir):
|
| 29 |
return papers
|
| 30 |
|
|
|
|
| 31 |
for filename in os.listdir(papers_dir):
|
| 32 |
if filename.endswith('.txt'):
|
| 33 |
filepath = os.path.join(papers_dir, filename)
|
| 34 |
try:
|
| 35 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 36 |
content = f.read()
|
| 37 |
-
#
|
| 38 |
-
|
| 39 |
-
papers[title] = content
|
| 40 |
except Exception as e:
|
| 41 |
print(f"Error loading {filename}: {e}")
|
| 42 |
|
| 43 |
return papers
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
# Load abstracts content globally
|
| 46 |
ABSTRACTS_CONTENT = load_abstracts_content()
|
| 47 |
PAPER_TEXTS = load_paper_texts()
|
|
@@ -53,34 +100,55 @@ def search_papers(query: str, papers: Dict[str, str]) -> List[tuple[str, str, st
|
|
| 53 |
"""
|
| 54 |
results = []
|
| 55 |
query_lower = query.lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
relevance_score = 0
|
| 60 |
|
| 61 |
# Check if query terms appear in title
|
| 62 |
-
|
| 63 |
-
|
|
|
|
| 64 |
|
| 65 |
# Check if query terms appear in content
|
| 66 |
content_lower = content.lower()
|
| 67 |
-
for term in
|
| 68 |
if term in content_lower:
|
| 69 |
relevance_score += content_lower.count(term)
|
| 70 |
|
| 71 |
if relevance_score > 0:
|
| 72 |
-
#
|
| 73 |
if any(keyword in query.lower() for keyword in ["full paper", "complete paper", "entire paper", "show me the paper", "read the paper"]):
|
| 74 |
-
# Include more content for full paper requests
|
| 75 |
truncated_content = content[:8000] + "..." if len(content) > 8000 else content
|
| 76 |
else:
|
| 77 |
-
# Truncate content to first 2000 characters for context
|
| 78 |
truncated_content = content[:2000] + "..." if len(content) > 2000 else content
|
| 79 |
results.append((title, truncated_content, relevance_score))
|
| 80 |
|
| 81 |
# Sort by relevance score
|
| 82 |
results.sort(key=lambda x: x[2], reverse=True)
|
| 83 |
-
return results[:
|
| 84 |
|
| 85 |
def get_relevant_papers_content(user_query: str) -> str:
|
| 86 |
"""
|
|
@@ -94,9 +162,9 @@ def get_relevant_papers_content(user_query: str) -> str:
|
|
| 94 |
if not relevant_papers:
|
| 95 |
return ""
|
| 96 |
|
| 97 |
-
content = "\n\n===
|
| 98 |
for title, paper_content, score in relevant_papers:
|
| 99 |
-
content += f"\n--- {title} ---\n"
|
| 100 |
content += paper_content
|
| 101 |
content += "\n" + "="*50 + "\n"
|
| 102 |
|
|
@@ -110,10 +178,91 @@ def get_full_paper_content(paper_title: str) -> str:
|
|
| 110 |
return ""
|
| 111 |
|
| 112 |
# Try to find the paper by title (case-insensitive)
|
| 113 |
-
for
|
|
|
|
| 114 |
if paper_title.lower() in title.lower() or title.lower() in paper_title.lower():
|
| 115 |
return f"\n\n=== FULL PAPER: {title} ===\n\n{content}"
|
| 116 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
return ""
|
| 118 |
|
| 119 |
def extract_conclusion_from_paper(content: str) -> str:
|
|
@@ -253,17 +402,23 @@ def respond(
|
|
| 253 |
# Check if user is asking for a specific paper (e.g., "show me the full paper about pigs")
|
| 254 |
specific_paper_content = ""
|
| 255 |
conclusion_content = ""
|
|
|
|
| 256 |
|
| 257 |
-
if any(keyword in message.lower() for keyword in ["full paper", "complete paper", "entire paper", "show me the paper", "read the paper"]):
|
| 258 |
# Try to find specific paper content
|
| 259 |
-
for
|
|
|
|
| 260 |
if any(term in title.lower() for term in message.lower().split()):
|
| 261 |
-
|
|
|
|
|
|
|
|
|
|
| 262 |
break
|
| 263 |
|
| 264 |
# Check if user is asking for conclusions specifically
|
| 265 |
if any(keyword in message.lower() for keyword in ["conclusion", "conclusions", "what's the conclusion", "what is the conclusion"]):
|
| 266 |
-
for
|
|
|
|
| 267 |
if any(term in title.lower() for term in message.lower().split()):
|
| 268 |
conclusion_text = extract_conclusion_from_paper(content)
|
| 269 |
conclusion_content = f"\n\n=== CONCLUSION FROM {title} ===\n\n{conclusion_text}"
|
|
@@ -281,6 +436,8 @@ Here is the current research paper database:
|
|
| 281 |
|
| 282 |
{specific_paper_content}
|
| 283 |
|
|
|
|
|
|
|
| 284 |
{conclusion_content}
|
| 285 |
|
| 286 |
IMPORTANT INSTRUCTIONS:
|
|
@@ -290,7 +447,11 @@ IMPORTANT INSTRUCTIONS:
|
|
| 290 |
4. When asked for quotes, provide the exact text from the paper content provided.
|
| 291 |
5. You can now access the complete text of papers and provide detailed information including conclusions, methodology, and specific quotes.
|
| 292 |
6. If a user asks for the "full paper" or "complete paper", provide a comprehensive summary including all major sections (abstract, introduction, methodology, results, conclusions).
|
| 293 |
-
7. When conclusion content is specifically provided, use that content to answer conclusion-related questions.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
|
| 295 |
messages = [{"role": "system", "content": system_prompt}]
|
| 296 |
|
|
@@ -453,6 +614,7 @@ with gr.Blocks(
|
|
| 453 |
example_btn3 = gr.Button("Summarize research on large language models", size="sm")
|
| 454 |
example_btn4 = gr.Button("Show me the full paper about pigs", size="sm")
|
| 455 |
example_btn5 = gr.Button("What's the conclusion of the pig disease paper?", size="sm")
|
|
|
|
| 456 |
|
| 457 |
# Simple event handling with proper chat function
|
| 458 |
msg.submit(
|
|
@@ -483,6 +645,7 @@ with gr.Blocks(
|
|
| 483 |
example_btn3.click(lambda: "Summarize research on large language models", outputs=msg)
|
| 484 |
example_btn4.click(lambda: "Show me the full paper about pigs", outputs=msg)
|
| 485 |
example_btn5.click(lambda: "What's the conclusion of the pig disease paper?", outputs=msg)
|
|
|
|
| 486 |
|
| 487 |
if __name__ == "__main__":
|
| 488 |
# Check if API key is set
|
|
|
|
| 21 |
|
| 22 |
# Load full paper texts
|
| 23 |
def load_paper_texts():
|
| 24 |
+
"""Load all paper texts from the Papers directory and create a mapping from abstracts filenames."""
|
| 25 |
papers = {}
|
| 26 |
papers_dir = "Papers"
|
| 27 |
|
| 28 |
if not os.path.exists(papers_dir):
|
| 29 |
return papers
|
| 30 |
|
| 31 |
+
# Create a mapping from abstracts filenames to actual file content
|
| 32 |
for filename in os.listdir(papers_dir):
|
| 33 |
if filename.endswith('.txt'):
|
| 34 |
filepath = os.path.join(papers_dir, filename)
|
| 35 |
try:
|
| 36 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 37 |
content = f.read()
|
| 38 |
+
# Store with the filename as key
|
| 39 |
+
papers[filename] = content
|
|
|
|
| 40 |
except Exception as e:
|
| 41 |
print(f"Error loading {filename}: {e}")
|
| 42 |
|
| 43 |
return papers
|
| 44 |
|
| 45 |
+
def normalize_filename(filename):
|
| 46 |
+
"""Normalize filename for better matching."""
|
| 47 |
+
# Remove .txt extension and normalize
|
| 48 |
+
if filename.endswith('.txt'):
|
| 49 |
+
filename = filename[:-4]
|
| 50 |
+
|
| 51 |
+
# Convert to lowercase and remove special characters
|
| 52 |
+
normalized = filename.lower()
|
| 53 |
+
normalized = re.sub(r'[^\w\s]', '', normalized)
|
| 54 |
+
normalized = re.sub(r'\s+', ' ', normalized).strip()
|
| 55 |
+
|
| 56 |
+
return normalized
|
| 57 |
+
|
| 58 |
+
def find_matching_paper_file(query_terms, papers_dict):
|
| 59 |
+
"""Find the best matching paper file based on query terms."""
|
| 60 |
+
query_normalized = normalize_filename(' '.join(query_terms))
|
| 61 |
+
|
| 62 |
+
best_match = None
|
| 63 |
+
best_score = 0
|
| 64 |
+
|
| 65 |
+
for filename in papers_dict.keys():
|
| 66 |
+
filename_normalized = normalize_filename(filename)
|
| 67 |
+
|
| 68 |
+
# Calculate similarity score
|
| 69 |
+
score = 0
|
| 70 |
+
|
| 71 |
+
# Check for exact matches in normalized filenames
|
| 72 |
+
if query_normalized in filename_normalized or filename_normalized in query_normalized:
|
| 73 |
+
score += 100
|
| 74 |
+
|
| 75 |
+
# Check for word overlaps
|
| 76 |
+
query_words = set(query_normalized.split())
|
| 77 |
+
filename_words = set(filename_normalized.split())
|
| 78 |
+
overlap = len(query_words.intersection(filename_words))
|
| 79 |
+
score += overlap * 10
|
| 80 |
+
|
| 81 |
+
# Check for partial matches
|
| 82 |
+
for word in query_words:
|
| 83 |
+
if any(word in fn_word or fn_word in word for fn_word in filename_words):
|
| 84 |
+
score += 5
|
| 85 |
+
|
| 86 |
+
if score > best_score:
|
| 87 |
+
best_score = score
|
| 88 |
+
best_match = filename
|
| 89 |
+
|
| 90 |
+
return best_match if best_score > 5 else None
|
| 91 |
+
|
| 92 |
# Load abstracts content globally
|
| 93 |
ABSTRACTS_CONTENT = load_abstracts_content()
|
| 94 |
PAPER_TEXTS = load_paper_texts()
|
|
|
|
| 100 |
"""
|
| 101 |
results = []
|
| 102 |
query_lower = query.lower()
|
| 103 |
+
query_terms = query_lower.split()
|
| 104 |
+
|
| 105 |
+
# First, try to find a specific paper by filename matching
|
| 106 |
+
specific_paper = find_matching_paper_file(query_terms, papers)
|
| 107 |
+
|
| 108 |
+
if specific_paper:
|
| 109 |
+
# If we found a specific paper, prioritize it
|
| 110 |
+
content = papers[specific_paper]
|
| 111 |
+
title = specific_paper[:-4] if specific_paper.endswith('.txt') else specific_paper
|
| 112 |
+
|
| 113 |
+
# For full paper requests, include more content
|
| 114 |
+
if any(keyword in query.lower() for keyword in ["full paper", "complete paper", "entire paper", "show me the paper", "read the paper"]):
|
| 115 |
+
truncated_content = content[:12000] + "..." if len(content) > 12000 else content
|
| 116 |
+
else:
|
| 117 |
+
# Truncate content to first 3000 characters for context
|
| 118 |
+
truncated_content = content[:3000] + "..." if len(content) > 3000 else content
|
| 119 |
+
|
| 120 |
+
results.append((title, truncated_content, 100)) # High priority for exact matches
|
| 121 |
|
| 122 |
+
# Also search through all papers for general relevance
|
| 123 |
+
for filename, content in papers.items():
|
| 124 |
+
if filename == specific_paper: # Skip if already added
|
| 125 |
+
continue
|
| 126 |
+
|
| 127 |
+
title = filename[:-4] if filename.endswith('.txt') else filename
|
| 128 |
relevance_score = 0
|
| 129 |
|
| 130 |
# Check if query terms appear in title
|
| 131 |
+
title_lower = title.lower()
|
| 132 |
+
if any(term in title_lower for term in query_terms):
|
| 133 |
+
relevance_score += 15
|
| 134 |
|
| 135 |
# Check if query terms appear in content
|
| 136 |
content_lower = content.lower()
|
| 137 |
+
for term in query_terms:
|
| 138 |
if term in content_lower:
|
| 139 |
relevance_score += content_lower.count(term)
|
| 140 |
|
| 141 |
if relevance_score > 0:
|
| 142 |
+
# Truncate content appropriately
|
| 143 |
if any(keyword in query.lower() for keyword in ["full paper", "complete paper", "entire paper", "show me the paper", "read the paper"]):
|
|
|
|
| 144 |
truncated_content = content[:8000] + "..." if len(content) > 8000 else content
|
| 145 |
else:
|
|
|
|
| 146 |
truncated_content = content[:2000] + "..." if len(content) > 2000 else content
|
| 147 |
results.append((title, truncated_content, relevance_score))
|
| 148 |
|
| 149 |
# Sort by relevance score
|
| 150 |
results.sort(key=lambda x: x[2], reverse=True)
|
| 151 |
+
return results[:5] # Return top 5 most relevant papers
|
| 152 |
|
| 153 |
def get_relevant_papers_content(user_query: str) -> str:
|
| 154 |
"""
|
|
|
|
| 162 |
if not relevant_papers:
|
| 163 |
return ""
|
| 164 |
|
| 165 |
+
content = "\n\n=== RELEVANT PAPER CONTENT ===\n"
|
| 166 |
for title, paper_content, score in relevant_papers:
|
| 167 |
+
content += f"\n--- {title} (Relevance Score: {score}) ---\n"
|
| 168 |
content += paper_content
|
| 169 |
content += "\n" + "="*50 + "\n"
|
| 170 |
|
|
|
|
| 178 |
return ""
|
| 179 |
|
| 180 |
# Try to find the paper by title (case-insensitive)
|
| 181 |
+
for filename, content in PAPER_TEXTS.items():
|
| 182 |
+
title = filename[:-4] if filename.endswith('.txt') else filename
|
| 183 |
if paper_title.lower() in title.lower() or title.lower() in paper_title.lower():
|
| 184 |
return f"\n\n=== FULL PAPER: {title} ===\n\n{content}"
|
| 185 |
|
| 186 |
+
# If not found by title, try by filename matching
|
| 187 |
+
query_terms = paper_title.lower().split()
|
| 188 |
+
matching_file = find_matching_paper_file(query_terms, PAPER_TEXTS)
|
| 189 |
+
|
| 190 |
+
if matching_file:
|
| 191 |
+
title = matching_file[:-4] if matching_file.endswith('.txt') else matching_file
|
| 192 |
+
return f"\n\n=== FULL PAPER: {title} ===\n\n{PAPER_TEXTS[matching_file]}"
|
| 193 |
+
|
| 194 |
+
return ""
|
| 195 |
+
|
| 196 |
+
def get_paper_summary(paper_title: str) -> str:
|
| 197 |
+
"""
|
| 198 |
+
Get a comprehensive summary of a specific paper including key sections.
|
| 199 |
+
"""
|
| 200 |
+
if not PAPER_TEXTS:
|
| 201 |
+
return ""
|
| 202 |
+
|
| 203 |
+
# Find the paper
|
| 204 |
+
matching_file = None
|
| 205 |
+
for filename, content in PAPER_TEXTS.items():
|
| 206 |
+
title = filename[:-4] if filename.endswith('.txt') else filename
|
| 207 |
+
if paper_title.lower() in title.lower() or title.lower() in paper_title.lower():
|
| 208 |
+
matching_file = filename
|
| 209 |
+
break
|
| 210 |
+
|
| 211 |
+
if not matching_file:
|
| 212 |
+
# Try filename matching
|
| 213 |
+
query_terms = paper_title.lower().split()
|
| 214 |
+
matching_file = find_matching_paper_file(query_terms, PAPER_TEXTS)
|
| 215 |
+
|
| 216 |
+
if matching_file:
|
| 217 |
+
title = matching_file[:-4] if matching_file.endswith('.txt') else matching_file
|
| 218 |
+
content = PAPER_TEXTS[matching_file]
|
| 219 |
+
|
| 220 |
+
# Extract key sections
|
| 221 |
+
summary = f"\n\n=== PAPER SUMMARY: {title} ===\n\n"
|
| 222 |
+
|
| 223 |
+
# Try to find abstract
|
| 224 |
+
abstract_start = content.lower().find('abstract')
|
| 225 |
+
if abstract_start != -1:
|
| 226 |
+
# Find the end of abstract (usually before introduction)
|
| 227 |
+
intro_start = content.lower().find('introduction', abstract_start)
|
| 228 |
+
if intro_start != -1:
|
| 229 |
+
abstract_text = content[abstract_start:intro_start]
|
| 230 |
+
summary += f"ABSTRACT:\n{abstract_text}\n\n"
|
| 231 |
+
|
| 232 |
+
# Try to find introduction
|
| 233 |
+
intro_start = content.lower().find('introduction')
|
| 234 |
+
if intro_start != -1:
|
| 235 |
+
# Find the end of introduction (usually before methodology or methods)
|
| 236 |
+
method_start = content.lower().find('method', intro_start)
|
| 237 |
+
if method_start != -1:
|
| 238 |
+
intro_text = content[intro_start:method_start]
|
| 239 |
+
summary += f"INTRODUCTION:\n{intro_text}\n\n"
|
| 240 |
+
|
| 241 |
+
# Try to find methodology/methods
|
| 242 |
+
method_start = content.lower().find('method')
|
| 243 |
+
if method_start != -1:
|
| 244 |
+
# Find the end of methods (usually before results)
|
| 245 |
+
results_start = content.lower().find('results', method_start)
|
| 246 |
+
if results_start != -1:
|
| 247 |
+
method_text = content[method_start:results_start]
|
| 248 |
+
summary += f"METHODOLOGY:\n{method_text}\n\n"
|
| 249 |
+
|
| 250 |
+
# Try to find results
|
| 251 |
+
results_start = content.lower().find('results')
|
| 252 |
+
if results_start != -1:
|
| 253 |
+
# Find the end of results (usually before conclusion)
|
| 254 |
+
conclusion_start = content.lower().find('conclusion', results_start)
|
| 255 |
+
if conclusion_start != -1:
|
| 256 |
+
results_text = content[results_start:conclusion_start]
|
| 257 |
+
summary += f"RESULTS:\n{results_text}\n\n"
|
| 258 |
+
|
| 259 |
+
# Get conclusion
|
| 260 |
+
conclusion_text = extract_conclusion_from_paper(content)
|
| 261 |
+
if conclusion_text:
|
| 262 |
+
summary += f"CONCLUSION:\n{conclusion_text}\n\n"
|
| 263 |
+
|
| 264 |
+
return summary
|
| 265 |
+
|
| 266 |
return ""
|
| 267 |
|
| 268 |
def extract_conclusion_from_paper(content: str) -> str:
|
|
|
|
| 402 |
# Check if user is asking for a specific paper (e.g., "show me the full paper about pigs")
|
| 403 |
specific_paper_content = ""
|
| 404 |
conclusion_content = ""
|
| 405 |
+
paper_summary_content = ""
|
| 406 |
|
| 407 |
+
if any(keyword in message.lower() for keyword in ["full paper", "complete paper", "entire paper", "show me the paper", "read the paper", "summarize", "summary"]):
|
| 408 |
# Try to find specific paper content
|
| 409 |
+
for filename, content in PAPER_TEXTS.items():
|
| 410 |
+
title = filename[:-4] if filename.endswith('.txt') else filename
|
| 411 |
if any(term in title.lower() for term in message.lower().split()):
|
| 412 |
+
if any(keyword in message.lower() for keyword in ["summarize", "summary"]):
|
| 413 |
+
paper_summary_content = get_paper_summary(title)
|
| 414 |
+
else:
|
| 415 |
+
specific_paper_content = get_full_paper_content(title)
|
| 416 |
break
|
| 417 |
|
| 418 |
# Check if user is asking for conclusions specifically
|
| 419 |
if any(keyword in message.lower() for keyword in ["conclusion", "conclusions", "what's the conclusion", "what is the conclusion"]):
|
| 420 |
+
for filename, content in PAPER_TEXTS.items():
|
| 421 |
+
title = filename[:-4] if filename.endswith('.txt') else filename
|
| 422 |
if any(term in title.lower() for term in message.lower().split()):
|
| 423 |
conclusion_text = extract_conclusion_from_paper(content)
|
| 424 |
conclusion_content = f"\n\n=== CONCLUSION FROM {title} ===\n\n{conclusion_text}"
|
|
|
|
| 436 |
|
| 437 |
{specific_paper_content}
|
| 438 |
|
| 439 |
+
{paper_summary_content}
|
| 440 |
+
|
| 441 |
{conclusion_content}
|
| 442 |
|
| 443 |
IMPORTANT INSTRUCTIONS:
|
|
|
|
| 447 |
4. When asked for quotes, provide the exact text from the paper content provided.
|
| 448 |
5. You can now access the complete text of papers and provide detailed information including conclusions, methodology, and specific quotes.
|
| 449 |
6. If a user asks for the "full paper" or "complete paper", provide a comprehensive summary including all major sections (abstract, introduction, methodology, results, conclusions).
|
| 450 |
+
7. When conclusion content is specifically provided, use that content to answer conclusion-related questions.
|
| 451 |
+
8. The system now connects filenames from the abstracts database to the corresponding full text files in the Papers folder, allowing you to provide information from the complete papers rather than just abstracts.
|
| 452 |
+
9. When users search for papers, prioritize providing information from the full paper content when available, as this gives more comprehensive and accurate information than just the abstracts.
|
| 453 |
+
10. When users ask for summaries, provide structured summaries including abstract, introduction, methodology, results, and conclusions when available.
|
| 454 |
+
11. The system can now provide both full paper content and structured summaries based on user requests."""
|
| 455 |
|
| 456 |
messages = [{"role": "system", "content": system_prompt}]
|
| 457 |
|
|
|
|
| 614 |
example_btn3 = gr.Button("Summarize research on large language models", size="sm")
|
| 615 |
example_btn4 = gr.Button("Show me the full paper about pigs", size="sm")
|
| 616 |
example_btn5 = gr.Button("What's the conclusion of the pig disease paper?", size="sm")
|
| 617 |
+
example_btn6 = gr.Button("Summarize the paper about AI companions", size="sm")
|
| 618 |
|
| 619 |
# Simple event handling with proper chat function
|
| 620 |
msg.submit(
|
|
|
|
| 645 |
example_btn3.click(lambda: "Summarize research on large language models", outputs=msg)
|
| 646 |
example_btn4.click(lambda: "Show me the full paper about pigs", outputs=msg)
|
| 647 |
example_btn5.click(lambda: "What's the conclusion of the pig disease paper?", outputs=msg)
|
| 648 |
+
example_btn6.click(lambda: "Summarize the paper about AI companions", outputs=msg)
|
| 649 |
|
| 650 |
if __name__ == "__main__":
|
| 651 |
# Check if API key is set
|
test_functionality.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script to verify the paper loading and matching functionality.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
# Add the current directory to the path so we can import from app.py
|
| 10 |
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
| 11 |
+
|
| 12 |
+
# Import the functions from app.py
|
| 13 |
+
from app import load_paper_texts, find_matching_paper_file, normalize_filename
|
| 14 |
+
|
| 15 |
+
def test_paper_loading():
|
| 16 |
+
"""Test that papers are loaded correctly."""
|
| 17 |
+
print("Testing paper loading...")
|
| 18 |
+
|
| 19 |
+
papers = load_paper_texts()
|
| 20 |
+
print(f"Loaded {len(papers)} papers")
|
| 21 |
+
|
| 22 |
+
if papers:
|
| 23 |
+
print("Sample paper filenames:")
|
| 24 |
+
for i, filename in enumerate(list(papers.keys())[:5]):
|
| 25 |
+
print(f" {i+1}. {filename}")
|
| 26 |
+
|
| 27 |
+
return papers
|
| 28 |
+
|
| 29 |
+
def test_filename_matching():
|
| 30 |
+
"""Test the filename matching functionality."""
|
| 31 |
+
print("\nTesting filename matching...")
|
| 32 |
+
|
| 33 |
+
papers = load_paper_texts()
|
| 34 |
+
if not papers:
|
| 35 |
+
print("No papers loaded, skipping test")
|
| 36 |
+
return
|
| 37 |
+
|
| 38 |
+
# Test cases
|
| 39 |
+
test_queries = [
|
| 40 |
+
"pigs",
|
| 41 |
+
"AI companions",
|
| 42 |
+
"labor market",
|
| 43 |
+
"generative AI",
|
| 44 |
+
"chatgpt",
|
| 45 |
+
"large language models"
|
| 46 |
+
]
|
| 47 |
+
|
| 48 |
+
for query in test_queries:
|
| 49 |
+
print(f"\nQuery: '{query}'")
|
| 50 |
+
matching_file = find_matching_paper_file(query.split(), papers)
|
| 51 |
+
if matching_file:
|
| 52 |
+
print(f" Matched: {matching_file}")
|
| 53 |
+
else:
|
| 54 |
+
print(" No match found")
|
| 55 |
+
|
| 56 |
+
def test_normalize_filename():
|
| 57 |
+
"""Test the filename normalization function."""
|
| 58 |
+
print("\nTesting filename normalization...")
|
| 59 |
+
|
| 60 |
+
test_filenames = [
|
| 61 |
+
"The Labor Market Effects of Generativ.txt",
|
| 62 |
+
"AI Companions Reduce Loneliness.txt",
|
| 63 |
+
"WHEN PIGS GET SICK MULTI-AGENT AI.txt",
|
| 64 |
+
"Your Brain on ChatGPT Accumulation o.txt"
|
| 65 |
+
]
|
| 66 |
+
|
| 67 |
+
for filename in test_filenames:
|
| 68 |
+
normalized = normalize_filename(filename)
|
| 69 |
+
print(f" '{filename}' -> '{normalized}'")
|
| 70 |
+
|
| 71 |
+
if __name__ == "__main__":
|
| 72 |
+
print("Testing Paperbot functionality...")
|
| 73 |
+
print("=" * 50)
|
| 74 |
+
|
| 75 |
+
# Test paper loading
|
| 76 |
+
papers = test_paper_loading()
|
| 77 |
+
|
| 78 |
+
# Test filename normalization
|
| 79 |
+
test_normalize_filename()
|
| 80 |
+
|
| 81 |
+
# Test filename matching
|
| 82 |
+
test_filename_matching()
|
| 83 |
+
|
| 84 |
+
print("\n" + "=" * 50)
|
| 85 |
+
print("Testing completed!")
|