reframe / components /thought_card.py
Venkatesh Rajagopal
REFRAME: live CBT studio β€” fine-tuned Gemma 12B on Modal + Cohere voice (ZeroGPU)
4ae4ae8
Raw
History Blame Contribute Delete
7.16 kB
"""Render the live thought card as HTML."""
from __future__ import annotations
from card_engine import ActiveCard, CardState
def render_card(active: ActiveCard) -> str:
"""Render the thought card HTML based on current state."""
if active.state == CardState.IDLE:
return ""
card = active.card
sections = []
# Situation + Thought (always visible once triggered)
if active.state.value != "idle":
thought_text = card.automatic_thought or "..."
sections.append(f"""
<div style="margin-bottom:12px;">
<div style="font-size:0.7rem; font-weight:700; color:#5a6a7a; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">AUTOMATIC THOUGHT</div>
<div style="font-size:0.9rem; color:#e8edf3; line-height:1.4;">"{thought_text}"</div>
</div>
""")
# Distortion tags
if card.distortions:
tags = "".join(
f'<span style="display:inline-block; background:rgba(139,92,246,0.2); border:1px solid rgba(139,92,246,0.4); border-radius:20px; padding:4px 12px; font-size:0.75rem; color:#a78bfa; font-weight:500; margin-right:6px; margin-bottom:4px;">{d}</span>'
for d in card.distortions
)
sections.append(f"""
<div style="margin-bottom:12px; display:flex; flex-wrap:wrap; gap:6px;">
{tags}
</div>
""")
# Evidence FOR
if card.evidence_for:
items = "".join(f'<li style="font-size:0.85rem; color:#e8edf3; padding:4px 0 4px 12px; border-left:2px solid rgba(255,255,255,0.08); margin-bottom:4px;">{e}</li>' for e in card.evidence_for)
sections.append(f"""
<div style="margin-bottom:12px;">
<div style="font-size:0.7rem; font-weight:700; color:#5a6a7a; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">EVIDENCE FOR</div>
<ul style="list-style:none; padding:0; margin:0;">{items}</ul>
</div>
""")
# Evidence AGAINST
if card.evidence_against:
items = "".join(f'<li style="font-size:0.85rem; color:#e8edf3; padding:4px 0 4px 12px; border-left:2px solid rgba(255,255,255,0.08); margin-bottom:4px;">{e}</li>' for e in card.evidence_against)
sections.append(f"""
<div style="margin-bottom:12px;">
<div style="font-size:0.7rem; font-weight:700; color:#5a6a7a; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">EVIDENCE AGAINST</div>
<ul style="list-style:none; padding:0; margin:0;">{items}</ul>
</div>
""")
# Balanced thought (reframe)
if card.balanced_thought:
sections.append(f"""
<div style="margin-bottom:12px;">
<div style="font-size:0.7rem; font-weight:700; color:#5a6a7a; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">πŸ”„ BALANCED THOUGHT</div>
<div style="font-size:0.9rem; color:#22c55e; line-height:1.4; font-style:italic;">"{card.balanced_thought}"</div>
</div>
""")
# Complete state
border_style = "border-color:rgba(34,197,94,0.5); box-shadow:0 0 20px rgba(34,197,94,0.15);" if active.state == CardState.COMPLETE else ""
return f"""
<div style="background:#1e2a3a; border:1px solid rgba(255,255,255,0.08); border-radius:12px; padding:16px; {border_style}">
<div style="font-size:0.85rem; color:#8899aa; margin-bottom:12px; font-weight:600; letter-spacing:0.5px;">πŸ“‹ Live Thought Card</div>
{''.join(sections)}
</div>
"""
def render_empty_card() -> str:
"""Render a minimal waiting state after user starts chatting."""
return """
<div style="display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:120px; text-align:center; padding:24px 16px;">
<div style="font-size:0.82rem; color:#8899aa; line-height:1.5; max-width:260px;">
Listening... a thought card will appear here once a thinking pattern is detected.
</div>
</div>
"""
def render_intro_card() -> str:
"""Render the benefit-focused 'how it helps you' explanation for the How it works tab."""
return """
<div style="padding:14px;">
<div style="font-size:0.95rem; font-weight:700; color:#e8edf3; margin-bottom:10px;">A calmer way to untangle your thoughts</div>
<div style="font-size:0.8rem; color:#8899aa; line-height:1.6; margin-bottom:14px;">
When you're caught in a worry or a harsh thought, it's hard to see it clearly from the inside.
REFRAME is a gentle, judgment-free space to talk it through β€” and watch an unhelpful thought
become a fairer, kinder one.
</div>
<div style="font-size:0.75rem; color:#8899aa; line-height:1.5; margin-bottom:10px;">
<strong style="color:#e8edf3;">How it helps you:</strong>
</div>
<div style="margin-bottom:8px; padding-left:8px; border-left:2px solid rgba(139,92,246,0.3);">
<div style="font-size:0.73rem; color:#a78bfa; font-weight:600;">See the thinking trap</div>
<div style="font-size:0.7rem; color:#8899aa;">It gently names patterns like catastrophizing or all-or-nothing thinking β€” the ones that are hard to spot in your own head.</div>
</div>
<div style="margin-bottom:8px; padding-left:8px; border-left:2px solid rgba(139,92,246,0.3);">
<div style="font-size:0.73rem; color:#a78bfa; font-weight:600;">Questions, not lectures</div>
<div style="font-size:0.7rem; color:#8899aa;">Rather than telling you what to think, it asks β€” what supports this thought, and what doesn't? You stay in control.</div>
</div>
<div style="margin-bottom:8px; padding-left:8px; border-left:2px solid rgba(139,92,246,0.3);">
<div style="font-size:0.73rem; color:#a78bfa; font-weight:600;">Reframes you actually believe</div>
<div style="font-size:0.7rem; color:#8899aa;">The balanced thought is yours, in your own words β€” which is exactly why it sticks with you.</div>
</div>
<div style="margin-bottom:8px; padding-left:8px; border-left:2px solid rgba(34,197,94,0.3);">
<div style="font-size:0.73rem; color:#22c55e; font-weight:600;">See yourself grow</div>
<div style="font-size:0.7rem; color:#8899aa;">Saved cards and your pattern tracker reveal what keeps coming up β€” and noticing is where change begins.</div>
</div>
<div style="margin-top:12px; padding:8px; background:rgba(139,92,246,0.05); border-radius:8px; font-size:0.7rem; color:#8899aa; line-height:1.5;">
πŸ’¬ Just talk β€” by voice or text. No jargon, no pressure. It's grounded in
<strong style="color:#a78bfa;">Cognitive Behavioral Therapy (CBT)</strong>, the most
evidence-based approach for reshaping unhelpful thinking.
</div>
<div style="margin-top:10px; font-size:0.66rem; color:#5a6a7a; line-height:1.5;">
A supportive companion β€” not a replacement for professional care. If you're ever in crisis,
it will surface helplines right away.
</div>
</div>
"""