feat: complete pragativeer v2 frontend and backend, docker setup, and cbt engine

This commit is contained in:
2026-07-06 17:08:13 +05:30
parent ce01795aa9
commit 426b98ddab
66 changed files with 7949 additions and 363 deletions

63
backend/analytics.py Normal file
View 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")
}