File size: 1,523 Bytes
e266561
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Helpers to load and persist the UserProfile from/to SQLite."""

from .db import get_profile, upsert_profile
from .models import UserProfile


def load_profile(session_id: str) -> UserProfile:
    """Fetch profile from DB, or create a fresh one if it doesn't exist."""
    row = get_profile(session_id)
    if row:
        return UserProfile(**row)
    return UserProfile(session_id=session_id)


def update_profile(profile: UserProfile, topic: str, gap_magnitude: int, solved: bool) -> UserProfile:
    """
    Update the profile in-memory after a reasoning evaluation:
      - Increment weak_topics score for the identified topic
      - Recalculate avg_gap with exponential moving average (alpha=0.3)
      - Increment turn count and solved count
    """
    topic_key = topic.strip().lower()
    profile.weak_topics[topic_key] = profile.weak_topics.get(topic_key, 0) + gap_magnitude

    # EMA for avg_gap
    alpha = 0.3
    profile.avg_gap = (alpha * gap_magnitude) + ((1 - alpha) * profile.avg_gap)

    profile.total_turns += 1
    if solved:
        profile.solved_problems += 1

    return profile


def persist_profile(profile: UserProfile) -> None:
    """Save the updated profile back to SQLite."""
    upsert_profile(profile.model_dump())


def top_weak_topics(profile: UserProfile, n: int = 3) -> list[str]:
    """Return the top-N weakest topics by cumulative score."""
    sorted_topics = sorted(profile.weak_topics.items(), key=lambda x: x[1], reverse=True)
    return [t[0] for t in sorted_topics[:n]]