Sazzz02 commited on
Commit
ffaa39f
Β·
verified Β·
1 Parent(s): ba9ab01

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +492 -0
app.py ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research Paper Summarizer using LangChain and Gradio
2
+ # Updated for Hugging Face Spaces with beautiful Gradio UI
3
+ # Install required packages first:
4
+ # pip install gradio langchain openai pypdf2 reportlab python-dotenv transformers torch
5
+
6
+ import gradio as gr
7
+ import os
8
+ from dotenv import load_dotenv
9
+ import PyPDF2
10
+ from io import BytesIO
11
+ from reportlab.lib.pagesizes import letter
12
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
13
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
14
+ from reportlab.lib.units import inch
15
+ import tempfile
16
+
17
+ # LangChain imports
18
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
19
+ from langchain.chains.summarize import load_summarize_chain
20
+ from langchain.docstore.document import Document
21
+ from langchain.llms import OpenAI
22
+ from langchain.chat_models import ChatOpenAI
23
+
24
+ # Alternative: Use Hugging Face models
25
+ from langchain.llms import HuggingFacePipeline
26
+ from transformers import pipeline
27
+
28
+ load_dotenv()
29
+
30
+ class ResearchPaperSummarizer:
31
+ def __init__(self):
32
+ self.llm = None
33
+ self.model_info = ""
34
+
35
+ def setup_llm(self, model_choice):
36
+ """Setup LLM based on user choice"""
37
+ # Check available API keys from environment
38
+ openai_api_key = os.getenv("OPENAI_API_KEY")
39
+ hf_token = os.getenv("HUGGINGFACE_TOKEN")
40
+
41
+ try:
42
+ if "OpenAI" in model_choice:
43
+ if not openai_api_key:
44
+ return False, "❌ OpenAI API Key not found in environment variables. Please add OPENAI_API_KEY to your Hugging Face Space settings."
45
+
46
+ os.environ["OPENAI_API_KEY"] = openai_api_key
47
+ if "GPT-4" in model_choice:
48
+ self.llm = ChatOpenAI(model_name="gpt-4", temperature=0.3)
49
+ self.model_info = "πŸš€ Using GPT-4 (Premium) - Highest quality summaries"
50
+ else:
51
+ self.llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.3)
52
+ self.model_info = "πŸš€ Using GPT-3.5 Turbo - Fast and efficient"
53
+
54
+ else:
55
+ # Use Hugging Face models (free but slower)
56
+ if "BART" in model_choice:
57
+ summarizer = pipeline(
58
+ "summarization",
59
+ model="facebook/bart-large-cnn",
60
+ tokenizer="facebook/bart-large-cnn",
61
+ use_auth_token=hf_token if hf_token else None
62
+ )
63
+ self.model_info = "πŸ€— Using BART model - Free, optimized for summarization"
64
+ else:
65
+ summarizer = pipeline(
66
+ "summarization",
67
+ model="t5-base",
68
+ tokenizer="t5-base",
69
+ use_auth_token=hf_token if hf_token else None
70
+ )
71
+ self.model_info = "πŸ€— Using T5 model - Free, versatile model"
72
+
73
+ self.llm = HuggingFacePipeline(pipeline=summarizer)
74
+
75
+ return True, f"βœ… Model loaded successfully! {self.model_info}"
76
+
77
+ except Exception as e:
78
+ return False, f"❌ Error loading model: {str(e)}"
79
+
80
+ def extract_text_from_pdf(self, pdf_file):
81
+ """Extract text from uploaded PDF"""
82
+ try:
83
+ if pdf_file is None:
84
+ return None, "❌ No PDF file uploaded"
85
+
86
+ pdf_reader = PyPDF2.PdfReader(pdf_file)
87
+ text = ""
88
+ for page in pdf_reader.pages:
89
+ text += page.extract_text()
90
+
91
+ if not text.strip():
92
+ return None, "❌ No text could be extracted from the PDF"
93
+
94
+ return text, f"βœ… Successfully extracted {len(text):,} characters from PDF"
95
+ except Exception as e:
96
+ return None, f"❌ Error reading PDF: {str(e)}"
97
+
98
+ def create_documents(self, text):
99
+ """Split text into manageable chunks"""
100
+ text_splitter = RecursiveCharacterTextSplitter(
101
+ chunk_size=4000,
102
+ chunk_overlap=200,
103
+ length_function=len
104
+ )
105
+
106
+ chunks = text_splitter.split_text(text)
107
+ documents = [Document(page_content=chunk) for chunk in chunks]
108
+ return documents
109
+
110
+ def generate_summary(self, documents, summary_type="map_reduce"):
111
+ """Generate summary using LangChain"""
112
+ try:
113
+ if summary_type == "map_reduce":
114
+ chain = load_summarize_chain(
115
+ self.llm,
116
+ chain_type="map_reduce",
117
+ verbose=False
118
+ )
119
+ elif summary_type == "stuff":
120
+ chain = load_summarize_chain(
121
+ self.llm,
122
+ chain_type="stuff",
123
+ verbose=False
124
+ )
125
+ else: # refine
126
+ chain = load_summarize_chain(
127
+ self.llm,
128
+ chain_type="refine",
129
+ verbose=False
130
+ )
131
+
132
+ summary = chain.run(documents)
133
+ return summary
134
+
135
+ except Exception as e:
136
+ return f"❌ Error generating summary: {str(e)}"
137
+
138
+ def create_structured_summary(self, text, documents):
139
+ """Create a structured summary with different sections"""
140
+ summaries = {}
141
+
142
+ # Overall Summary
143
+ summaries['overall'] = self.generate_summary(documents, "map_reduce")
144
+
145
+ # Key Points - Create a separate prompt for key points
146
+ if len(text) > 8000:
147
+ key_points_text = text[:8000]
148
+ else:
149
+ key_points_text = text
150
+
151
+ key_points_prompt = f"""
152
+ Extract the 5-7 most important key points from this research paper:
153
+
154
+ {key_points_text}
155
+ """
156
+
157
+ key_points_docs = [Document(page_content=key_points_prompt)]
158
+ summaries['key_points'] = self.generate_summary(key_points_docs, "stuff")
159
+
160
+ return summaries
161
+
162
+ def create_pdf_summary(self, summaries, paper_title="Research Paper Summary"):
163
+ """Create PDF with the summary"""
164
+ buffer = BytesIO()
165
+ doc = SimpleDocTemplate(buffer, pagesize=letter)
166
+ styles = getSampleStyleSheet()
167
+ story = []
168
+
169
+ # Title
170
+ title_style = ParagraphStyle(
171
+ 'CustomTitle',
172
+ parent=styles['Heading1'],
173
+ fontSize=16,
174
+ spaceAfter=30,
175
+ textColor='darkblue'
176
+ )
177
+
178
+ story.append(Paragraph(paper_title, title_style))
179
+ story.append(Spacer(1, 12))
180
+
181
+ # Overall Summary
182
+ story.append(Paragraph("Overall Summary", styles['Heading2']))
183
+ story.append(Spacer(1, 12))
184
+ story.append(Paragraph(summaries.get('overall', 'No summary available'), styles['Normal']))
185
+ story.append(Spacer(1, 20))
186
+
187
+ # Key Points
188
+ if 'key_points' in summaries:
189
+ story.append(Paragraph("Key Points", styles['Heading2']))
190
+ story.append(Spacer(1, 12))
191
+ story.append(Paragraph(summaries['key_points'], styles['Normal']))
192
+
193
+ doc.build(story)
194
+ buffer.seek(0)
195
+
196
+ # Save to temporary file for Gradio
197
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
198
+ temp_file.write(buffer.getvalue())
199
+ temp_file.close()
200
+
201
+ return temp_file.name
202
+
203
+ # Initialize the summarizer
204
+ summarizer = ResearchPaperSummarizer()
205
+
206
+ def process_paper(pdf_file, model_choice, summary_type, include_key_points, paper_title):
207
+ """Main function to process the research paper"""
208
+
209
+ # Setup model
210
+ success, message = summarizer.setup_llm(model_choice)
211
+ if not success:
212
+ return message, "", "", None
213
+
214
+ status_message = message + "\n\n"
215
+
216
+ # Extract text from PDF
217
+ text, extract_message = summarizer.extract_text_from_pdf(pdf_file)
218
+ status_message += extract_message + "\n\n"
219
+
220
+ if text is None:
221
+ return status_message, "", "", None
222
+
223
+ # Create documents
224
+ documents = summarizer.create_documents(text)
225
+ status_message += f"πŸ“ Text split into {len(documents)} chunks for processing\n\n"
226
+
227
+ # Generate summary
228
+ status_message += "πŸ”„ Generating summary... Please wait...\n\n"
229
+
230
+ try:
231
+ if include_key_points:
232
+ summaries = summarizer.create_structured_summary(text, documents)
233
+ overall_summary = summaries.get('overall', 'No summary generated')
234
+ key_points = summaries.get('key_points', 'No key points generated')
235
+ else:
236
+ overall_summary = summarizer.generate_summary(documents, summary_type)
237
+ key_points = "Key points not requested"
238
+ summaries = {'overall': overall_summary}
239
+
240
+ status_message += "πŸŽ‰ Summary generated successfully!"
241
+
242
+ # Generate PDF if title is provided
243
+ pdf_file_path = None
244
+ if paper_title and paper_title.strip():
245
+ try:
246
+ pdf_file_path = summarizer.create_pdf_summary(summaries, paper_title.strip())
247
+ status_message += "\nπŸ“„ PDF summary created!"
248
+ except Exception as e:
249
+ status_message += f"\n⚠️ PDF creation failed: {str(e)}"
250
+
251
+ return status_message, overall_summary, key_points, pdf_file_path
252
+
253
+ except Exception as e:
254
+ return status_message + f"❌ Error during processing: {str(e)}", "", "", None
255
+
256
+ def get_model_info(model_choice):
257
+ """Return information about the selected model"""
258
+ model_descriptions = {
259
+ "OpenAI GPT-3.5": "πŸ’‘ **Fast and Efficient** - Good for most tasks, paid API required",
260
+ "OpenAI GPT-4": "πŸš€ **Highest Quality** - Most advanced summaries, paid API required",
261
+ "Hugging Face BART": "πŸ†“ **Free Model** - Optimized for summarization, slower on first load",
262
+ "Hugging Face T5": "πŸ†“ **Free Versatile** - Good general-purpose model, slower on first load"
263
+ }
264
+ return model_descriptions.get(model_choice, "")
265
+
266
+ # Custom CSS for beautiful styling
267
+ custom_css = """
268
+ .gradio-container {
269
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
270
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
271
+ }
272
+
273
+ .gr-interface {
274
+ background: rgba(255, 255, 255, 0.95);
275
+ backdrop-filter: blur(10px);
276
+ border-radius: 20px;
277
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
278
+ }
279
+
280
+ .gr-box {
281
+ border-radius: 15px;
282
+ border: 2px solid #e1e5e9;
283
+ background: linear-gradient(145deg, #ffffff, #f0f2f5);
284
+ }
285
+
286
+ .gr-button {
287
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
288
+ border: none;
289
+ border-radius: 10px;
290
+ color: white;
291
+ font-weight: bold;
292
+ transition: transform 0.2s;
293
+ }
294
+
295
+ .gr-button:hover {
296
+ transform: translateY(-2px);
297
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
298
+ }
299
+
300
+ .gr-textbox, .gr-dropdown {
301
+ border-radius: 10px;
302
+ border: 2px solid #e1e5e9;
303
+ }
304
+
305
+ .gr-file {
306
+ border-radius: 15px;
307
+ border: 3px dashed #667eea;
308
+ background: linear-gradient(145deg, #f8f9ff, #ffffff);
309
+ }
310
+ """
311
+
312
+ # Create the Gradio interface
313
+ with gr.Blocks(css=custom_css, title="πŸ”¬ Research Paper Summarizer", theme=gr.themes.Soft()) as app:
314
+
315
+ # Header
316
+ gr.Markdown(
317
+ """
318
+ # πŸ”¬ Research Paper Summarizer
319
+ ### Transform lengthy research papers into concise, insightful summaries using AI
320
+
321
+ Upload your PDF research paper and get an intelligent summary with key points extracted automatically!
322
+ """,
323
+ elem_classes="header"
324
+ )
325
+
326
+ with gr.Row():
327
+ with gr.Column(scale=1):
328
+ # Input Section
329
+ gr.Markdown("## πŸ“ Upload & Configure")
330
+
331
+ pdf_input = gr.File(
332
+ label="πŸ“„ Upload Research Paper (PDF)",
333
+ file_types=[".pdf"],
334
+ elem_classes="file-upload"
335
+ )
336
+
337
+ model_choice = gr.Dropdown(
338
+ choices=[
339
+ "OpenAI GPT-3.5",
340
+ "OpenAI GPT-4",
341
+ "Hugging Face BART",
342
+ "Hugging Face T5"
343
+ ],
344
+ value="Hugging Face BART",
345
+ label="πŸ€– Choose AI Model",
346
+ info="Free models work without API keys"
347
+ )
348
+
349
+ model_info = gr.Markdown("")
350
+
351
+ summary_type = gr.Dropdown(
352
+ choices=["map_reduce", "stuff", "refine"],
353
+ value="map_reduce",
354
+ label="πŸ“‹ Summary Method",
355
+ info="map_reduce: best for long papers | stuff: faster for short papers | refine: iterative improvement"
356
+ )
357
+
358
+ include_key_points = gr.Checkbox(
359
+ label="πŸ”‘ Include Key Points",
360
+ value=True,
361
+ info="Extract important key points separately"
362
+ )
363
+
364
+ paper_title = gr.Textbox(
365
+ label="πŸ“ Paper Title (for PDF export)",
366
+ placeholder="Enter the title of your research paper...",
367
+ info="Optional: Used as title in the generated PDF summary"
368
+ )
369
+
370
+ process_btn = gr.Button(
371
+ "πŸš€ Generate Summary",
372
+ variant="primary",
373
+ size="lg",
374
+ elem_classes="process-button"
375
+ )
376
+
377
+ with gr.Column(scale=2):
378
+ # Output Section
379
+ gr.Markdown("## πŸ“Š Results")
380
+
381
+ status_output = gr.Textbox(
382
+ label="πŸ“ˆ Processing Status",
383
+ lines=8,
384
+ max_lines=10,
385
+ interactive=False,
386
+ show_copy_button=True
387
+ )
388
+
389
+ summary_output = gr.Textbox(
390
+ label="πŸ“‹ Overall Summary",
391
+ lines=10,
392
+ max_lines=15,
393
+ interactive=False,
394
+ show_copy_button=True,
395
+ placeholder="Your paper summary will appear here..."
396
+ )
397
+
398
+ key_points_output = gr.Textbox(
399
+ label="πŸ”‘ Key Points",
400
+ lines=8,
401
+ max_lines=12,
402
+ interactive=False,
403
+ show_copy_button=True,
404
+ placeholder="Key points will be extracted here..."
405
+ )
406
+
407
+ pdf_output = gr.File(
408
+ label="πŸ“„ Download PDF Summary",
409
+ interactive=False
410
+ )
411
+
412
+ # Setup Instructions
413
+ with gr.Accordion("πŸ”§ Setup Instructions for API Keys", open=False):
414
+ gr.Markdown(
415
+ """
416
+ ### For Enhanced Performance (Optional):
417
+
418
+ **OpenAI API Setup:**
419
+ 1. Get your API key from [OpenAI Platform](https://platform.openai.com/api-keys)
420
+ 2. In your Hugging Face Space settings, add: `OPENAI_API_KEY = your_key_here`
421
+ 3. Restart your Space to apply changes
422
+
423
+ **Hugging Face Token Setup:**
424
+ 1. Get your token from [HuggingFace Settings](https://huggingface.co/settings/tokens)
425
+ 2. Add: `HUGGINGFACE_TOKEN = your_token_here`
426
+ 3. Provides access to gated models and higher rate limits
427
+
428
+ **Note:** Free Hugging Face models work without any API keys but may be slower on first load.
429
+ """
430
+ )
431
+
432
+ # Performance Tips
433
+ with gr.Accordion("πŸ’‘ Tips for Best Results", open=False):
434
+ gr.Markdown(
435
+ """
436
+ ### Optimization Tips:
437
+
438
+ - **πŸ“„ File Size:** Smaller PDFs (< 10MB) process faster
439
+ - **πŸ€– Model Choice:** OpenAI models provide highest quality but require API keys
440
+ - **⚑ Speed:** "stuff" method is fastest for papers under 20 pages
441
+ - **πŸ“Š Quality:** "map_reduce" works best for comprehensive summaries of long papers
442
+ - **πŸ”„ First Load:** Hugging Face models may take 2-3 minutes to load initially
443
+ - **πŸ“± Mobile:** Works on mobile devices but desktop recommended for large files
444
+ """
445
+ )
446
+
447
+ # Event handlers
448
+ model_choice.change(
449
+ fn=get_model_info,
450
+ inputs=[model_choice],
451
+ outputs=[model_info]
452
+ )
453
+
454
+ process_btn.click(
455
+ fn=process_paper,
456
+ inputs=[
457
+ pdf_input,
458
+ model_choice,
459
+ summary_type,
460
+ include_key_points,
461
+ paper_title
462
+ ],
463
+ outputs=[
464
+ status_output,
465
+ summary_output,
466
+ key_points_output,
467
+ pdf_output
468
+ ],
469
+ show_progress=True
470
+ )
471
+
472
+ # Footer
473
+ gr.Markdown(
474
+ """
475
+ ---
476
+ <div style="text-align: center; color: #666; font-size: 14px;">
477
+ πŸ”¬ <strong>Research Paper Summarizer</strong> | Powered by LangChain & AI Models |
478
+ Built with ❀️ using Gradio
479
+ </div>
480
+ """,
481
+ elem_classes="footer"
482
+ )
483
+
484
+ # Launch the app
485
+ if __name__ == "__main__":
486
+ app.launch(
487
+ share=True,
488
+ show_error=True,
489
+ debug=True,
490
+ server_name="0.0.0.0",
491
+ server_port=7860
492
+ )