64 lines
2.4 KiB
Python
64 lines
2.4 KiB
Python
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")
|
|
}
|