disclosure (no JS) so a physician can audit the label without
it crowding the card by default.
"""
rationale = ev.get("rationale") or []
if not rationale:
return ""
rows = "".join(
f''
f'+{f["points"]} {html.escape(f["factor"])} — {html.escape(f["detail"])}'
for f in rationale
)
total = ev.get("points", sum(f["points"] for f in rationale))
summary = (f'Why {html.escape(ev.get("tier", ""))}? ({total} pts — '
"≥4 Strong · 2–3 Moderate · <2 Emerging)")
return (
''
f'{summary}
'
f''
' '
)
def _pmid_cite(pmid: str) -> str:
"""Small ' [PMID 123]' PubMed link, or '' when there's no citation."""
pmid = (pmid or "").strip()
if not pmid:
return ""
return (f' [PMID {html.escape(pmid)}]')
def _mechanism_summary_html(summary: dict) -> str:
"""Collapsible 'Mechanism summary' block: compound, target, animal results, repurposed-from.
RAG-grounded (offline step 5.5). Each field shows its supporting PMID when the claim came
from the corpus; missing/unsupported fields read "Unknown", per the grounding guardrail.
"""
if not summary:
return ""
def _val(text: str) -> str:
text = (text or "unknown").strip()
style = "color:#aaa;" if text.lower() in ("unknown", "not repurposed") else ""
return f'{html.escape(text)}'
rows = [
("Compound", _val(summary.get("compound", "unknown")), ""),
("Targeting mechanism", _val(summary.get("targeting_mechanism", "unknown")),
summary.get("targeting_mechanism_pmid", "")),
("Animal / preclinical results", _val(summary.get("animal_results", "unknown")),
summary.get("animal_results_pmid", "")),
("Repurposed from", _val(summary.get("repurposed_from", "unknown")),
summary.get("repurposed_from_pmid", "")),
]
items = "".join(
f'{label}: {value}{_pmid_cite(pmid)}'
for label, value, pmid in rows
)
return (
''
'Mechanism summary
'
f''
' '
)
def _eligibility_html(elig: dict) -> str:
"""Collapsible enrollment-criteria block: age/sex summary + inclusion/exclusion text.
Rendered only for active/recruiting trials (the caller gates on status), since that's when
a physician assesses whether a patient qualifies.
"""
criteria = (elig.get("criteria") or "").strip()
if not criteria:
return ""
bits = []
age = " – ".join(x for x in (elig.get("min_age"), elig.get("max_age")) if x) or None
if age:
bits.append(f"Age {html.escape(age)}")
sex = elig.get("sex")
if sex and sex != "ALL":
bits.append(html.escape(sex.title()))
elif sex == "ALL":
bits.append("All sexes")
if elig.get("healthy_volunteers"):
bits.append("Accepts healthy volunteers")
summary = "Eligibility" + (f" · {' · '.join(bits)}" if bits else "")
body = html.escape(criteria).replace("\n", "
")
return (
''
f'{summary}
'
f'{body}
'
' '
)
def render_trials_html(enriched: list[dict], match_count: int) -> str:
"""Render enriched location-search results as an HTML card list."""
if not enriched:
return 'No trials found for this location.
'
caption = (f''
f'{match_count} trial(s) matched — showing {len(enriched)}, recruiting first.
')
cards = []
for t in enriched:
s_color, s_label = _status_badge(t["status"])
ev = t["evidence"]
tier_pill = _pill(f'Evidence: {ev["tier"]}', _TIER_COLOR.get(ev["tier"], "#B2BEC3"))
mech = t.get("mechanism", "")
mech_pill = _pill(f'Mechanism: {mech}', "#6C5CE7") if mech else ""
rationale_html = _tier_rationale_html(ev)
mech_summary_html = _mechanism_summary_html(t.get("mechanism_summary", {}))
# Enrollment criteria only for active/recruiting trials — the enrollable ones.
elig_html = _eligibility_html(t.get("eligibility", {})) if t.get("is_recruiting") else ""
phase = html.escape((t.get("phase") or "—").replace("PHASE", "Ph"))
title = html.escape(t.get("title", "")[:140])
nct = html.escape(t.get("nct_id", ""))
url = html.escape(t.get("url", ""))
nct_link = f'{nct}' if url else nct
sites = t.get("matched_sites", [])
site_bits = []
for st in sites[:3]:
loc = ", ".join(x for x in (st.get("facility", ""), st.get("city", ""), st.get("state", "")) if x)
if loc:
site_bits.append(html.escape(loc))
sites_html = "
".join(site_bits)
if len(sites) > 3:
sites_html += f'
+{len(sites) - 3} more site(s)'
papers = t.get("key_papers", [])
if papers:
paper_items = "".join(
f'{html.escape(p.get("title", "")[:120])} '
f'({p.get("year") or "n.d."}) — '
f'PMID {html.escape(str(p.get("pmid", "")))}, '
f'{p.get("citation_count", 0)} citations'
for p in papers
)
papers_html = f''
else:
papers_html = 'No supporting papers found in the database.
'
siblings = t.get("sibling_trials", [])
if siblings:
sib_links = ", ".join(
f'{html.escape(s.get("nct_id", ""))}'
for s in siblings
)
siblings_html = f'Related trials (same compound): {sib_links}
'
else:
siblings_html = ""
cards.append(
''
f'
'
f'{_pill(s_label, s_color)}{tier_pill}{mech_pill}'
f'{phase}
'
f'
{nct_link} — {title}
'
f'{rationale_html}{mech_summary_html}'
f'
Site(s):
{sites_html}
'
f'{elig_html}{papers_html}{siblings_html}'
'
'
)
return caption + "".join(cards)