feat: complete pragativeer v2 frontend and backend, docker setup, and cbt engine
This commit is contained in:
63
backend/analytics.py
Normal file
63
backend/analytics.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from sqlmodel import Session, select
|
||||
from datetime import datetime, timedelta
|
||||
from collections import Counter
|
||||
from uuid import UUID
|
||||
import models
|
||||
|
||||
def generate_parent_report(student_id: UUID, session: Session) -> dict:
|
||||
"""
|
||||
Aggregates granular performance data for a specific student
|
||||
into a clean, simple, parent-friendly schema.
|
||||
"""
|
||||
# 1. Fetch Student Baseline Info
|
||||
student = session.get(models.User, student_id)
|
||||
if not student:
|
||||
return {"error": "Student record not found."}
|
||||
|
||||
# 2. Compile Last 7 Days Time & Attempts Data
|
||||
seven_days_ago = datetime.utcnow() - timedelta(days=7)
|
||||
attempts = session.exec(
|
||||
select(models.Attempt)
|
||||
.where(models.Attempt.user_id == student_id)
|
||||
.where(models.Attempt.submitted_at >= seven_days_ago)
|
||||
).all()
|
||||
|
||||
total_time_spent_seconds = sum((a.time_taken or 0) for a in attempts)
|
||||
total_time_spent_minutes = round(total_time_spent_seconds / 60, 1)
|
||||
|
||||
# 3. Calculate 7-Day Accuracy Trend Line Data
|
||||
# Group accuracy by date strings for simple frontend parsing
|
||||
trend_data = []
|
||||
for i in range(6, -1, -1):
|
||||
target_date = (datetime.utcnow() - timedelta(days=i)).date()
|
||||
daily_attempts = [a for a in attempts if a.submitted_at.date() == target_date]
|
||||
|
||||
if daily_attempts:
|
||||
avg_accuracy = sum(a.accuracy for a in daily_attempts) / len(daily_attempts)
|
||||
trend_data.append({"date": target_date.strftime("%b %d"), "accuracy": round(avg_accuracy, 1)})
|
||||
else:
|
||||
trend_data.append({"date": target_date.strftime("%b %d"), "accuracy": 0.0})
|
||||
|
||||
# 4. Extract Top "Areas of Concern" (Active un-mastered mistakes)
|
||||
active_mistakes = session.exec(
|
||||
select(models.Mistake)
|
||||
.where(models.Mistake.user_id == student_id)
|
||||
.where(models.Mistake.is_mastered == False)
|
||||
).all()
|
||||
|
||||
# Aggregate topic counts to find where they struggle most
|
||||
topic_counter = Counter([m.topic for m in active_mistakes])
|
||||
top_concerns = [
|
||||
{"topic": topic, "pending_errors": count}
|
||||
for topic, count in topic_counter.most_common(3)
|
||||
]
|
||||
|
||||
return {
|
||||
"student_name": student.name,
|
||||
"streak_count": student.streak_count,
|
||||
"weekly_minutes_spent": total_time_spent_minutes,
|
||||
"total_tests_attempted_this_week": len(attempts),
|
||||
"accuracy_trend": trend_data,
|
||||
"areas_of_concern": top_concerns,
|
||||
"last_active": student.last_active.strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
Reference in New Issue
Block a user