""" Session export generators for ResolutionFlow. Provides markdown, plain text, HTML, and PSA/ticket note export formatters for troubleshooting sessions. """ import html from datetime import datetime, timezone from app.models.session import Session from app.schemas.session import SessionExport def _format_duration(started_at: datetime, completed_at: datetime | None) -> str: """Format duration between two datetimes as human-readable string.""" if not completed_at: return "In progress" delta = completed_at - started_at total_seconds = int(delta.total_seconds()) if total_seconds < 0: return "0 minutes" hours, remainder = divmod(total_seconds, 3600) minutes = remainder // 60 if hours > 0: return f"{hours}h {minutes}m" return f"{minutes} minutes" def generate_markdown_export(session: Session, options: SessionExport) -> str: """Generate markdown export.""" lines = [] if options.include_tree_info: tree_name = session.tree_snapshot.get("name", "Troubleshooting Session") lines.append(f"# {tree_name}") lines.append("") if session.ticket_number: lines.append(f"**Ticket:** {session.ticket_number}") if session.client_name: lines.append(f"**Client:** {session.client_name}") if options.include_timestamps: lines.append(f"**Started:** {session.started_at.strftime('%Y-%m-%d %H:%M')}") if session.completed_at: lines.append(f"**Completed:** {session.completed_at.strftime('%Y-%m-%d %H:%M')}") lines.append("") lines.append("---") lines.append("") # Scratchpad / Evidence section scratchpad = getattr(session, 'scratchpad', '') or '' if scratchpad.strip(): lines.append("## Evidence / Reference") lines.append("") lines.append(scratchpad) lines.append("") lines.append("---") lines.append("") lines.append("## Troubleshooting Steps") lines.append("") for i, decision in enumerate(session.decisions, 1): question = decision.get("question") or decision.get("action_performed", "Step") answer = decision.get("answer", "") notes = decision.get("notes", "") lines.append(f"### Step {i}: {question}") if answer: lines.append(f"**Answer:** {answer}") if notes: lines.append(f"**Notes:** {notes}") if options.include_timestamps and decision.get("timestamp"): lines.append(f"*{decision['timestamp']}*") lines.append("") return "\n".join(lines) def generate_text_export(session: Session, options: SessionExport) -> str: """Generate plain text export.""" lines = [] if options.include_tree_info: tree_name = session.tree_snapshot.get("name", "Troubleshooting Session") lines.append(tree_name) lines.append("=" * len(tree_name)) if session.ticket_number: lines.append(f"Ticket: {session.ticket_number}") if session.client_name: lines.append(f"Client: {session.client_name}") if options.include_timestamps: lines.append(f"Started: {session.started_at.strftime('%Y-%m-%d %H:%M')}") if session.completed_at: lines.append(f"Completed: {session.completed_at.strftime('%Y-%m-%d %H:%M')}") lines.append("") # Scratchpad / Evidence section scratchpad = getattr(session, 'scratchpad', '') or '' if scratchpad.strip(): lines.append("EVIDENCE / REFERENCE") lines.append("-" * 20) lines.append(scratchpad) lines.append("") lines.append("TROUBLESHOOTING STEPS") lines.append("-" * 20) for i, decision in enumerate(session.decisions, 1): question = decision.get("question") or decision.get("action_performed", "Step") answer = decision.get("answer", "") notes = decision.get("notes", "") lines.append(f"\n{i}. {question}") if answer: lines.append(f" Answer: {answer}") if notes: lines.append(f" Notes: {notes}") return "\n".join(lines) def generate_html_export(session: Session, options: SessionExport) -> str: """Generate HTML export.""" tree_name = html.escape(session.tree_snapshot.get("name", "Troubleshooting Session")) html_parts = ['', '', '
', '', f'Answer: {answer}
') if notes: html_parts.append(f'Notes: {notes}
') if options.include_timestamps and decision.get("timestamp"): html_parts.append(f'') html_parts.append('