# 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"{key}: {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