Major UI improvements: Enhanced formatting, comprehensive custom prompts, fixed export error
624de5a
| # utils/export.py - Export functionality for PDF Analysis & Orchestrator | |
| import json | |
| import os | |
| from pathlib import Path | |
| from typing import Dict, Any, Optional, List | |
| from datetime import datetime | |
| from config import Config | |
| class ExportManager: | |
| """Handle export of analysis results to various formats""" | |
| def __init__(self, export_dir: str = None): | |
| self.export_dir = Path(export_dir or Config.EXPORT_DIR) | |
| self.export_dir.mkdir(parents=True, exist_ok=True) | |
| def export_text(self, content: str, filename: str = None, | |
| metadata: Dict[str, Any] = None) -> str: | |
| """Export content as text file""" | |
| if not filename: | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"analysis_{timestamp}.txt" | |
| if not filename.endswith('.txt'): | |
| filename += '.txt' | |
| filepath = self.export_dir / filename | |
| # Add metadata header if provided | |
| if metadata: | |
| header = self._format_metadata_header(metadata) | |
| content = f"{header}\n\n{content}" | |
| with open(filepath, 'w', encoding='utf-8') as f: | |
| f.write(content) | |
| return str(filepath) | |
| def export_json(self, data: Dict[str, Any], filename: str = None) -> str: | |
| """Export data as JSON file""" | |
| if not filename: | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"analysis_{timestamp}.json" | |
| if not filename.endswith('.json'): | |
| filename += '.json' | |
| filepath = self.export_dir / filename | |
| # Add export metadata | |
| export_data = { | |
| "exported_at": datetime.now().isoformat(), | |
| "export_version": "1.0", | |
| "data": data | |
| } | |
| with open(filepath, 'w', encoding='utf-8') as f: | |
| json.dump(export_data, f, indent=2, ensure_ascii=False) | |
| return str(filepath) | |
| def export_pdf(self, content: str, filename: str = None, | |
| metadata: Dict[str, Any] = None, username: str = None) -> str: | |
| """Export content as PDF (requires reportlab)""" | |
| try: | |
| from reportlab.lib.pagesizes import letter | |
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib.units import inch | |
| except ImportError: | |
| raise ImportError("reportlab is required for PDF export. Install with: pip install reportlab") | |
| if not filename: | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| filename = f"analysis_{timestamp}.pdf" | |
| if not filename.endswith('.pdf'): | |
| filename += '.pdf' | |
| filepath = self.export_dir / filename | |
| # Create PDF | |
| doc = SimpleDocTemplate(str(filepath), pagesize=letter) | |
| styles = getSampleStyleSheet() | |
| # Custom style for content | |
| content_style = ParagraphStyle( | |
| 'CustomContent', | |
| parent=styles['Normal'], | |
| fontSize=11, | |
| spaceAfter=12, | |
| leading=14 | |
| ) | |
| story = [] | |
| # Add metadata header if provided | |
| if metadata: | |
| header_style = ParagraphStyle( | |
| 'Header', | |
| parent=styles['Heading1'], | |
| fontSize=14, | |
| spaceAfter=20 | |
| ) | |
| story.append(Paragraph("Analysis Report", header_style)) | |
| story.append(Spacer(1, 12)) | |
| for key, value in metadata.items(): | |
| story.append(Paragraph(f"<b>{key}:</b> {value}", styles['Normal'])) | |
| story.append(Spacer(1, 20)) | |
| # Add content | |
| paragraphs = content.split('\n\n') | |
| for para in paragraphs: | |
| if para.strip(): | |
| story.append(Paragraph(para.strip(), content_style)) | |
| story.append(Spacer(1, 6)) | |
| doc.build(story) | |
| return str(filepath) | |
| def _format_metadata_header(self, metadata: Dict[str, Any]) -> str: | |
| """Format metadata as text header""" | |
| lines = ["=" * 50, "ANALYSIS REPORT", "=" * 50] | |
| for key, value in metadata.items(): | |
| lines.append(f"{key}: {value}") | |
| lines.append("=" * 50) | |
| return "\n".join(lines) | |
| def get_export_history(self, limit: int = 10) -> List[Dict[str, Any]]: | |
| """Get recent export history""" | |
| files = [] | |
| for filepath in self.export_dir.glob("*"): | |
| if filepath.is_file(): | |
| stat = filepath.stat() | |
| files.append({ | |
| "filename": filepath.name, | |
| "filepath": str(filepath), | |
| "size": stat.st_size, | |
| "created": datetime.fromtimestamp(stat.st_ctime).isoformat(), | |
| "format": filepath.suffix[1:] if filepath.suffix else "unknown" | |
| }) | |
| # Sort by creation time, newest first | |
| files.sort(key=lambda x: x["created"], reverse=True) | |
| return files[:limit] | |
| def cleanup_old_exports(self, days: int = 7) -> int: | |
| """Clean up exports older than specified days""" | |
| cutoff_time = datetime.now().timestamp() - (days * 24 * 60 * 60) | |
| deleted_count = 0 | |
| for filepath in self.export_dir.glob("*"): | |
| if filepath.is_file() and filepath.stat().st_ctime < cutoff_time: | |
| try: | |
| filepath.unlink() | |
| deleted_count += 1 | |
| except Exception: | |
| pass | |
| return deleted_count | |