use chrono::SecondsFormat; use crate::{models::TriageRecord, pipeline::orchestrator::TriageOutcome}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TriageViewModel { pub record_id: String, pub patient_id: String, pub reason: String, pub redacted_note: String, pub pii_map: Vec, pub triage_result: String, pub model_used: String, pub device_used: String, pub cid: String, pub transaction_hash: String, pub redaction_proof: crate::pipeline::proof::RedactionProof, pub consortium_attestations: Vec, pub enrichment: crate::models::MedicalEnrichment, pub degraded_reason: Option, pub created_at: String, } impl TriageViewModel { pub fn from_outcome(outcome: TriageOutcome) -> Self { let record = outcome.record; Self { record_id: record.record_id.as_str().to_string(), patient_id: record.patient_id.as_str().to_string(), reason: record.reason, redacted_note: record.redacted_note, pii_map: record.pii_map, triage_result: record.triage_result, model_used: record.model_used, device_used: record.device_used, cid: record.cid, transaction_hash: record.transaction_hash, redaction_proof: record.redaction_proof, consortium_attestations: record.consortium_attestations, enrichment: record.enrichment, degraded_reason: record.degraded_reason, created_at: record.created_at.to_rfc3339_opts(SecondsFormat::Secs, true), } } } pub fn render_dashboard_fragment(records: &[TriageRecord]) -> String { if records.is_empty() { return r#"
No triage history yet. Run a case and it appears here instantly.
"#.to_string(); } let rows = records.iter().rev().take(12).map(render_history_row).collect::(); format!(r#"
Live Memory

Recent triage decisions

{}
"#, rows) } fn render_history_row(record: &TriageRecord) -> String { format!(r#"
Record
{}
Patient
{}
Decision
{}
Audit
CID {}
"#, record.record_id.as_str(), escape_html(record.patient_id.as_str()), escape_html(&record.triage_result), escape_html(&record.cid)) } pub fn render_triage_fragment(vm: &TriageViewModel) -> String { let pii_rows = if vm.pii_map.is_empty() { "
  • No PHI patterns detected by the deterministic shield.
  • ".to_string() } else { vm.pii_map.iter().map(|item| { format!(r#"
  • {}{}
  • "#, escape_html(&item.original), escape_html(&item.placeholder)) }).collect::() }; let attestation_rows = vm.consortium_attestations.iter().map(|a| { format!(r#"
    {}
    {}
    {}
    "#, escape_html(&a.hospital), escape_html(&a.signature_status), escape_html(&a.attestation_hash)) }).collect::(); let pubmed_rows = if vm.enrichment.pubmed_hits.is_empty() { "
    No PubMed results matched this case.
    ".to_string() } else { vm.enrichment.pubmed_hits.iter().map(|hit| { format!(r#"
    PubMed {}
    {}
    "#, escape_html(&hit.url), escape_html(&hit.pmid), escape_html(&hit.title)) }).collect::() }; let degraded = vm.degraded_reason.as_ref().map(|reason| format!(r#"
    Backend degraded mode
    {}
    "#, escape_html(reason))).unwrap_or_default(); format!(r#"
    Triage Result

    Case {}

    {}
    {}
    Clinical synthesis

    {}

    Redacted note
    {}
    Redaction proof
    {}
    Verified: {}
    PII shield map
      {}
    Consortium attestations
    {}
    PubMed enrichment
    {}
    On-chain audit
    CID: {}
    Tx: {}
    Model: {} · {}
    Created: {}
    "#, escape_html(&vm.record_id), escape_html(&vm.reason), degraded, escape_html(&vm.triage_result), escape_html(&vm.redacted_note), escape_html(&vm.redaction_proof.proof), vm.redaction_proof.verified, pii_rows, attestation_rows, pubmed_rows, escape_html(&vm.cid), escape_html(&vm.transaction_hash), escape_html(&vm.model_used), escape_html(&vm.device_used), escape_html(&vm.created_at)) } pub fn render_dicom_fragment(result: &crate::pipeline::dicom::DicomRedactionResult) -> String { let fields = if result.report.detected_fields.is_empty() { "
  • No structured DICOM fields were parsed in this demo file.
  • ".to_string() } else { result.report.detected_fields.iter().map(|field| format!(r#"
  • {}
  • "#, escape_html(field))).collect::() }; format!(r#"
    DICOM Shield

    {}

    Parsed fields
      {}
    Burned-in OCR preview
    {}
    Redacted preview
    {}
    "#, escape_html(&result.report.filename), fields, escape_html(&result.report.burned_in_text_preview), escape_html(&result.report.redacted_preview)) } fn escape_html(input: &str) -> String { html_escape::encode_text(input).to_string() }