diff --git a/backend/app/api/endpoints/sessions.py b/backend/app/api/endpoints/sessions.py index 47a238a5..ea4375f1 100644 --- a/backend/app/api/endpoints/sessions.py +++ b/backend/app/api/endpoints/sessions.py @@ -407,18 +407,35 @@ async def export_session( headers={"Content-Disposition": f'attachment; filename="session-export-{session_id}.pdf"'}, ) + # Query supporting data for non-PDF formats + from app.models.supporting_data import SessionSupportingData + sd_result = await db.execute( + select(SessionSupportingData) + .where(SessionSupportingData.session_id == session_id) + .order_by(SessionSupportingData.sort_order) + ) + supporting_data_items = [ + { + "label": sd.label, + "data_type": sd.data_type, + "content": sd.content, + "content_type": sd.content_type, + } + for sd in sd_result.scalars().all() + ] + # Generate export based on format if export_options.format == "markdown": - content = generate_markdown_export(session, export_options) + content = generate_markdown_export(session, export_options, supporting_data=supporting_data_items) media_type = "text/markdown" elif export_options.format == "html": - content = generate_html_export(session, export_options) + content = generate_html_export(session, export_options, supporting_data=supporting_data_items) media_type = "text/html" elif export_options.format == "psa": - content = generate_psa_export(session, export_options) + content = generate_psa_export(session, export_options, supporting_data=supporting_data_items) media_type = "text/plain" else: # text - content = generate_text_export(session, export_options) + content = generate_text_export(session, export_options, supporting_data=supporting_data_items) media_type = "text/plain" # Resolve variables in export output diff --git a/backend/app/services/export_service.py b/backend/app/services/export_service.py index 15e1426b..7d3d8091 100644 --- a/backend/app/services/export_service.py +++ b/backend/app/services/export_service.py @@ -171,7 +171,7 @@ def _escape_markdown_table(value: str) -> str: return value.replace("|", "\\|").replace("\n", " ") -def generate_markdown_export(session: Session, options: SessionExport) -> str: +def generate_markdown_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str: """Generate markdown export.""" if _is_procedural_session(session): return _generate_procedural_markdown(session, options) @@ -261,6 +261,22 @@ def generate_markdown_export(session: Session, options: SessionExport) -> str: lines.append(f"*{decision['timestamp']}*") lines.append("") + # Supporting Data + if supporting_data: + lines.append("---") + lines.append("") + lines.append("## Supporting Data") + lines.append("") + for sd in supporting_data: + lines.append(f"### {sd['label']}") + if sd["data_type"] == "text_snippet": + lines.append("```") + lines.append(sd["content"]) + lines.append("```") + else: + lines.append(f"[Screenshot: {sd['label']}]") + lines.append("") + # Resolution / Outcome Notes _raw_notes = getattr(session, 'outcome_notes', None) outcome_notes = _raw_notes if isinstance(_raw_notes, str) else '' @@ -286,7 +302,7 @@ def generate_markdown_export(session: Session, options: SessionExport) -> str: return "\n".join(lines) -def generate_text_export(session: Session, options: SessionExport) -> str: +def generate_text_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str: """Generate plain text export.""" if _is_procedural_session(session): return _generate_procedural_text(session, options) @@ -361,6 +377,19 @@ def generate_text_export(session: Session, options: SessionExport) -> str: if duration_seconds is not None: lines.append(f" Duration: {_format_step_duration(duration_seconds)}") + # Supporting Data + if supporting_data: + lines.append("") + lines.append("SUPPORTING DATA") + lines.append("-" * 20) + for sd in supporting_data: + lines.append(f"\n {sd['label']}:") + if sd["data_type"] == "text_snippet": + for content_line in sd["content"].splitlines(): + lines.append(f" {content_line}") + else: + lines.append(f" [Screenshot: {sd['label']}]") + # Resolution _raw_notes = getattr(session, 'outcome_notes', None) outcome_notes = _raw_notes if isinstance(_raw_notes, str) else '' @@ -382,7 +411,7 @@ def generate_text_export(session: Session, options: SessionExport) -> str: return "\n".join(lines) -def generate_html_export(session: Session, options: SessionExport) -> str: +def generate_html_export(session: Session, options: SessionExport, supporting_data: list[dict] | None = None) -> str: """Generate HTML export.""" if _is_procedural_session(session): return _generate_procedural_html(session, options) @@ -472,6 +501,15 @@ def generate_html_export(session: Session, options: SessionExport) -> str: html_parts.append(f'
') html_parts.append('') + # Supporting Data + if supporting_data: + html_parts.append('{html.escape(sd["content"])}