Spaces:
Running on Zero
Running on Zero
Venkatesh Rajagopal
REFRAME: live CBT studio β fine-tuned Gemma 12B on Modal + Cohere voice (ZeroGPU)
4ae4ae8 | """Cross-card pattern analysis β distortion frequency, timing, themes.""" | |
| from __future__ import annotations | |
| from session import SessionState | |
| def analyze_patterns(state: SessionState) -> dict: | |
| """Analyze card deck for patterns. | |
| Returns dict with: | |
| - top_distortions: list of (name, count) sorted by frequency | |
| - total_cards: int | |
| - card_dates: list of dates | |
| - insight: str (generated summary) | |
| """ | |
| if not state.cards: | |
| return { | |
| "top_distortions": [], | |
| "total_cards": 0, | |
| "card_dates": [], | |
| "insight": "Complete your first thought record to start seeing patterns.", | |
| } | |
| top = sorted(state.distortion_counts.items(), key=lambda x: x[1], reverse=True) | |
| dates = [c.get("date", "") for c in state.cards] | |
| # Generate insight | |
| insight = _generate_insight(top, len(state.cards)) | |
| return { | |
| "top_distortions": top[:5], | |
| "total_cards": len(state.cards), | |
| "card_dates": dates, | |
| "insight": insight, | |
| } | |
| def _generate_insight(top_distortions: list[tuple[str, int]], total_cards: int) -> str: | |
| """Generate a human-readable insight from patterns.""" | |
| if not top_distortions: | |
| return "Keep going β patterns emerge after a few cards." | |
| top_name, top_count = top_distortions[0] | |
| if total_cards < 3: | |
| return f"Early pattern: {top_name} has come up {top_count} time(s). Let's see if it continues." | |
| pct = int((top_count / max(total_cards, 1)) * 100) | |
| return ( | |
| f"Your most common pattern is {top_name} " | |
| f"({top_count} times across {total_cards} cards β {pct}% of sessions). " | |
| f"Noticing it is the first step to changing it." | |
| ) | |
| def get_patterns_html(state: SessionState) -> str: | |
| """Render patterns as HTML for the progress panel.""" | |
| data = analyze_patterns(state) | |
| if not data["top_distortions"]: | |
| return """ | |
| <div style="color:#5a6a7a; font-size:0.85rem; text-align:center; padding:20px;"> | |
| <p>Complete thought records to reveal your thinking patterns.</p> | |
| </div> | |
| """ | |
| bars = "" | |
| max_count = data["top_distortions"][0][1] if data["top_distortions"] else 1 | |
| for name, count in data["top_distortions"]: | |
| width = int((count / max_count) * 100) | |
| bars += f""" | |
| <div style="display:flex; align-items:center; gap:8px; margin-bottom:8px;"> | |
| <span style="font-size:0.75rem; color:#8899aa; width:120px; flex-shrink:0;">{name}</span> | |
| <div style="flex:1; height:6px; background:rgba(255,255,255,0.08); border-radius:3px; overflow:hidden;"> | |
| <div style="height:100%; width:{width}%; background:linear-gradient(90deg,#8b5cf6,#a78bfa); border-radius:3px;"></div> | |
| </div> | |
| <span style="font-size:0.7rem; color:#5a6a7a; width:30px; text-align:right;">{count}x</span> | |
| </div> | |
| """ | |
| return f""" | |
| <div style="background:#1e2a3a; border-radius:12px; padding:16px; border:1px solid rgba(255,255,255,0.08);"> | |
| <h3 style="font-size:0.9rem; color:#e8edf3; margin-bottom:12px;">π Your Thinking Patterns</h3> | |
| <div>{bars}</div> | |
| <div style="margin-top:12px; font-size:0.8rem; color:#e8edf3; line-height:1.4; padding:10px; background:rgba(139,92,246,0.05); border-radius:8px;">π‘ {data['insight']}</div> | |
| <div style="margin-top:8px; font-size:0.7rem; color:#5a6a7a;">{data['total_cards']} cards completed</div> | |
| </div> | |
| """ | |