| 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: |
| |
| 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", "") |
|
|
| |
| try: |
| mastery_score = int(mastery_score) |
| except (ValueError, TypeError): |
| mastery_score = 0 |
|
|
| |
| today = datetime.date.today() |
| year, week_num, _ = today.isocalendar() |
| week_id = f"week_{week_num:02d}_{year}" |
|
|
| |
| |
| doc_ref = db.collection("users").document(uid).collection("analytics").document(week_id) |
|
|
| |
| |
| skill_payload = { |
| "sum_scores": firestore.Increment(mastery_score), |
| "count": firestore.Increment(1) |
| } |
| if sub_skill: |
| skill_payload["sub_skills"] = firestore.ArrayUnion([sub_skill]) |
|
|
| |
| 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]) |
|
|
| |
| 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}") |
|
|
| |
| analytics_manager = AnalyticsManager() |
|
|