Spaces:
Sleeping
Sleeping
File size: 3,509 Bytes
4ae4ae8 | 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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """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>
"""
|