{_escape(turn.get('label', turn.get('role', 'Turn')))}
") body.append(f"") body.append(f"{_escape(turn.get('content', ''))}
") body.append("from __future__ import annotations import html import json from pathlib import Path def _escape(value: object) -> str: return html.escape(str(value)) def build_accessible_session_text(session: dict) -> str: lines = [ "Didactopus Learner Session", "", f"Learner goal: {session.get('goal', '')}", "", "Study plan:", ] for index, step in enumerate(session.get("study_plan", {}).get("steps", []), start=1): lines.extend( [ f"{index}. {step.get('title', '')}", f" Status: {step.get('status', '')}", f" Prerequisites: {', '.join(step.get('prerequisite_titles', []) or ['none explicit'])}", f" Supporting lessons: {', '.join(step.get('supporting_lessons', []) or ['none listed'])}", ] ) for fragment in step.get("source_fragments", [])[:2]: lines.append(f" Source fragment ({fragment.get('kind', 'fragment')}): {fragment.get('text', '')}") lines.extend( [ "", "Conversation:", ] ) for turn in session.get("turns", []): lines.extend( [ f"{turn.get('label', turn.get('role', 'Turn'))}:", str(turn.get("content", "")), "", ] ) evaluation = session.get("evaluation", {}) lines.extend( [ "Evaluation summary:", f"Verdict: {evaluation.get('verdict', '')}", f"Aggregated dimensions: {json.dumps(evaluation.get('aggregated', {}), sort_keys=True)}", f"Follow-up: {evaluation.get('follow_up', '')}", ] ) return "\n".join(lines).strip() + "\n" def build_accessible_session_html(session: dict) -> str: steps = session.get("study_plan", {}).get("steps", []) turns = session.get("turns", []) evaluation = session.get("evaluation", {}) body = [ "", '', "
", '', '', "This page is structured for keyboard and screen-reader use. It presents the learner goal, study plan, grounded source fragments, and conversation turns in reading order.
', f"Learner goal: {_escape(session.get('goal', ''))}
", "Status: {_escape(step.get('status', ''))}
") body.append( f"Prerequisites: {_escape(', '.join(step.get('prerequisite_titles', []) or ['none explicit']))}
" ) body.append( f"Supporting lessons: {_escape(', '.join(step.get('supporting_lessons', []) or ['none listed']))}
" ) fragments = step.get("source_fragments", [])[:2] if fragments: body.append("Grounding fragments:
") body.append("{_escape(turn.get('content', ''))}
") body.append("Verdict: {_escape(evaluation.get('verdict', ''))}
", f"Aggregated dimensions: {_escape(json.dumps(evaluation.get('aggregated', {}), sort_keys=True))}
", f"Follow-up: {_escape(evaluation.get('follow_up', ''))}
", "