JatsTheAIGen commited on
Commit
73f15b1
Β·
1 Parent(s): bb3909a

Major visual improvements: stunning outputs, downloadable exports, enhanced UI

Browse files
Files changed (3) hide show
  1. agents.py +26 -15
  2. app.py +53 -12
  3. utils/visual_output.py +84 -18
agents.py CHANGED
@@ -103,24 +103,35 @@ class AnalysisAgent(BaseAgent):
103
  # Calculate dynamic tokens
104
  max_tokens = self._calculate_dynamic_tokens(prompt, len(text))
105
 
106
- system = """You are AnalysisAgent: produce crisp, visually appealing, and highly readable insights.
107
 
108
- CRITICAL FORMATTING REQUIREMENTS:
109
- - Use clear section headers with emojis (## πŸ“‹ Key Points, ## πŸ” Analysis, etc.)
110
- - Create concise bullet points (max 1 line each)
111
- - Use tables for data comparison when appropriate
112
- - Include visual separators (---) between major sections
113
- - Use **bold** for key concepts and numbers
114
- - Keep sections short and scannable
115
- - Prioritize actionable insights over lengthy explanations
 
116
 
117
  CONTENT REQUIREMENTS:
118
- - Be concise and to the point
119
- - Use simple language even for technical topics
120
- - Include specific numbers, percentages, and metrics
121
- - Provide clear next steps or recommendations
122
- - Structure information for quick scanning
123
- - Focus on what matters most to the user"""
 
 
 
 
 
 
 
 
 
 
124
 
125
  try:
126
  response = await call_openai_chat(
 
103
  # Calculate dynamic tokens
104
  max_tokens = self._calculate_dynamic_tokens(prompt, len(text))
105
 
106
+ system = """You are AnalysisAgent: produce stunning, visually rich, and highly engaging insights.
107
 
108
+ CRITICAL VISUAL FORMATTING REQUIREMENTS:
109
+ - Use beautiful section headers with emojis and clear hierarchy
110
+ - Create visually appealing bullet points with icons (β€’ βœ… ❌ ⚠️ πŸ’‘ 🎯 πŸ“Š)
111
+ - Use tables extensively for data comparison and organization
112
+ - Include progress bars, metrics cards, and visual separators
113
+ - Use **bold** for key concepts, numbers, and important data
114
+ - Create infographic-style summaries with visual elements
115
+ - Use color coding and visual hierarchy throughout
116
+ - Include actionable insights with clear visual indicators
117
 
118
  CONTENT REQUIREMENTS:
119
+ - Be concise but comprehensive - every word counts
120
+ - Use simple language with technical depth when needed
121
+ - Include specific numbers, percentages, and metrics prominently
122
+ - Provide clear next steps with visual callouts
123
+ - Structure information for instant scanning and understanding
124
+ - Focus on what matters most with visual emphasis
125
+ - Create engaging, professional presentations
126
+
127
+ VISUAL ELEMENTS TO USE:
128
+ - πŸ“Š Data visualizations and metrics
129
+ - 🎯 Key insights with visual emphasis
130
+ - βœ… Success indicators and achievements
131
+ - ⚠️ Important warnings and considerations
132
+ - πŸ’‘ Actionable recommendations
133
+ - πŸ“ˆ Trends and comparisons
134
+ - πŸ” Detailed analysis sections"""
135
 
136
  try:
137
  response = await call_openai_chat(
app.py CHANGED
@@ -2,9 +2,11 @@
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 (
@@ -159,7 +161,7 @@ def handle_batch_analysis(files, prompt, username="anonymous"):
159
  return f"Error during batch analysis: {str(e)}", None, None
160
 
161
  def handle_export(result_text, export_format, username="anonymous"):
162
- """Handle export of analysis results"""
163
  if not result_text or result_text.strip() == "":
164
  return "No content to export.", None
165
 
@@ -167,19 +169,47 @@ def handle_export(result_text, export_format, username="anonymous"):
167
  return "Export functionality not available.", None
168
 
169
  try:
 
 
 
 
170
  if export_format == "txt":
171
- filepath = EXPORT_MANAGER.export_text(result_text, username=username)
 
 
 
172
  elif export_format == "json":
173
- data = {"analysis": result_text, "exported_by": username, "timestamp": time.time()}
174
- filepath = EXPORT_MANAGER.export_json(data, username=username)
 
 
 
 
 
 
175
  elif export_format == "pdf":
176
- filepath = EXPORT_MANAGER.export_pdf(result_text, username=username)
177
  else:
178
  return f"Unsupported export format: {export_format}", None
179
 
180
- return f"βœ… Export successful! File saved to: {filepath}", filepath
 
 
 
 
 
 
 
 
 
181
  except Exception as e:
182
- return f"❌ Export failed: {str(e)}", None
 
 
 
 
 
 
183
 
184
  def get_custom_prompts():
185
  """Get available custom prompts"""
@@ -261,14 +291,25 @@ with gr.Blocks(title="PDF Analysis & Orchestrator", theme=gr.themes.Soft()) as d
261
 
262
  with gr.Column(scale=1):
263
  # Export Section
264
- with gr.Accordion("πŸ’Ύ Export Results", open=False):
 
265
  export_format = gr.Dropdown(
266
  choices=["txt", "json", "pdf"],
267
- label="Export Format",
268
- value="txt"
 
269
  )
270
- export_btn = gr.Button("πŸ“₯ Export", variant="secondary")
271
- export_status = gr.Textbox(label="Export Status", interactive=False)
 
 
 
 
 
 
 
 
 
272
 
273
  # Batch Processing Tab
274
  with gr.Tab("πŸ“š Batch Processing"):
 
2
  import os
3
  import asyncio
4
  import uuid
5
+ import re
6
  from pathlib import Path
7
  from typing import Optional, List, Tuple
8
  import time
9
+ from datetime import datetime
10
 
11
  import gradio as gr
12
  from agents import (
 
161
  return f"Error during batch analysis: {str(e)}", None, None
162
 
163
  def handle_export(result_text, export_format, username="anonymous"):
164
+ """Handle export of analysis results with downloadable files"""
165
  if not result_text or result_text.strip() == "":
166
  return "No content to export.", None
167
 
 
169
  return "Export functionality not available.", None
170
 
171
  try:
172
+ # Create a unique filename
173
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
174
+ filename = f"analysis_{username}_{timestamp}.{export_format}"
175
+
176
  if export_format == "txt":
177
+ # Create a clean text version without HTML
178
+ clean_text = re.sub(r'<[^>]+>', '', result_text) # Remove HTML tags
179
+ clean_text = re.sub(r'\n\s*\n', '\n\n', clean_text) # Clean up spacing
180
+ filepath = EXPORT_MANAGER.export_text(clean_text, filename=filename)
181
  elif export_format == "json":
182
+ data = {
183
+ "analysis": result_text,
184
+ "exported_by": username,
185
+ "timestamp": time.time(),
186
+ "export_date": datetime.now().isoformat(),
187
+ "format": export_format
188
+ }
189
+ filepath = EXPORT_MANAGER.export_json(data, filename=filename)
190
  elif export_format == "pdf":
191
+ filepath = EXPORT_MANAGER.export_pdf(result_text, filename=filename)
192
  else:
193
  return f"Unsupported export format: {export_format}", None
194
 
195
+ # Return success message with download info
196
+ success_msg = f"""
197
+ <div style="background: #d4edda; border: 1px solid #c3e6cb; border-radius: 8px; padding: 15px; margin: 10px 0;">
198
+ <h4 style="color: #155724; margin: 0 0 10px 0;">βœ… Export Successful!</h4>
199
+ <p style="color: #155724; margin: 0 0 10px 0;">Your analysis has been exported as <strong>{export_format.upper()}</strong> format.</p>
200
+ <p style="color: #155724; margin: 0; font-size: 14px;">Filename: <code>{filename}</code></p>
201
+ </div>
202
+ """
203
+
204
+ return success_msg, filepath
205
  except Exception as e:
206
+ error_msg = f"""
207
+ <div style="background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 8px; padding: 15px; margin: 10px 0;">
208
+ <h4 style="color: #721c24; margin: 0 0 10px 0;">❌ Export Failed</h4>
209
+ <p style="color: #721c24; margin: 0;">Error: {str(e)}</p>
210
+ </div>
211
+ """
212
+ return error_msg, None
213
 
214
  def get_custom_prompts():
215
  """Get available custom prompts"""
 
291
 
292
  with gr.Column(scale=1):
293
  # Export Section
294
+ with gr.Accordion("πŸ’Ύ Export & Download", open=True):
295
+ gr.Markdown("**Download your analysis in multiple formats:**")
296
  export_format = gr.Dropdown(
297
  choices=["txt", "json", "pdf"],
298
+ label="πŸ“„ Export Format",
299
+ value="txt",
300
+ info="Choose your preferred format"
301
  )
302
+ export_btn = gr.Button("πŸ“₯ Generate Download", variant="secondary", size="lg")
303
+ export_status = gr.Markdown(
304
+ value="**Ready to export** - Click the button above to generate downloadable files",
305
+ label="Export Status"
306
+ )
307
+
308
+ # Download section
309
+ gr.Markdown("**πŸ“ Download Options:**")
310
+ gr.Markdown("β€’ **TXT**: Clean text format for easy reading")
311
+ gr.Markdown("β€’ **JSON**: Structured data with metadata")
312
+ gr.Markdown("β€’ **PDF**: Professional formatted document")
313
 
314
  # Batch Processing Tab
315
  with gr.Tab("πŸ“š Batch Processing"):
utils/visual_output.py CHANGED
@@ -123,22 +123,30 @@ class VisualOutputGenerator:
123
  return chart
124
 
125
  def create_key_points(self, points: List[str], title: str = "Key Points") -> str:
126
- """Create a visually appealing key points section"""
127
  if not points:
128
  return ""
129
 
 
 
 
130
  visual = f"""
131
  ## πŸ’‘ {title}
132
 
133
- <div style="display: grid; gap: 15px; margin: 20px 0;">
134
  """
135
 
136
  for i, point in enumerate(points, 1):
 
 
 
137
  visual += f"""
138
- <div style="background: #f8f9fa; border-left: 4px solid #007bff; padding: 15px; border-radius: 0 8px 8px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
139
- <div style="display: flex; align-items: flex-start;">
140
- <span style="background: #007bff; color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; font-weight: bold; margin-right: 12px; flex-shrink: 0;">{i}</span>
141
- <p style="margin: 0; line-height: 1.5;">{point}</p>
 
 
142
  </div>
143
  </div>
144
  """
@@ -195,36 +203,94 @@ class VisualOutputGenerator:
195
  return cards
196
 
197
  def format_analysis_with_visuals(self, analysis_text: str, document_metadata: Dict[str, Any] = None) -> str:
198
- """Format analysis text with visual elements"""
199
- # Extract key information for visual representation
200
  visual_elements = []
201
 
202
  # Add document info if available
203
  if document_metadata:
204
  visual_elements.append(self.create_metric_cards({
205
- "Pages": document_metadata.get('page_count', 'Unknown'),
206
- "File Size": f"{document_metadata.get('file_size', 0) / 1024:.1f} KB",
207
- "Processing Time": f"{document_metadata.get('processing_time', 0):.1f}s"
208
- }, "Document Information"))
 
 
 
 
209
 
210
  # Try to extract key points from analysis
211
  key_points = self._extract_key_points(analysis_text)
212
  if key_points:
213
- visual_elements.append(self.create_key_points(key_points))
214
 
215
  # Try to extract metrics
216
  metrics = self._extract_metrics(analysis_text)
217
  if metrics:
218
- visual_elements.append(self.create_metric_cards(metrics, "Key Metrics"))
219
 
220
- # Combine visual elements with analysis
221
- result = analysis_text
 
 
222
 
223
- if visual_elements:
224
- result = "\n\n".join(visual_elements) + "\n\n---\n\n" + analysis_text
 
 
 
 
 
225
 
226
  return result
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  def _extract_key_points(self, text: str) -> List[str]:
229
  """Extract key points from analysis text"""
230
  # Look for bullet points, numbered lists, or key findings
 
123
  return chart
124
 
125
  def create_key_points(self, points: List[str], title: str = "Key Points") -> str:
126
+ """Create a stunning key points section with visual elements"""
127
  if not points:
128
  return ""
129
 
130
+ # Icons for different types of points
131
+ icons = ["🎯", "πŸ’‘", "βœ…", "πŸ“Š", "⚑", "πŸ”", "πŸš€", "πŸ’Ž", "⭐", "πŸ”₯"]
132
+
133
  visual = f"""
134
  ## πŸ’‘ {title}
135
 
136
+ <div style="display: grid; gap: 20px; margin: 25px 0;">
137
  """
138
 
139
  for i, point in enumerate(points, 1):
140
+ icon = icons[i % len(icons)]
141
+ color = ["#007bff", "#28a745", "#ffc107", "#dc3545", "#6f42c1"][i % 5]
142
+
143
  visual += f"""
144
+ <div style="background: linear-gradient(135deg, {color}15, {color}05); border: 2px solid {color}30; padding: 20px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); transition: transform 0.2s ease;">
145
+ <div style="display: flex; align-items: flex-start; gap: 15px;">
146
+ <div style="background: {color}; color: white; border-radius: 50%; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: bold; flex-shrink: 0; box-shadow: 0 2px 8px {color}50;">{icon}</div>
147
+ <div style="flex: 1;">
148
+ <p style="margin: 0; line-height: 1.6; font-size: 16px; color: #333; font-weight: 500;">{point}</p>
149
+ </div>
150
  </div>
151
  </div>
152
  """
 
203
  return cards
204
 
205
  def format_analysis_with_visuals(self, analysis_text: str, document_metadata: Dict[str, Any] = None) -> str:
206
+ """Format analysis text with stunning visual elements"""
 
207
  visual_elements = []
208
 
209
  # Add document info if available
210
  if document_metadata:
211
  visual_elements.append(self.create_metric_cards({
212
+ "πŸ“„ Pages": document_metadata.get('page_count', 'Unknown'),
213
+ "πŸ’Ύ File Size": f"{document_metadata.get('file_size', 0) / 1024:.1f} KB",
214
+ "⚑ Processing": f"{document_metadata.get('processing_time', 0):.1f}s",
215
+ "🎯 Tokens": document_metadata.get('tokens_used', 'N/A')
216
+ }, "πŸ“Š Document Overview"))
217
+
218
+ # Create a beautiful header
219
+ visual_elements.append(self.create_analysis_header())
220
 
221
  # Try to extract key points from analysis
222
  key_points = self._extract_key_points(analysis_text)
223
  if key_points:
224
+ visual_elements.append(self.create_key_points(key_points, "🎯 Key Insights"))
225
 
226
  # Try to extract metrics
227
  metrics = self._extract_metrics(analysis_text)
228
  if metrics:
229
+ visual_elements.append(self.create_metric_cards(metrics, "πŸ“ˆ Key Metrics"))
230
 
231
+ # Try to extract data for tables
232
+ table_data = self._extract_table_data(analysis_text)
233
+ if table_data:
234
+ visual_elements.append(self.create_data_table(table_data, "πŸ“‹ Data Summary"))
235
 
236
+ # Format the main analysis with better structure
237
+ formatted_analysis = self._format_analysis_text(analysis_text)
238
+
239
+ # Combine all elements
240
+ result = "\n\n".join(visual_elements)
241
+ if formatted_analysis:
242
+ result += f"\n\n---\n\n{formatted_analysis}"
243
 
244
  return result
245
 
246
+ def create_analysis_header(self) -> str:
247
+ """Create a beautiful analysis header"""
248
+ return """
249
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 25px; border-radius: 15px; color: white; margin: 20px 0; text-align: center; box-shadow: 0 8px 32px rgba(0,0,0,0.1);">
250
+ <h1 style="margin: 0 0 10px 0; font-size: 28px; font-weight: 700;">πŸ“„ AI Document Analysis</h1>
251
+ <p style="margin: 0; font-size: 16px; opacity: 0.9;">Powered by Advanced AI β€’ Instant Insights β€’ Professional Results</p>
252
+ </div>
253
+ """
254
+
255
+ def _format_analysis_text(self, text: str) -> str:
256
+ """Format analysis text with better visual structure"""
257
+ # Split into sections
258
+ sections = text.split('\n\n')
259
+ formatted_sections = []
260
+
261
+ for section in sections:
262
+ if section.strip():
263
+ # Check if it's a header
264
+ if section.startswith('##'):
265
+ formatted_sections.append(f"\n{section}\n")
266
+ else:
267
+ # Format as a content block
268
+ formatted_sections.append(f"""
269
+ <div style="background: #f8f9fa; border-left: 4px solid #007bff; padding: 20px; margin: 15px 0; border-radius: 0 8px 8px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
270
+ {section}
271
+ </div>
272
+ """)
273
+
274
+ return '\n'.join(formatted_sections)
275
+
276
+ def _extract_table_data(self, text: str) -> List[Dict[str, Any]]:
277
+ """Extract data that can be formatted as tables"""
278
+ table_data = []
279
+
280
+ # Look for comparison patterns
281
+ comparison_pattern = r'(\w+):\s*(\d+(?:\.\d+)?%?)\s*vs\s*(\w+):\s*(\d+(?:\.\d+)?%?)'
282
+ matches = re.findall(comparison_pattern, text, re.IGNORECASE)
283
+
284
+ for match in matches:
285
+ table_data.append({
286
+ "Metric": match[0],
287
+ "Value": match[1],
288
+ "Comparison": match[2],
289
+ "Value 2": match[3]
290
+ })
291
+
292
+ return table_data
293
+
294
  def _extract_key_points(self, text: str) -> List[str]:
295
  """Extract key points from analysis text"""
296
  # Look for bullet points, numbered lists, or key findings