|
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
import os |
|
|
from typing import List, Dict |
|
|
|
|
|
import streamlit as st |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ensure_dirs(paths: List[str]) -> None: |
|
|
"""Ensure directories exist.""" |
|
|
for p in paths: |
|
|
os.makedirs(p, exist_ok=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def render_referral_tokens(tokens: List[Dict]) -> None: |
|
|
""" |
|
|
Render referral tokens as chips with section-level normalized weights. |
|
|
The highest-weight token = 1.0; others scale relative to it. |
|
|
Darker blue = stronger influence. |
|
|
""" |
|
|
if not tokens: |
|
|
st.write("_No referral tokens available._") |
|
|
return |
|
|
|
|
|
raw_weights = [float(t.get("weight", 0)) for t in tokens if t.get("weight") is not None] |
|
|
if not raw_weights: |
|
|
st.write("_No weights available._") |
|
|
return |
|
|
|
|
|
max_w = max(raw_weights) |
|
|
html_parts = [] |
|
|
for t in tokens: |
|
|
wn = round(float(t.get("weight", 0)) / max_w, 2) if max_w > 0 else 0.0 |
|
|
opacity = 0.35 + 0.65 * wn |
|
|
color = f"rgba(27,132,255,{opacity:.2f})" |
|
|
text_color = "#fff" if wn > 0.5 else "#f0f4ff" |
|
|
|
|
|
html_parts.append( |
|
|
f"<span style='display:inline-block;background:{color};" |
|
|
f"color:{text_color};padding:5px 10px;border-radius:14px;" |
|
|
f"margin:3px 6px 3px 0;font-size:0.9rem;white-space:nowrap;' " |
|
|
f"title='Weight: {t.get('weight', 0):.2f} (normalized {wn:.2f})'>" |
|
|
f"{t.get('token','')}</span>" |
|
|
) |
|
|
|
|
|
st.markdown("".join(html_parts), unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def render_guideline_refs(refs: List[Dict]) -> None: |
|
|
"""Render guideline reference list.""" |
|
|
if not refs: |
|
|
st.write("_No guideline references yet._") |
|
|
return |
|
|
|
|
|
for r in refs: |
|
|
doc = r.get("doc", "Guideline") |
|
|
page = r.get("page", "") |
|
|
excerpt = r.get("excerpt", "") |
|
|
st.markdown(f"π **{doc} p.{page}** β {excerpt}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rerun_guideline_refs_mock(text: str) -> List[Dict]: |
|
|
""" |
|
|
Mock retrieval of guideline references. Replace later with |
|
|
E5 embeddings + FAISS search for offline demos. |
|
|
""" |
|
|
text_l = text.lower() |
|
|
refs: List[Dict] = [] |
|
|
if "diure" in text_l or "furosemide" in text_l: |
|
|
refs.append({ |
|
|
"doc": "ESC 2021", |
|
|
"page": 12, |
|
|
"excerpt": "Increase loop diuretic dose or add thiazide-like agent if congestion persists." |
|
|
}) |
|
|
if "echo" in text_l or "echocard" in text_l: |
|
|
refs.append({ |
|
|
"doc": "ACC/AHA 2022", |
|
|
"page": 7, |
|
|
"excerpt": "Repeat echocardiography once euvolemic to avoid misclassification." |
|
|
}) |
|
|
if "sodium" in text_l or "weight" in text_l: |
|
|
refs.append({ |
|
|
"doc": "ACC/AHA 2022", |
|
|
"page": 5, |
|
|
"excerpt": "Educate on sodium restriction and daily weight monitoring." |
|
|
}) |
|
|
if not refs: |
|
|
refs = [{ |
|
|
"doc": "ACC/AHA 2022", |
|
|
"page": 7, |
|
|
"excerpt": "Elevated filling pressures should prompt decongestion and reassessment." |
|
|
}] |
|
|
return refs[:3] |
|
|
|