BuddyMath / analytics.py
dotandru's picture
feat: AI Assessment Analytics Infrastructure
f7cf4db
Raw
History Blame Contribute Delete
2.74 kB
import datetime
import logging
from firebase_admin import firestore
from firebase_manager import firebase_manager
logger = logging.getLogger("HamoraServer")
class AnalyticsManager:
"""
Manages AI Assessment Telemetry and Weekly Reports.
"""
def _get_db(self):
return firebase_manager.get_db()
def update_weekly_analytics(self, uid: str, assessment: dict):
"""
Updates the weekly analytics document for a user using atomic operations.
Runs silently.
"""
if not uid or not assessment:
return
db = self._get_db()
if not db:
logger.error("❌ [ANALYTICS] Firestore DB not available.")
return
try:
# 1. Parse assessment data
primary_skill = assessment.get("primary_skill", "Unknown")
sub_skill = assessment.get("sub_skill", "")
mastery_score = assessment.get("mastery_score", 0)
parent_note = assessment.get("parent_note", "")
# Ensure score is an integer
try:
mastery_score = int(mastery_score)
except (ValueError, TypeError):
mastery_score = 0
# 2. Compute week_id (e.g., week_11_2026)
today = datetime.date.today()
year, week_num, _ = today.isocalendar()
week_id = f"week_{week_num:02d}_{year}"
# 3. Construct the document reference
# Path: users/{uid}/analytics/{week_id}
doc_ref = db.collection("users").document(uid).collection("analytics").document(week_id)
# 4. Construct payload with FieldValue operations for atomic updates
# Create the nested skill payload
skill_payload = {
"sum_scores": firestore.Increment(mastery_score),
"count": firestore.Increment(1)
}
if sub_skill:
skill_payload["sub_skills"] = firestore.ArrayUnion([sub_skill])
# Combine into final payload
payload = {
"total_exercises": firestore.Increment(1),
f"skills_data.{primary_skill}": skill_payload,
"last_updated": firestore.SERVER_TIMESTAMP
}
if parent_note:
payload["parent_notes"] = firestore.ArrayUnion([parent_note])
# 5. Set with merge=True
doc_ref.set(payload, merge=True)
logger.info(f"📊 [ANALYTICS] Successfully updated telemetry for {uid} in {week_id}.")
except Exception as e:
logger.error(f"❌ [ANALYTICS] Error updating analytics for {uid}: {e}")
# Global instance
analytics_manager = AnalyticsManager()