JatsTheAIGen commited on
Commit
93c9801
Β·
1 Parent(s): cbd78de

Fix build issues: simplify app.py and fix packages.txt

Browse files
Files changed (4) hide show
  1. app.py +67 -145
  2. app_simple.py +308 -0
  3. packages.txt +0 -1
  4. requirements.txt +0 -1
app.py CHANGED
@@ -1,5 +1,4 @@
1
- # PDF Analysis & Orchestrator
2
- # Extracted core functionality from Sharmaji ka PDF Blaster V1
3
  import os
4
  import asyncio
5
  import uuid
@@ -24,7 +23,10 @@ from config import Config
24
  # ------------------------
25
  # Initialize Components
26
  # ------------------------
27
- Config.ensure_directories()
 
 
 
28
 
29
  # Agent Roster - Focused on Analysis & Orchestration
30
  AGENTS = {
@@ -35,8 +37,13 @@ AGENTS = {
35
  ORCHESTRATOR = MasterOrchestrator(agents=AGENTS)
36
 
37
  # Initialize managers
38
- PROMPT_MANAGER = PromptManager()
39
- EXPORT_MANAGER = ExportManager()
 
 
 
 
 
40
 
41
  # ------------------------
42
  # File Handling
@@ -76,12 +83,10 @@ def handle_analysis(file, prompt, username="anonymous", use_streaming=False):
76
  if file is None:
77
  return "Please upload a PDF.", None, None
78
 
79
- validate_file_size(file)
80
- path = save_uploaded_file(file, username)
81
-
82
- if use_streaming:
83
- return handle_analysis_streaming(path, prompt, username)
84
- else:
85
  result = run_async(
86
  ORCHESTRATOR.handle_user_prompt,
87
  user_id=username,
@@ -90,86 +95,63 @@ def handle_analysis(file, prompt, username="anonymous", use_streaming=False):
90
  targets=["analysis"]
91
  )
92
  return result.get("analysis", "No analysis result."), None, None
93
-
94
- def handle_analysis_streaming(file_path, prompt, username="anonymous"):
95
- """Handle analysis with streaming output"""
96
- def stream_generator():
97
- async def async_stream():
98
- async for chunk in ORCHESTRATOR.handle_user_prompt_streaming(
99
- user_id=username,
100
- prompt=prompt,
101
- file_path=file_path,
102
- targets=["analysis"]
103
- ):
104
- yield chunk
105
-
106
- # Convert async generator to sync generator
107
- loop = asyncio.new_event_loop()
108
- asyncio.set_event_loop(loop)
109
- try:
110
- async_gen = async_stream()
111
- while True:
112
- try:
113
- chunk = loop.run_until_complete(async_gen.__anext__())
114
- yield chunk
115
- except StopAsyncIteration:
116
- break
117
- finally:
118
- loop.close()
119
-
120
- return stream_generator(), None, None
121
 
122
  def handle_batch_analysis(files, prompt, username="anonymous"):
123
  """Handle batch analysis of multiple PDFs"""
124
  if not files or len(files) == 0:
125
  return "Please upload at least one PDF.", None, None
126
 
127
- # Validate all files
128
- file_paths = []
129
- for file in files:
130
- try:
131
  validate_file_size(file)
132
  path = save_uploaded_file(file, username)
133
  file_paths.append(path)
134
- except Exception as e:
135
- return f"Error with file {file}: {str(e)}", None, None
136
-
137
- result = run_async(
138
- ORCHESTRATOR.handle_batch_analysis,
139
- user_id=username,
140
- prompt=prompt,
141
- file_paths=file_paths,
142
- targets=["analysis"]
143
- )
144
-
145
- # Format batch results
146
- batch_summary = result.get("summary", {})
147
- batch_results = result.get("batch_results", [])
148
-
149
- formatted_output = f"πŸ“Š Batch Analysis Results\n"
150
- formatted_output += f"Total files: {batch_summary.get('processing_stats', {}).get('total_files', 0)}\n"
151
- formatted_output += f"Successful: {batch_summary.get('processing_stats', {}).get('successful', 0)}\n"
152
- formatted_output += f"Failed: {batch_summary.get('processing_stats', {}).get('failed', 0)}\n"
153
- formatted_output += f"Success rate: {batch_summary.get('processing_stats', {}).get('success_rate', '0%')}\n\n"
154
-
155
- if batch_summary.get("batch_analysis"):
156
- formatted_output += f"πŸ“‹ Batch Summary:\n{batch_summary['batch_analysis']}\n\n"
157
-
158
- formatted_output += "πŸ“„ Individual Results:\n"
159
- for i, file_result in enumerate(batch_results):
160
- formatted_output += f"\n--- File {i+1}: {Path(file_result.get('file_path', 'Unknown')).name} ---\n"
161
- if "error" in file_result:
162
- formatted_output += f"❌ Error: {file_result['error']}\n"
163
- else:
164
- formatted_output += f"βœ… {file_result.get('analysis', 'No analysis')}\n"
165
-
166
- return formatted_output, None, None
167
 
168
  def handle_export(result_text, export_format, username="anonymous"):
169
  """Handle export of analysis results"""
170
  if not result_text or result_text.strip() == "":
171
  return "No content to export.", None
172
 
 
 
 
173
  try:
174
  if export_format == "txt":
175
  filepath = EXPORT_MANAGER.export_text(result_text, username=username)
@@ -187,19 +169,23 @@ def handle_export(result_text, export_format, username="anonymous"):
187
 
188
  def get_custom_prompts():
189
  """Get available custom prompts"""
 
 
190
  prompts = PROMPT_MANAGER.get_all_prompts()
191
  return list(prompts.keys())
192
 
193
  def load_custom_prompt(prompt_id):
194
  """Load a custom prompt template"""
 
 
195
  return PROMPT_MANAGER.get_prompt(prompt_id) or ""
196
 
197
  # ------------------------
198
- # Gradio UI - Enhanced Interface
199
  # ------------------------
200
  with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as demo:
201
  gr.Markdown("# πŸ“„ PDF Analysis & Orchestrator - Intelligent Document Processing")
202
- gr.Markdown("Upload PDFs and provide instructions for analysis, summarization, or explanation. Now with enhanced features!")
203
 
204
  with gr.Tabs():
205
  # Single Document Analysis Tab
@@ -217,14 +203,6 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
217
  value=None
218
  )
219
  load_prompt_btn = gr.Button("Load Prompt", size="sm")
220
-
221
- # Analysis Options
222
- with gr.Accordion("βš™οΈ Analysis Options", open=False):
223
- use_streaming = gr.Checkbox(label="Enable Streaming Output", value=False)
224
- chunk_size = gr.Slider(
225
- minimum=5000, maximum=30000, value=15000, step=1000,
226
- label="Chunk Size (for large documents)"
227
- )
228
 
229
  with gr.Column(scale=2):
230
  gr.Markdown("### Analysis Instructions")
@@ -254,10 +232,6 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
254
  )
255
  export_btn = gr.Button("πŸ“₯ Export", variant="secondary")
256
  export_status = gr.Textbox(label="Export Status", interactive=False)
257
-
258
- # Document Info
259
- with gr.Accordion("πŸ“Š Document Info", open=False):
260
- doc_info = gr.Textbox(label="Document Information", interactive=False, lines=6)
261
 
262
  # Batch Processing Tab
263
  with gr.Tab("πŸ“š Batch Processing"):
@@ -281,44 +255,12 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
281
  batch_output = gr.Textbox(label="Batch Results", lines=20, max_lines=30, show_copy_button=True)
282
  batch_status = gr.Textbox(label="Batch Status", interactive=False)
283
 
284
- # Custom Prompts Management Tab
285
- with gr.Tab("🎯 Manage Prompts"):
286
- with gr.Row():
287
- with gr.Column(scale=1):
288
- gr.Markdown("### Add New Prompt")
289
- new_prompt_id = gr.Textbox(label="Prompt ID", placeholder="my_custom_prompt")
290
- new_prompt_name = gr.Textbox(label="Prompt Name", placeholder="My Custom Analysis")
291
- new_prompt_desc = gr.Textbox(label="Description", placeholder="What this prompt does")
292
- new_prompt_template = gr.Textbox(
293
- lines=4,
294
- label="Prompt Template",
295
- placeholder="Enter your custom prompt template..."
296
- )
297
- new_prompt_category = gr.Dropdown(
298
- choices=["custom", "business", "technical", "explanation", "analysis"],
299
- label="Category",
300
- value="custom"
301
- )
302
- add_prompt_btn = gr.Button("βž• Add Prompt", variant="primary")
303
-
304
- with gr.Column(scale=1):
305
- gr.Markdown("### Existing Prompts")
306
- prompt_list = gr.Dataframe(
307
- headers=["ID", "Name", "Category", "Description"],
308
- datatype=["str", "str", "str", "str"],
309
- interactive=False,
310
- label="Available Prompts"
311
- )
312
- refresh_prompts_btn = gr.Button("πŸ”„ Refresh List")
313
- delete_prompt_id = gr.Textbox(label="Prompt ID to Delete", placeholder="prompt_id")
314
- delete_prompt_btn = gr.Button("πŸ—‘οΈ Delete Prompt", variant="stop")
315
-
316
  # Event Handlers
317
  # Single document analysis
318
  submit_btn.click(
319
  fn=handle_analysis,
320
- inputs=[pdf_in, prompt_input, username_input, use_streaming],
321
- outputs=[output_box, status_box, doc_info]
322
  )
323
 
324
  # Load custom prompt
@@ -348,26 +290,6 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
348
  inputs=[batch_files, batch_prompt, batch_username],
349
  outputs=[batch_output, batch_status, gr.State()]
350
  )
351
-
352
- # Prompt management
353
- add_prompt_btn.click(
354
- fn=lambda id, name, desc, template, cat: PROMPT_MANAGER.add_prompt(id, name, desc, template, cat),
355
- inputs=[new_prompt_id, new_prompt_name, new_prompt_desc, new_prompt_template, new_prompt_category],
356
- outputs=[]
357
- )
358
-
359
- refresh_prompts_btn.click(
360
- fn=lambda: [[pid, prompt["name"], prompt["category"], prompt["description"]]
361
- for pid, prompt in PROMPT_MANAGER.get_all_prompts().items()],
362
- inputs=[],
363
- outputs=[prompt_list]
364
- )
365
-
366
- delete_prompt_btn.click(
367
- fn=lambda pid: PROMPT_MANAGER.delete_prompt(pid),
368
- inputs=[delete_prompt_id],
369
- outputs=[]
370
- )
371
 
372
  # Examples
373
  gr.Examples(
@@ -383,4 +305,4 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
383
  )
384
 
385
  if __name__ == "__main__":
386
- demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
 
1
+ # PDF Analysis & Orchestrator - Simplified for Hugging Face Spaces
 
2
  import os
3
  import asyncio
4
  import uuid
 
23
  # ------------------------
24
  # Initialize Components
25
  # ------------------------
26
+ try:
27
+ Config.ensure_directories()
28
+ except Exception as e:
29
+ print(f"Warning: Could not ensure directories: {e}")
30
 
31
  # Agent Roster - Focused on Analysis & Orchestration
32
  AGENTS = {
 
37
  ORCHESTRATOR = MasterOrchestrator(agents=AGENTS)
38
 
39
  # Initialize managers
40
+ try:
41
+ PROMPT_MANAGER = PromptManager()
42
+ EXPORT_MANAGER = ExportManager()
43
+ except Exception as e:
44
+ print(f"Warning: Could not initialize managers: {e}")
45
+ PROMPT_MANAGER = None
46
+ EXPORT_MANAGER = None
47
 
48
  # ------------------------
49
  # File Handling
 
83
  if file is None:
84
  return "Please upload a PDF.", None, None
85
 
86
+ try:
87
+ validate_file_size(file)
88
+ path = save_uploaded_file(file, username)
89
+
 
 
90
  result = run_async(
91
  ORCHESTRATOR.handle_user_prompt,
92
  user_id=username,
 
95
  targets=["analysis"]
96
  )
97
  return result.get("analysis", "No analysis result."), None, None
98
+ except Exception as e:
99
+ return f"Error during analysis: {str(e)}", None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  def handle_batch_analysis(files, prompt, username="anonymous"):
102
  """Handle batch analysis of multiple PDFs"""
103
  if not files or len(files) == 0:
104
  return "Please upload at least one PDF.", None, None
105
 
106
+ try:
107
+ # Validate all files
108
+ file_paths = []
109
+ for file in files:
110
  validate_file_size(file)
111
  path = save_uploaded_file(file, username)
112
  file_paths.append(path)
113
+
114
+ result = run_async(
115
+ ORCHESTRATOR.handle_batch_analysis,
116
+ user_id=username,
117
+ prompt=prompt,
118
+ file_paths=file_paths,
119
+ targets=["analysis"]
120
+ )
121
+
122
+ # Format batch results
123
+ batch_summary = result.get("summary", {})
124
+ batch_results = result.get("batch_results", [])
125
+
126
+ formatted_output = f"πŸ“Š Batch Analysis Results\n"
127
+ formatted_output += f"Total files: {batch_summary.get('processing_stats', {}).get('total_files', 0)}\n"
128
+ formatted_output += f"Successful: {batch_summary.get('processing_stats', {}).get('successful', 0)}\n"
129
+ formatted_output += f"Failed: {batch_summary.get('processing_stats', {}).get('failed', 0)}\n"
130
+ formatted_output += f"Success rate: {batch_summary.get('processing_stats', {}).get('success_rate', '0%')}\n\n"
131
+
132
+ if batch_summary.get("batch_analysis"):
133
+ formatted_output += f"πŸ“‹ Batch Summary:\n{batch_summary['batch_analysis']}\n\n"
134
+
135
+ formatted_output += "πŸ“„ Individual Results:\n"
136
+ for i, file_result in enumerate(batch_results):
137
+ formatted_output += f"\n--- File {i+1}: {Path(file_result.get('file_path', 'Unknown')).name} ---\n"
138
+ if "error" in file_result:
139
+ formatted_output += f"❌ Error: {file_result['error']}\n"
140
+ else:
141
+ formatted_output += f"βœ… {file_result.get('analysis', 'No analysis')}\n"
142
+
143
+ return formatted_output, None, None
144
+ except Exception as e:
145
+ return f"Error during batch analysis: {str(e)}", None, None
146
 
147
  def handle_export(result_text, export_format, username="anonymous"):
148
  """Handle export of analysis results"""
149
  if not result_text or result_text.strip() == "":
150
  return "No content to export.", None
151
 
152
+ if not EXPORT_MANAGER:
153
+ return "Export functionality not available.", None
154
+
155
  try:
156
  if export_format == "txt":
157
  filepath = EXPORT_MANAGER.export_text(result_text, username=username)
 
169
 
170
  def get_custom_prompts():
171
  """Get available custom prompts"""
172
+ if not PROMPT_MANAGER:
173
+ return []
174
  prompts = PROMPT_MANAGER.get_all_prompts()
175
  return list(prompts.keys())
176
 
177
  def load_custom_prompt(prompt_id):
178
  """Load a custom prompt template"""
179
+ if not PROMPT_MANAGER:
180
+ return ""
181
  return PROMPT_MANAGER.get_prompt(prompt_id) or ""
182
 
183
  # ------------------------
184
+ # Gradio UI - Simplified Interface
185
  # ------------------------
186
  with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as demo:
187
  gr.Markdown("# πŸ“„ PDF Analysis & Orchestrator - Intelligent Document Processing")
188
+ gr.Markdown("Upload PDFs and provide instructions for analysis, summarization, or explanation.")
189
 
190
  with gr.Tabs():
191
  # Single Document Analysis Tab
 
203
  value=None
204
  )
205
  load_prompt_btn = gr.Button("Load Prompt", size="sm")
 
 
 
 
 
 
 
 
206
 
207
  with gr.Column(scale=2):
208
  gr.Markdown("### Analysis Instructions")
 
232
  )
233
  export_btn = gr.Button("πŸ“₯ Export", variant="secondary")
234
  export_status = gr.Textbox(label="Export Status", interactive=False)
 
 
 
 
235
 
236
  # Batch Processing Tab
237
  with gr.Tab("πŸ“š Batch Processing"):
 
255
  batch_output = gr.Textbox(label="Batch Results", lines=20, max_lines=30, show_copy_button=True)
256
  batch_status = gr.Textbox(label="Batch Status", interactive=False)
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  # Event Handlers
259
  # Single document analysis
260
  submit_btn.click(
261
  fn=handle_analysis,
262
+ inputs=[pdf_in, prompt_input, username_input, gr.State(False)],
263
+ outputs=[output_box, status_box, gr.State()]
264
  )
265
 
266
  # Load custom prompt
 
290
  inputs=[batch_files, batch_prompt, batch_username],
291
  outputs=[batch_output, batch_status, gr.State()]
292
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
  # Examples
295
  gr.Examples(
 
305
  )
306
 
307
  if __name__ == "__main__":
308
+ demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
app_simple.py ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PDF Analysis & Orchestrator - Simplified for Hugging Face Spaces
2
+ import os
3
+ import asyncio
4
+ import uuid
5
+ from pathlib import Path
6
+ from typing import Optional, List, Tuple
7
+ import time
8
+
9
+ import gradio as gr
10
+ from agents import (
11
+ AnalysisAgent,
12
+ CollaborationAgent,
13
+ ConversationAgent,
14
+ MasterOrchestrator,
15
+ )
16
+ from utils import load_pdf_text
17
+ from utils.session import make_user_session
18
+ from utils.validation import validate_file_size
19
+ from utils.prompts import PromptManager
20
+ from utils.export import ExportManager
21
+ from config import Config
22
+
23
+ # ------------------------
24
+ # Initialize Components
25
+ # ------------------------
26
+ try:
27
+ Config.ensure_directories()
28
+ except Exception as e:
29
+ print(f"Warning: Could not ensure directories: {e}")
30
+
31
+ # Agent Roster - Focused on Analysis & Orchestration
32
+ AGENTS = {
33
+ "analysis": AnalysisAgent(name="AnalysisAgent", model=Config.OPENAI_MODEL, tasks_completed=0),
34
+ "collab": CollaborationAgent(name="CollaborationAgent", model=Config.OPENAI_MODEL, tasks_completed=0),
35
+ "conversation": ConversationAgent(name="ConversationAgent", model=Config.OPENAI_MODEL, tasks_completed=0),
36
+ }
37
+ ORCHESTRATOR = MasterOrchestrator(agents=AGENTS)
38
+
39
+ # Initialize managers
40
+ try:
41
+ PROMPT_MANAGER = PromptManager()
42
+ EXPORT_MANAGER = ExportManager()
43
+ except Exception as e:
44
+ print(f"Warning: Could not initialize managers: {e}")
45
+ PROMPT_MANAGER = None
46
+ EXPORT_MANAGER = None
47
+
48
+ # ------------------------
49
+ # File Handling
50
+ # ------------------------
51
+ def save_uploaded_file(uploaded, username: str = "anonymous", session_dir: Optional[str] = None) -> str:
52
+ if session_dir is None:
53
+ session_dir = make_user_session(username)
54
+ Path(session_dir).mkdir(parents=True, exist_ok=True)
55
+ dst = Path(session_dir) / f"upload_{uuid.uuid4().hex}.pdf"
56
+
57
+ if isinstance(uploaded, str) and os.path.exists(uploaded):
58
+ from shutil import copyfile
59
+ copyfile(uploaded, dst)
60
+ return str(dst)
61
+ if hasattr(uploaded, "read"):
62
+ with open(dst, "wb") as f:
63
+ f.write(uploaded.read())
64
+ return str(dst)
65
+ if isinstance(uploaded, dict) and "name" in uploaded and os.path.exists(uploaded["name"]):
66
+ from shutil import copyfile
67
+ copyfile(uploaded["name"], dst)
68
+ return str(dst)
69
+ raise RuntimeError("Unable to save uploaded file.")
70
+
71
+ # ------------------------
72
+ # Async wrapper
73
+ # ------------------------
74
+ def run_async(func, *args, **kwargs):
75
+ loop = asyncio.new_event_loop()
76
+ asyncio.set_event_loop(loop)
77
+ return loop.run_until_complete(func(*args, **kwargs))
78
+
79
+ # ------------------------
80
+ # Analysis Handlers - Core Features
81
+ # ------------------------
82
+ def handle_analysis(file, prompt, username="anonymous", use_streaming=False):
83
+ if file is None:
84
+ return "Please upload a PDF.", None, None
85
+
86
+ try:
87
+ validate_file_size(file)
88
+ path = save_uploaded_file(file, username)
89
+
90
+ result = run_async(
91
+ ORCHESTRATOR.handle_user_prompt,
92
+ user_id=username,
93
+ prompt=prompt,
94
+ file_path=path,
95
+ targets=["analysis"]
96
+ )
97
+ return result.get("analysis", "No analysis result."), None, None
98
+ except Exception as e:
99
+ return f"Error during analysis: {str(e)}", None, None
100
+
101
+ def handle_batch_analysis(files, prompt, username="anonymous"):
102
+ """Handle batch analysis of multiple PDFs"""
103
+ if not files or len(files) == 0:
104
+ return "Please upload at least one PDF.", None, None
105
+
106
+ try:
107
+ # Validate all files
108
+ file_paths = []
109
+ for file in files:
110
+ validate_file_size(file)
111
+ path = save_uploaded_file(file, username)
112
+ file_paths.append(path)
113
+
114
+ result = run_async(
115
+ ORCHESTRATOR.handle_batch_analysis,
116
+ user_id=username,
117
+ prompt=prompt,
118
+ file_paths=file_paths,
119
+ targets=["analysis"]
120
+ )
121
+
122
+ # Format batch results
123
+ batch_summary = result.get("summary", {})
124
+ batch_results = result.get("batch_results", [])
125
+
126
+ formatted_output = f"πŸ“Š Batch Analysis Results\n"
127
+ formatted_output += f"Total files: {batch_summary.get('processing_stats', {}).get('total_files', 0)}\n"
128
+ formatted_output += f"Successful: {batch_summary.get('processing_stats', {}).get('successful', 0)}\n"
129
+ formatted_output += f"Failed: {batch_summary.get('processing_stats', {}).get('failed', 0)}\n"
130
+ formatted_output += f"Success rate: {batch_summary.get('processing_stats', {}).get('success_rate', '0%')}\n\n"
131
+
132
+ if batch_summary.get("batch_analysis"):
133
+ formatted_output += f"πŸ“‹ Batch Summary:\n{batch_summary['batch_analysis']}\n\n"
134
+
135
+ formatted_output += "πŸ“„ Individual Results:\n"
136
+ for i, file_result in enumerate(batch_results):
137
+ formatted_output += f"\n--- File {i+1}: {Path(file_result.get('file_path', 'Unknown')).name} ---\n"
138
+ if "error" in file_result:
139
+ formatted_output += f"❌ Error: {file_result['error']}\n"
140
+ else:
141
+ formatted_output += f"βœ… {file_result.get('analysis', 'No analysis')}\n"
142
+
143
+ return formatted_output, None, None
144
+ except Exception as e:
145
+ return f"Error during batch analysis: {str(e)}", None, None
146
+
147
+ def handle_export(result_text, export_format, username="anonymous"):
148
+ """Handle export of analysis results"""
149
+ if not result_text or result_text.strip() == "":
150
+ return "No content to export.", None
151
+
152
+ if not EXPORT_MANAGER:
153
+ return "Export functionality not available.", None
154
+
155
+ try:
156
+ if export_format == "txt":
157
+ filepath = EXPORT_MANAGER.export_text(result_text, username=username)
158
+ elif export_format == "json":
159
+ data = {"analysis": result_text, "exported_by": username, "timestamp": time.time()}
160
+ filepath = EXPORT_MANAGER.export_json(data, username=username)
161
+ elif export_format == "pdf":
162
+ filepath = EXPORT_MANAGER.export_pdf(result_text, username=username)
163
+ else:
164
+ return f"Unsupported export format: {export_format}", None
165
+
166
+ return f"βœ… Export successful! File saved to: {filepath}", filepath
167
+ except Exception as e:
168
+ return f"❌ Export failed: {str(e)}", None
169
+
170
+ def get_custom_prompts():
171
+ """Get available custom prompts"""
172
+ if not PROMPT_MANAGER:
173
+ return []
174
+ prompts = PROMPT_MANAGER.get_all_prompts()
175
+ return list(prompts.keys())
176
+
177
+ def load_custom_prompt(prompt_id):
178
+ """Load a custom prompt template"""
179
+ if not PROMPT_MANAGER:
180
+ return ""
181
+ return PROMPT_MANAGER.get_prompt(prompt_id) or ""
182
+
183
+ # ------------------------
184
+ # Gradio UI - Simplified Interface
185
+ # ------------------------
186
+ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as demo:
187
+ gr.Markdown("# πŸ“„ PDF Analysis & Orchestrator - Intelligent Document Processing")
188
+ gr.Markdown("Upload PDFs and provide instructions for analysis, summarization, or explanation.")
189
+
190
+ with gr.Tabs():
191
+ # Single Document Analysis Tab
192
+ with gr.Tab("πŸ“„ Single Document Analysis"):
193
+ with gr.Row():
194
+ with gr.Column(scale=1):
195
+ pdf_in = gr.File(label="Upload PDF", file_types=[".pdf"], elem_id="file_upload")
196
+ username_input = gr.Textbox(label="Username (optional)", placeholder="anonymous", elem_id="username")
197
+
198
+ # Custom Prompts Section
199
+ with gr.Accordion("🎯 Custom Prompts", open=False):
200
+ prompt_dropdown = gr.Dropdown(
201
+ choices=get_custom_prompts(),
202
+ label="Select Custom Prompt",
203
+ value=None
204
+ )
205
+ load_prompt_btn = gr.Button("Load Prompt", size="sm")
206
+
207
+ with gr.Column(scale=2):
208
+ gr.Markdown("### Analysis Instructions")
209
+ prompt_input = gr.Textbox(
210
+ lines=4,
211
+ placeholder="Describe what you want to do with the document...\nExamples:\n- Summarize this document in 3 key points\n- Explain this technical paper for a 10-year-old\n- Segment this document by themes\n- Analyze the key findings",
212
+ label="Instructions"
213
+ )
214
+
215
+ with gr.Row():
216
+ submit_btn = gr.Button("πŸ” Analyze & Orchestrate", variant="primary", size="lg")
217
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", size="sm")
218
+
219
+ # Results Section
220
+ with gr.Row():
221
+ with gr.Column(scale=2):
222
+ output_box = gr.Textbox(label="Analysis Result", lines=15, max_lines=25, show_copy_button=True)
223
+ status_box = gr.Textbox(label="Status", value="Ready to analyze documents", interactive=False)
224
+
225
+ with gr.Column(scale=1):
226
+ # Export Section
227
+ with gr.Accordion("πŸ’Ύ Export Results", open=False):
228
+ export_format = gr.Dropdown(
229
+ choices=["txt", "json", "pdf"],
230
+ label="Export Format",
231
+ value="txt"
232
+ )
233
+ export_btn = gr.Button("πŸ“₯ Export", variant="secondary")
234
+ export_status = gr.Textbox(label="Export Status", interactive=False)
235
+
236
+ # Batch Processing Tab
237
+ with gr.Tab("πŸ“š Batch Processing"):
238
+ with gr.Row():
239
+ with gr.Column(scale=1):
240
+ batch_files = gr.File(
241
+ label="Upload Multiple PDFs",
242
+ file_count="multiple",
243
+ file_types=[".pdf"]
244
+ )
245
+ batch_username = gr.Textbox(label="Username (optional)", placeholder="anonymous")
246
+
247
+ with gr.Column(scale=2):
248
+ batch_prompt = gr.Textbox(
249
+ lines=3,
250
+ placeholder="Enter analysis instructions for all documents...",
251
+ label="Batch Analysis Instructions"
252
+ )
253
+ batch_submit = gr.Button("πŸš€ Process Batch", variant="primary", size="lg")
254
+
255
+ batch_output = gr.Textbox(label="Batch Results", lines=20, max_lines=30, show_copy_button=True)
256
+ batch_status = gr.Textbox(label="Batch Status", interactive=False)
257
+
258
+ # Event Handlers
259
+ # Single document analysis
260
+ submit_btn.click(
261
+ fn=handle_analysis,
262
+ inputs=[pdf_in, prompt_input, username_input, gr.State(False)],
263
+ outputs=[output_box, status_box, gr.State()]
264
+ )
265
+
266
+ # Load custom prompt
267
+ load_prompt_btn.click(
268
+ fn=load_custom_prompt,
269
+ inputs=[prompt_dropdown],
270
+ outputs=[prompt_input]
271
+ )
272
+
273
+ # Export functionality
274
+ export_btn.click(
275
+ fn=handle_export,
276
+ inputs=[output_box, export_format, username_input],
277
+ outputs=[export_status, gr.State()]
278
+ )
279
+
280
+ # Clear functionality
281
+ clear_btn.click(
282
+ fn=lambda: ("", "", "", "Ready"),
283
+ inputs=[],
284
+ outputs=[pdf_in, prompt_input, output_box, status_box]
285
+ )
286
+
287
+ # Batch processing
288
+ batch_submit.click(
289
+ fn=handle_batch_analysis,
290
+ inputs=[batch_files, batch_prompt, batch_username],
291
+ outputs=[batch_output, batch_status, gr.State()]
292
+ )
293
+
294
+ # Examples
295
+ gr.Examples(
296
+ examples=[
297
+ ["Summarize this document in 3 key points"],
298
+ ["Explain this technical content for a general audience"],
299
+ ["Segment this document by main themes or topics"],
300
+ ["Analyze the key findings and recommendations"],
301
+ ["Create an executive summary of this document"],
302
+ ],
303
+ inputs=prompt_input,
304
+ label="Example Instructions"
305
+ )
306
+
307
+ if __name__ == "__main__":
308
+ demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
packages.txt CHANGED
@@ -1,4 +1,3 @@
1
- # System packages required for PDF Analysis & Orchestrator
2
  libgl1-mesa-glx
3
  libglib2.0-0
4
  libsm6
 
 
1
  libgl1-mesa-glx
2
  libglib2.0-0
3
  libsm6
requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
- # Core dependencies for PDF Analysis & Orchestrator
2
  gradio>=3.30
3
  openai>=1.0.0
4
  pypdf>=3.0.0
 
 
1
  gradio>=3.30
2
  openai>=1.0.0
3
  pypdf>=3.0.0