File size: 2,438 Bytes
2b21f2d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | """Renders a call's full transcript as attention-shaded HTML, driven by the per-turn
attention_weight values exported by src/evaluation/export_dashboard_data.py."""
import html
from theme import BORDER_HAIRLINE, TEXT_SECONDARY
SECTION_LABELS = {
"operator_transition": "Operator",
"prepared_remarks": "Prepared Remarks",
"qa": "Q&A",
}
def _intensity_color(weight: float, max_weight: float) -> str:
"""Accent-tinted background, opacity scaled by relative attention weight."""
if max_weight <= 0:
return "transparent"
frac = min(weight / max_weight, 1.0)
alpha = 0.05 + 0.30 * frac
r, g, b = 255, 87, 34
return f"rgba({r},{g},{b},{alpha:.3f})"
def render_full_transcript(turns: list[dict], selected_turn: int | None = None) -> str:
"""Full ordered transcript, grouped into sections, each turn background-shaded by
its own attention weight relative to the call's max.
`selected_turn`, when set, adds the `fl-timeline-selected` class to that turn's
block (used by the Workspace tab to sync highlighting with the Timeline/Evidence
panel)."""
if not turns:
return "<p>No transcript available.</p>"
max_w = max(t["attention_weight"] for t in turns)
blocks = []
current_section = None
for t in turns:
section = SECTION_LABELS.get(t["segment_type"], t["segment_type"])
if section != current_section:
blocks.append(f'<div class="fl-section-header">{html.escape(section)}</div>')
current_section = section
text = html.escape(t["text"])
speaker = html.escape(t.get("speaker_name") or t["speaker_role"])
bg = _intensity_color(t["attention_weight"], max_w)
selected_cls = " fl-timeline-selected" if t["turn_index"] == selected_turn else ""
xray_cls = " fl-xray-highlight" if t.get("is_risk_event") else ""
blocks.append(
f'<div class="fl-turn{selected_cls}{xray_cls}" id="turn-{t["turn_index"]}" data-turn-index="{t["turn_index"]}" '
f'style="background:{bg}; border-left-color:{TEXT_SECONDARY};">'
f'<div class="fl-turn-meta">{speaker} ({t["speaker_role"]})</div>'
f'<div class="fl-turn-text">{text}</div>'
f"</div>"
)
return (
f'<div style="border:1px solid {BORDER_HAIRLINE}; padding:12px; max-height:520px; overflow-y:auto;">'
+ "".join(blocks)
+ "</div>"
)
|