cstr commited on
Commit
897fb70
Β·
verified Β·
1 Parent(s): d7defaa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +237 -103
app.py CHANGED
@@ -6,17 +6,14 @@ import gradio as gr
6
  from PyPDF2 import PdfReader
7
  import logging
8
  import webbrowser
9
- from gradio_client import Client
 
 
10
 
11
  # Set up logging
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
 
14
- # Initialize Hugging Face models
15
- HUGGINGFACE_MODELS = {
16
- "Phi-3 Mini 128k": "eswardivi/Phi-3-mini-128k-instruct",
17
- }
18
-
19
- # Common context window sizes
20
  CONTEXT_SIZES = {
21
  "4K": 4000,
22
  "8K": 8000,
@@ -25,15 +22,49 @@ CONTEXT_SIZES = {
25
  "200K": 200000
26
  }
27
 
28
- def copy_to_clipboard(text):
29
- return text
 
 
 
 
 
30
 
31
- def open_chatgpt():
32
- webbrowser.open('https://chat.openai.com/')
33
- return "Opening ChatGPT in browser..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- # Utility Functions
36
- def extract_text_from_pdf(pdf_path):
37
  """Extract text content from PDF file."""
38
  try:
39
  reader = PdfReader(pdf_path)
@@ -51,7 +82,7 @@ def extract_text_from_pdf(pdf_path):
51
  logging.error(f"Error reading PDF file: {e}")
52
  return f"Error reading PDF file: {e}"
53
 
54
- def format_content(text, format_type):
55
  """Format extracted text according to specified format."""
56
  if format_type == 'txt':
57
  return text
@@ -65,7 +96,7 @@ def format_content(text, format_type):
65
  logging.error(f"Unsupported format: {format_type}")
66
  return f"Unsupported format: {format_type}"
67
 
68
- def split_into_snippets(text, context_size):
69
  """Split text into manageable snippets based on context size."""
70
  sentences = re.split(r'(?<=[.!?]) +', text)
71
  snippets = []
@@ -87,7 +118,7 @@ def split_into_snippets(text, context_size):
87
 
88
  return snippets
89
 
90
- def build_prompts(snippets, prompt_instruction, custom_prompt, snippet_num=None):
91
  """Build formatted prompts from text snippets."""
92
  if snippet_num is not None:
93
  if 1 <= snippet_num <= len(snippets):
@@ -111,27 +142,120 @@ def build_prompts(snippets, prompt_instruction, custom_prompt, snippet_num=None)
111
 
112
  return "\n\n".join(prompts)
113
 
114
- def send_to_huggingface(prompt, model_name):
115
- """Send prompt to Hugging Face model using gradio_client."""
116
  try:
117
- client = Client(model_name)
118
- response = client.predict(
119
- prompt, # message
120
- 0.9, # temperature
121
- True, # sampling
122
- 512, # max_new_tokens
123
- api_name="/chat"
124
  )
125
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  except Exception as e:
127
- logging.error(f"Error interacting with Hugging Face model: {e}")
128
- return f"Error interacting with Hugging Face model: {e}"
129
 
130
  # Main Interface
131
  with gr.Blocks(theme=gr.themes.Default()) as demo:
 
 
 
132
  # Header
133
  gr.Markdown("# πŸ“„ Smart PDF Summarizer")
134
- gr.Markdown("Upload a PDF document and get AI-powered summaries using OpenAI or Hugging Face models.")
135
 
136
  # Main Content
137
  with gr.Row():
@@ -151,9 +275,10 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
151
 
152
  gr.Markdown("### Context Window Size")
153
  with gr.Row():
 
154
  for size_name, size_value in CONTEXT_SIZES.items():
155
- if gr.Button(size_name).click:
156
- context_size.value = size_value
157
 
158
  context_size = gr.Slider(
159
  minimum=1000,
@@ -176,30 +301,43 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
176
  )
177
 
178
  model_choice = gr.Radio(
179
- choices=["OpenAI ChatGPT", "Hugging Face Model"],
180
  value="OpenAI ChatGPT",
181
  label="πŸ€– Model Selection"
182
  )
183
 
184
- hf_model = gr.Dropdown(
185
- choices=list(HUGGINGFACE_MODELS.keys()),
186
- label="πŸ”§ Hugging Face Model",
187
- visible=False
188
- )
 
 
 
 
 
 
 
 
 
 
189
 
190
- # Authentication moved down
191
- with gr.Row(visible=False) as auth_row:
192
- openai_api_key = gr.Textbox(
193
- label="πŸ”‘ OpenAI API Key",
194
- type="password",
195
- placeholder="Enter your OpenAI API key (optional)"
 
 
 
 
196
  )
197
 
198
  # Right Column - Output
199
  with gr.Column(scale=1):
200
- with gr.Row():
201
- process_button = gr.Button("πŸš€ Process PDF", variant="primary")
202
-
203
  progress_status = gr.Textbox(
204
  label="πŸ“Š Progress",
205
  interactive=False
@@ -226,63 +364,51 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
226
  )
227
 
228
  # Event Handlers
229
- def toggle_hf_model(choice):
230
- return gr.update(visible=choice == "Hugging Face Model"), gr.update(visible=choice == "OpenAI ChatGPT")
231
 
232
- def process_pdf(pdf, fmt, ctx_size, snippet_num, prompt, model_selection, hf_model_choice):
233
- try:
234
- if not pdf:
235
- return "Please upload a PDF file.", "", "", None
236
-
237
- # Extract text
238
- text = extract_text_from_pdf(pdf.name)
239
- if text.startswith("Error"):
240
- return text, "", "", None
241
-
242
- # Format content
243
- formatted_text = format_content(text, fmt)
244
-
245
- # Split into snippets
246
- snippets = split_into_snippets(formatted_text, ctx_size)
247
-
248
- # Build prompts
249
- default_prompt = "Summarize the following text:"
250
- full_prompt = build_prompts(snippets, default_prompt, prompt, snippet_num)
251
-
252
- if isinstance(full_prompt, str) and full_prompt.startswith("Error"):
253
- return full_prompt, "", "", None
254
-
255
- # Generate summary based on model choice
256
- if model_selection == "Hugging Face Model":
257
- summary = send_to_huggingface(full_prompt, HUGGINGFACE_MODELS[hf_model_choice])
258
- else:
259
- summary = "Please use the Copy Prompt button and paste into ChatGPT."
260
-
261
- # Save files for download
262
- files_to_download = []
263
-
264
- with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt') as prompt_file:
265
- prompt_file.write(full_prompt)
266
- files_to_download.append(prompt_file.name)
267
-
268
- if summary != "Please use the Copy Prompt button and paste into ChatGPT.":
269
- with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt') as summary_file:
270
- summary_file.write(summary)
271
- files_to_download.append(summary_file.name)
272
-
273
- return "Processing complete!", full_prompt, summary, files_to_download
274
-
275
- except Exception as e:
276
- logging.error(f"Error processing PDF: {e}")
277
- return f"Error processing PDF: {str(e)}", "", "", None
278
 
279
  # Connect event handlers
280
  model_choice.change(
281
- toggle_hf_model,
282
  inputs=[model_choice],
283
- outputs=[hf_model, auth_row]
284
  )
285
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  process_button.click(
287
  process_pdf,
288
  inputs=[
@@ -292,7 +418,11 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
292
  snippet_number,
293
  custom_prompt,
294
  model_choice,
295
- hf_model
 
 
 
 
296
  ],
297
  outputs=[
298
  progress_status,
@@ -301,19 +431,19 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
301
  download_files
302
  ]
303
  )
304
-
305
  copy_prompt_button.click(
306
  copy_to_clipboard,
307
  inputs=[generated_prompt],
308
  outputs=[progress_status]
309
  )
310
-
311
  copy_summary_button.click(
312
  copy_to_clipboard,
313
  inputs=[summary_output],
314
  outputs=[progress_status]
315
  )
316
-
317
  open_chatgpt_button.click(
318
  open_chatgpt,
319
  outputs=[progress_status]
@@ -325,7 +455,10 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
325
  1. Upload a PDF document
326
  2. Choose output format and context window size
327
  3. Select snippet number (default: 1) or enter custom prompt
328
- 4. Select between OpenAI ChatGPT or Hugging Face model
 
 
 
329
  5. Click 'Process PDF' to generate summary
330
  6. Use 'Copy Prompt' and 'Open ChatGPT' for manual processing
331
  7. Download generated files as needed
@@ -334,6 +467,7 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
334
  - Support for multiple PDF formats
335
  - Flexible text formatting options
336
  - Predefined context window sizes (4K to 200K)
 
337
  - Copy to clipboard functionality
338
  - Direct ChatGPT integration
339
  - Downloadable outputs
 
6
  from PyPDF2 import PdfReader
7
  import logging
8
  import webbrowser
9
+ from huggingface_hub import InferenceClient
10
+ from typing import Dict, List, Optional, Tuple
11
+ import time
12
 
13
  # Set up logging
14
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
15
 
16
+ # Constants
 
 
 
 
 
17
  CONTEXT_SIZES = {
18
  "4K": 4000,
19
  "8K": 8000,
 
22
  "200K": 200000
23
  }
24
 
25
+ class ModelRegistry:
26
+ def __init__(self):
27
+ self.hf_models = {
28
+ "Phi-3 Mini 128k": "microsoft/Phi-3-mini-128k-instruct",
29
+ "Custom Model": ""
30
+ }
31
+ self.groq_models = self._fetch_groq_models()
32
 
33
+ def _fetch_groq_models(self) -> Dict[str, str]:
34
+ """Fetch available Groq models"""
35
+ try:
36
+ headers = {
37
+ "Authorization": f"Bearer {os.getenv('GROQ_API_KEY')}",
38
+ "Content-Type": "application/json"
39
+ }
40
+ response = requests.get("https://api.groq.com/openai/v1/models", headers=headers)
41
+ if response.status_code == 200:
42
+ models = response.json().get("data", [])
43
+ return {model["id"]: model["id"] for model in models}
44
+ else:
45
+ logging.error(f"Failed to fetch Groq models: {response.status_code}")
46
+ return self._get_default_groq_models()
47
+ except Exception as e:
48
+ logging.error(f"Error fetching Groq models: {e}")
49
+ return self._get_default_groq_models()
50
+
51
+ def _get_default_groq_models(self) -> Dict[str, str]:
52
+ """Return default Groq models when API is unavailable"""
53
+ return {
54
+ "llama-3.1-70b-versatile": "llama-3.1-70b-versatile",
55
+ "mixtral-8x7b-32768": "mixtral-8x7b-32768",
56
+ "llama-3.1-8b-instant": "llama-3.1-8b-instant"
57
+ }
58
+
59
+ def refresh_groq_models(self) -> Dict[str, str]:
60
+ """Refresh the list of available Groq models"""
61
+ self.groq_models = self._fetch_groq_models()
62
+ return self.groq_models
63
+
64
+ # Initialize model registry
65
+ model_registry = ModelRegistry()
66
 
67
+ def extract_text_from_pdf(pdf_path: str) -> str:
 
68
  """Extract text content from PDF file."""
69
  try:
70
  reader = PdfReader(pdf_path)
 
82
  logging.error(f"Error reading PDF file: {e}")
83
  return f"Error reading PDF file: {e}"
84
 
85
+ def format_content(text: str, format_type: str) -> str:
86
  """Format extracted text according to specified format."""
87
  if format_type == 'txt':
88
  return text
 
96
  logging.error(f"Unsupported format: {format_type}")
97
  return f"Unsupported format: {format_type}"
98
 
99
+ def split_into_snippets(text: str, context_size: int) -> List[str]:
100
  """Split text into manageable snippets based on context size."""
101
  sentences = re.split(r'(?<=[.!?]) +', text)
102
  snippets = []
 
118
 
119
  return snippets
120
 
121
+ def build_prompts(snippets: List[str], prompt_instruction: str, custom_prompt: Optional[str], snippet_num: Optional[int] = None) -> str:
122
  """Build formatted prompts from text snippets."""
123
  if snippet_num is not None:
124
  if 1 <= snippet_num <= len(snippets):
 
142
 
143
  return "\n\n".join(prompts)
144
 
145
+ def send_to_hf_inference(prompt: str, model_name: str, api_key: str) -> str:
146
+ """Send prompt to HuggingFace using Inference API"""
147
  try:
148
+ client = InferenceClient(api_key=api_key)
149
+ messages = [{"role": "user", "content": prompt}]
150
+ completion = client.chat.completions.create(
151
+ model=model_name,
152
+ messages=messages,
153
+ max_tokens=500
 
154
  )
155
+ return completion.choices[0].message.content
156
+ except Exception as e:
157
+ logging.error(f"Error with HF inference: {e}")
158
+ return f"Error with HF inference: {e}"
159
+
160
+ def send_to_groq(prompt: str, model_name: str, api_key: str) -> str:
161
+ """Send prompt to Groq API"""
162
+ try:
163
+ headers = {
164
+ "Authorization": f"Bearer {api_key}",
165
+ "Content-Type": "application/json"
166
+ }
167
+ data = {
168
+ "model": model_name,
169
+ "messages": [{"role": "user", "content": prompt}]
170
+ }
171
+ response = requests.post(
172
+ "https://api.groq.com/openai/v1/chat/completions",
173
+ headers=headers,
174
+ json=data
175
+ )
176
+ return response.json()["choices"][0]["message"]["content"]
177
+ except Exception as e:
178
+ logging.error(f"Error with Groq API: {e}")
179
+ return f"Error with Groq API: {e}"
180
+
181
+ def copy_to_clipboard(text: str) -> str:
182
+ """Copy text to clipboard"""
183
+ return "Text copied to clipboard!"
184
+
185
+ def open_chatgpt() -> str:
186
+ """Open ChatGPT in browser"""
187
+ webbrowser.open('https://chat.openai.com/')
188
+ return "Opening ChatGPT in browser..."
189
+
190
+ def process_pdf(pdf, fmt, ctx_size, snippet_num, prompt, model_selection,
191
+ hf_model_choice, hf_custom_model, hf_api_key,
192
+ groq_model_choice, groq_api_key) -> Tuple[str, str, str, List[str]]:
193
+ """Process PDF and generate summary"""
194
+ try:
195
+ if not pdf:
196
+ return "Please upload a PDF file.", "", "", []
197
+
198
+ # Extract text
199
+ text = extract_text_from_pdf(pdf.name)
200
+ if text.startswith("Error"):
201
+ return text, "", "", []
202
+
203
+ # Format content
204
+ formatted_text = format_content(text, fmt)
205
+
206
+ # Split into snippets
207
+ snippets = split_into_snippets(formatted_text, ctx_size)
208
+
209
+ # Build prompts
210
+ default_prompt = "Summarize the following text:"
211
+ full_prompt = build_prompts(snippets, default_prompt, prompt, snippet_num)
212
+
213
+ if isinstance(full_prompt, str) and full_prompt.startswith("Error"):
214
+ return full_prompt, "", "", []
215
+
216
+ # Process with selected model
217
+ if model_selection == "HuggingFace Inference":
218
+ if not hf_api_key:
219
+ return "HuggingFace API key required.", full_prompt, "", []
220
+
221
+ model_id = hf_custom_model if hf_model_choice == "Custom Model" else model_registry.hf_models[hf_model_choice]
222
+ summary = send_to_hf_inference(full_prompt, model_id, hf_api_key)
223
+
224
+ elif model_selection == "Groq API":
225
+ if not groq_api_key:
226
+ return "Groq API key required.", full_prompt, "", []
227
+
228
+ summary = send_to_groq(full_prompt, groq_model_choice, groq_api_key)
229
+
230
+ else: # OpenAI ChatGPT
231
+ summary = "Please use the Copy Prompt button and paste into ChatGPT."
232
+
233
+ # Save files for download
234
+ files_to_download = []
235
+
236
+ with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt') as prompt_file:
237
+ prompt_file.write(full_prompt)
238
+ files_to_download.append(prompt_file.name)
239
+
240
+ if summary != "Please use the Copy Prompt button and paste into ChatGPT.":
241
+ with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt') as summary_file:
242
+ summary_file.write(summary)
243
+ files_to_download.append(summary_file.name)
244
+
245
+ return "Processing complete!", full_prompt, summary, files_to_download
246
+
247
  except Exception as e:
248
+ logging.error(f"Error processing PDF: {e}")
249
+ return f"Error processing PDF: {str(e)}", "", "", []
250
 
251
  # Main Interface
252
  with gr.Blocks(theme=gr.themes.Default()) as demo:
253
+ # Store context size value
254
+ context_size_value = gr.State(value=32000)
255
+
256
  # Header
257
  gr.Markdown("# πŸ“„ Smart PDF Summarizer")
258
+ gr.Markdown("Upload a PDF document and get AI-powered summaries using various AI models.")
259
 
260
  # Main Content
261
  with gr.Row():
 
275
 
276
  gr.Markdown("### Context Window Size")
277
  with gr.Row():
278
+ context_buttons = []
279
  for size_name, size_value in CONTEXT_SIZES.items():
280
+ btn = gr.Button(size_name)
281
+ context_buttons.append((btn, size_value))
282
 
283
  context_size = gr.Slider(
284
  minimum=1000,
 
301
  )
302
 
303
  model_choice = gr.Radio(
304
+ choices=["OpenAI ChatGPT", "HuggingFace Inference", "Groq API"],
305
  value="OpenAI ChatGPT",
306
  label="πŸ€– Model Selection"
307
  )
308
 
309
+ with gr.Column(visible=False) as hf_options:
310
+ hf_model = gr.Dropdown(
311
+ choices=list(model_registry.hf_models.keys()),
312
+ label="πŸ”§ HuggingFace Model",
313
+ value="Phi-3 Mini 128k"
314
+ )
315
+ hf_custom_model = gr.Textbox(
316
+ label="Custom Model ID",
317
+ placeholder="Enter custom model ID...",
318
+ visible=False
319
+ )
320
+ hf_api_key = gr.Textbox(
321
+ label="πŸ”‘ HuggingFace API Key",
322
+ type="password"
323
+ )
324
 
325
+ with gr.Column(visible=False) as groq_options:
326
+ groq_model = gr.Dropdown(
327
+ choices=list(model_registry.groq_models.keys()),
328
+ label="πŸ”§ Groq Model",
329
+ value=list(model_registry.groq_models.keys())[0]
330
+ )
331
+ groq_refresh_btn = gr.Button("πŸ”„ Refresh Models")
332
+ groq_api_key = gr.Textbox(
333
+ label="πŸ”‘ Groq API Key",
334
+ type="password"
335
  )
336
 
337
  # Right Column - Output
338
  with gr.Column(scale=1):
339
+ process_button = gr.Button("πŸš€ Process PDF", variant="primary")
340
+
 
341
  progress_status = gr.Textbox(
342
  label="πŸ“Š Progress",
343
  interactive=False
 
364
  )
365
 
366
  # Event Handlers
367
+ def update_context_size(size):
368
+ return gr.update(value=size)
369
 
370
+ def toggle_model_options(choice):
371
+ return (
372
+ gr.update(visible=choice == "HuggingFace Inference"),
373
+ gr.update(visible=choice == "Groq API")
374
+ )
375
+
376
+ def refresh_groq_models_list():
377
+ updated_models = model_registry.refresh_groq_models()
378
+ return gr.update(choices=list(updated_models.keys()))
379
+
380
+ def toggle_custom_model(model_name):
381
+ return gr.update(visible=model_name == "Custom Model")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  # Connect event handlers
384
  model_choice.change(
385
+ toggle_model_options,
386
  inputs=[model_choice],
387
+ outputs=[hf_options, groq_options]
388
  )
389
+
390
+ for btn, size_value in context_buttons:
391
+ btn.click(
392
+ update_context_size,
393
+ inputs=[],
394
+ outputs=[context_size]
395
+ ).then(
396
+ lambda x=size_value: x,
397
+ None,
398
+ context_size
399
+ )
400
+
401
+ hf_model.change(
402
+ toggle_custom_model,
403
+ inputs=[hf_model],
404
+ outputs=[hf_custom_model]
405
+ )
406
+
407
+ groq_refresh_btn.click(
408
+ refresh_groq_models_list,
409
+ outputs=[groq_model]
410
+ )
411
+
412
  process_button.click(
413
  process_pdf,
414
  inputs=[
 
418
  snippet_number,
419
  custom_prompt,
420
  model_choice,
421
+ hf_model,
422
+ hf_custom_model,
423
+ hf_api_key,
424
+ groq_model,
425
+ groq_api_key
426
  ],
427
  outputs=[
428
  progress_status,
 
431
  download_files
432
  ]
433
  )
434
+
435
  copy_prompt_button.click(
436
  copy_to_clipboard,
437
  inputs=[generated_prompt],
438
  outputs=[progress_status]
439
  )
440
+
441
  copy_summary_button.click(
442
  copy_to_clipboard,
443
  inputs=[summary_output],
444
  outputs=[progress_status]
445
  )
446
+
447
  open_chatgpt_button.click(
448
  open_chatgpt,
449
  outputs=[progress_status]
 
455
  1. Upload a PDF document
456
  2. Choose output format and context window size
457
  3. Select snippet number (default: 1) or enter custom prompt
458
+ 4. Select your preferred model:
459
+ - OpenAI ChatGPT: Manual copy/paste workflow
460
+ - HuggingFace Inference: Direct API integration
461
+ - Groq API: High-performance inference
462
  5. Click 'Process PDF' to generate summary
463
  6. Use 'Copy Prompt' and 'Open ChatGPT' for manual processing
464
  7. Download generated files as needed
 
467
  - Support for multiple PDF formats
468
  - Flexible text formatting options
469
  - Predefined context window sizes (4K to 200K)
470
+ - Multiple model integrations
471
  - Copy to clipboard functionality
472
  - Direct ChatGPT integration
473
  - Downloadable outputs