| """Indonesian SBAR-style markdown renderer for `TriageOutput`. |
| |
| Section headers and labels are translated. Narrative content fields |
| (`actions_required`, `flag`, `quote`, `limitations`, `disclaimer`, etc.) are |
| rendered as-is from the draft — they will already be in Indonesian when the |
| drafter ran with `lang="id"`. Enum values stay in English so the schema |
| validates. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from ats.schema import ( |
| AirwayAssessment, |
| BreathingAssessment, |
| CirculationAssessment, |
| DisabilityAssessment, |
| ExposureAssessment, |
| TriageOutput, |
| ) |
|
|
| _CONCERN_RANK = {"low": 0, "moderate": 1, "high": 2, "critical": 3} |
|
|
|
|
| def _highest_concern(draft: TriageOutput) -> str: |
| levels = [ |
| draft.primary_survey.A_airway.concern_level, |
| draft.primary_survey.B_breathing.concern_level, |
| draft.primary_survey.C_circulation.concern_level, |
| draft.primary_survey.D_disability.concern_level, |
| draft.primary_survey.E_exposure.concern_level, |
| ] |
| return max(levels, key=lambda lv: _CONCERN_RANK.get(lv, 0)) |
|
|
|
|
| def _fmt_actions(actions: list[str]) -> str: |
| if not actions: |
| return "tidak ada tindakan spesifik" |
| return "; ".join(actions) |
|
|
|
|
| def _fmt_letter(label: str, assessment) -> str: |
| extras: list[str] = [] |
| if isinstance(assessment, BreathingAssessment): |
| if assessment.rr is not None: |
| extras.append(f"RR {assessment.rr}") |
| if assessment.spo2 is not None: |
| extras.append(f"SpO2 {assessment.spo2}%") |
| elif isinstance(assessment, CirculationAssessment): |
| if assessment.hr is not None: |
| extras.append(f"Nadi {assessment.hr}") |
| if assessment.sbp is not None and assessment.dbp is not None: |
| extras.append(f"TD {assessment.sbp}/{assessment.dbp}") |
| elif isinstance(assessment, DisabilityAssessment): |
| if assessment.gcs is not None: |
| extras.append(f"GCS {assessment.gcs}") |
| elif isinstance(assessment, ExposureAssessment): |
| if assessment.temp is not None: |
| extras.append(f"Suhu {assessment.temp}°C") |
| elif isinstance(assessment, AirwayAssessment): |
| pass |
|
|
| extra_str = f" ({', '.join(extras)})" if extras else "" |
| return ( |
| f"- **{label}**: {assessment.concern_level}{extra_str} — " |
| f"{_fmt_actions(assessment.actions_required)}" |
| ) |
|
|
|
|
| def render_id(draft: TriageOutput) -> str: |
| """Render `draft` as an Indonesian SBAR-style markdown handoff.""" |
| pb = draft.patient_brief |
| ps = draft.primary_survey |
| md = draft.model_metadata |
|
|
| lines: list[str] = [] |
| lines.append(f"# Survei Primer ATLS — Kasus {draft.case_id}") |
| lines.append("") |
| lines.append(f"**Pasien:** {pb.age} {pb.sex}, {pb.mechanism}") |
| lines.append("") |
|
|
| |
| lines.append("## Situasi") |
| lines.append(f"- Tingkat kekhawatiran tertinggi: **{_highest_concern(draft)}**") |
| lines.append(f"- Prioritas disposisi: **{draft.disposition.priority}**") |
| lines.append( |
| f"- Eskalasi: {draft.disposition.escalation.who} ({draft.disposition.escalation.when})" |
| ) |
| lines.append("") |
|
|
| |
| lines.append("## Latar Belakang") |
| lines.append(_fmt_letter("A (jalan napas)", ps.A_airway)) |
| lines.append(_fmt_letter("B (pernapasan)", ps.B_breathing)) |
| lines.append(_fmt_letter("C (sirkulasi)", ps.C_circulation)) |
| lines.append(_fmt_letter("D (disabilitas)", ps.D_disability)) |
| lines.append(_fmt_letter("E (paparan)", ps.E_exposure)) |
| lines.append("") |
|
|
| |
| lines.append("## Temuan Pencitraan") |
| findings = ( |
| list(ps.A_airway.imaging_findings) |
| + list(ps.B_breathing.imaging_findings) |
| + list(ps.C_circulation.imaging_findings) |
| ) |
| if findings: |
| for f in findings: |
| cite = f" [sitasi: {f.citation_id}]" if f.citation_id else "" |
| lines.append(f"- {f.finding} ({f.laterality}, {f.severity}){cite}") |
| else: |
| lines.append("- Tidak ada temuan pencitraan yang menonjol pada proyeksi ini.") |
| lines.append("") |
|
|
| |
| lines.append("## Tanda Bahaya") |
| if draft.red_flags: |
| for rf in draft.red_flags: |
| ev = "; ".join(rf.evidence) if rf.evidence else "tidak ada bukti konkret yang dicatat" |
| lines.append(f"- ⚠ **{rf.flag}** — {rf.immediate_action} _(bukti: {ev})_") |
| else: |
| lines.append("- Tidak ada") |
| lines.append("") |
|
|
| |
| lines.append("## Tindakan yang Direkomendasikan") |
| if draft.disposition.recommended_actions: |
| for a in draft.disposition.recommended_actions: |
| cite = f" [sitasi: {a.citation_id}]" if a.citation_id else "" |
| lines.append(f"- ({a.urgency}) {a.action} — {a.rationale}{cite}") |
| else: |
| lines.append("- Tidak ada") |
|
|
| if draft.disposition.additional_imaging: |
| lines.append("") |
| lines.append("**Pencitraan tambahan:** " + ", ".join(draft.disposition.additional_imaging)) |
| if draft.disposition.labs: |
| lines.append("**Laboratorium:** " + ", ".join(draft.disposition.labs)) |
| lines.append("") |
|
|
| |
| lines.append("## Sitasi") |
| if draft.citations: |
| for c in draft.citations: |
| url = f" {c.url}" if c.url else "" |
| lines.append(f'- [{c.id}] {c.source}, {c.section}: "{c.quote}"{url}') |
| else: |
| lines.append("- Tidak ada") |
| lines.append("") |
|
|
| |
| lines.append("## Metadata Model") |
| lines.append(f"- Model: {md.model}") |
| lines.append(f"- Kepercayaan: {md.confidence}") |
| lines.append(f"- Keterbatasan: {'; '.join(md.limitations)}") |
| lines.append(f"- Disclaimer: {md.disclaimer}") |
| if md.verifier_notes: |
| lines.append("- Catatan verifier:") |
| for n in md.verifier_notes: |
| lines.append(f" - {n}") |
| else: |
| lines.append("- Catatan verifier: (tidak ada)") |
|
|
| return "\n".join(lines) |
|
|