AIdea-Server / scripts /recalculate_analytics.py
Ahmed Mostafa
feat: add scripts to migrate and recalculate user analytics and update dependency lockfile
fbfd0f5
Raw
History Blame Contribute Delete
6.28 kB
import os
import sys
from pathlib import Path
from datetime import datetime, timezone, timedelta
# Add the server root to the Python path
server_root = Path(__file__).resolve().parent.parent
sys.path.append(str(server_root))
from firebase_admin import firestore
from src.db.firebase import get_firebase_db
from src.utils.logger import setup_logger
logger = setup_logger(__name__)
def recalculate_analytics():
"""
Recalculates all KPI fields for every user by iterating through their notes.
"""
db = get_firebase_db()
if not db:
logger.error("Database not initialized")
return
logger.info("Starting comprehensive analytics recalculation...")
users_ref = db.collection('users')
notes_ref = db.collection('notes')
analytics_ref = db.collection('analytics')
try:
users = users_ref.stream()
migrated_count = 0
now = datetime.now(timezone.utc)
week_ago = now - timedelta(days=7)
current_month = now.month
current_year = now.year
for user_doc in users:
user_id = user_doc.id
logger.info(f"Processing user: {user_id}")
# Fetch all notes for this user
user_notes = list(notes_ref.where('userId', '==', user_id).stream())
# --- Initialize KPI Counters ---
notes_count = len(user_notes)
category_count = {}
favorite_notes_count = 0
total_key_points = 0
total_video_duration_seconds = 0
this_week_videos = 0
this_month_saved_hours = 0.0
# For streak calculation
note_dates = set()
for note_doc in user_notes:
data = note_doc.to_dict()
# Categories
categories = []
if 'category' in data:
cat_data = data['category']
if isinstance(cat_data, list):
categories = cat_data
elif isinstance(cat_data, str):
categories = [cat_data]
elif 'video_categories' in data and isinstance(data['video_categories'], list):
categories = data['video_categories']
elif 'categories' in data and isinstance(data['categories'], list):
categories = data['categories']
if 'Uncategorized' in categories:
categories.remove('Uncategorized')
if not categories:
categories.append('Technology & AI')
for cat in categories:
category_count[cat] = category_count.get(cat, 0) + 1
# Favorites
if data.get('isFavorite', False):
favorite_notes_count += 1
# Key Points
key_points = data.get('keyPoints', [])
total_key_points += len(key_points)
# Duration
video_duration = data.get('videoDuration', data.get('video_duration', 0))
total_video_duration_seconds += video_duration
# Dates (for streak, weekly, monthly stats)
created_at = data.get('createdAt')
if created_at:
dt = created_at
# Some data might have python datetimes if created directly
if hasattr(created_at, 'timestamp'):
# Handle Google Cloud Timestamp vs Python datetime
dt_val = created_at
# Store date string for streak calculation (YYYY-MM-DD)
note_dates.add(dt.strftime('%Y-%m-%d'))
# This week videos
if dt >= week_ago:
this_week_videos += 1
# This month saved hours (assuming videoDuration is the saved time roughly)
if dt.month == current_month and dt.year == current_year:
this_month_saved_hours += video_duration / 3600.0
# --- Finalize Aggregations ---
total_minutes = total_video_duration_seconds // 60
total_saved_hours = total_video_duration_seconds / 3600.0
# Find favorite category
favorite_category = 'None'
if category_count:
favorite_category = max(category_count.items(), key=lambda x: x[1])[0]
# Calculate current streak
current_streak = 0
check_date = now.date()
# If they haven't posted today, check if they posted yesterday (streak is still alive)
if check_date.strftime('%Y-%m-%d') not in note_dates:
check_date = check_date - timedelta(days=1)
while check_date.strftime('%Y-%m-%d') in note_dates:
current_streak += 1
check_date -= timedelta(days=1)
# Update analytics document
analytics_data = {
'userId': user_id,
'notesCount': notes_count,
'categoryCount': category_count,
'favoriteCategory': favorite_category,
'favoriteNotesCount': favorite_notes_count,
'totalKeyPoints': total_key_points,
'totalMinutes': total_minutes,
'totalSavedHours': round(total_saved_hours, 2),
'thisWeekVideos': this_week_videos,
'thisMonthSavedHours': round(this_month_saved_hours, 2),
'currentStreak': current_streak,
'lastUpdated': firestore.SERVER_TIMESTAMP,
}
analytics_ref.document(user_id).set(analytics_data, merge=True)
logger.info(f"Updated analytics for {user_id}: {notes_count} notes, {current_streak} streak.")
migrated_count += 1
logger.info(f"Recalculation completed. Processed {migrated_count} users.")
except Exception as e:
logger.error(f"Error during recalculation: {e}", exc_info=True)
if __name__ == "__main__":
recalculate_analytics()