Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | import { NextResponse } from 'next/server' import { db } from '@/db' import { players } from '@/db/schema' import { withAuth } from '@/lib/auth/withAuth' import { computeBktFromHistory, DEFAULT_BKT_OPTIONS, type SkillBktResult, } from '@/lib/curriculum/bkt' import { BKT_THRESHOLDS } from '@/lib/curriculum/config/bkt-integration' import { getRecentSessionResults } from '@/lib/curriculum/session-planner' /** * GET /api/settings/bkt/aggregate * * Returns aggregate BKT stats across all students. * * Query params: * - threshold: confidence threshold (default from BKT_THRESHOLDS.confidence) */ export const GET = withAuth(async (request) => { try { const { searchParams } = new URL(request.url) const threshold = parseFloat(searchParams.get('threshold') ?? String(BKT_THRESHOLDS.confidence)) // Get all players const allPlayers = await db.select({ id: players.id }).from(players) if (allPlayers.length === 0) { return NextResponse.json({ totalStudents: 0, totalSkills: 0, weak: 0, developing: 0, strong: 0, // Legacy aliases for backwards compatibility struggling: 0, learning: 0, mastered: 0, }) } // Track aggregate counts let totalStudents = 0 let totalSkills = 0 let weak = 0 let developing = 0 let strong = 0 // Process each player for (const player of allPlayers) { // Fetch problem history using the session-planner's helper const problemHistory = await getRecentSessionResults(player.id, 500) if (problemHistory.length === 0) continue // Compute BKT const bktResult = computeBktFromHistory(problemHistory, { ...DEFAULT_BKT_OPTIONS, confidenceThreshold: threshold, }) // Count classifications totalStudents++ for (const skill of bktResult.skills) { totalSkills++ const classification = classifySkill(skill, threshold) if (classification === 'weak') weak++ else if (classification === 'developing') developing++ else if (classification === 'strong') strong++ } } return NextResponse.json({ totalStudents, totalSkills, weak, developing, strong, // Legacy aliases for backwards compatibility with BktSettingsClient struggling: weak, learning: developing, mastered: strong, }) } catch (error) { console.error('Error computing aggregate BKT stats:', error) return NextResponse.json({ error: 'Failed to compute stats' }, { status: 500 }) } }) function classifySkill(skill: SkillBktResult, threshold: number): 'weak' | 'developing' | 'strong' { if (skill.confidence < threshold) { return 'developing' // Not enough data - safest default } if (skill.pKnown >= BKT_THRESHOLDS.strong) { return 'strong' } if (skill.pKnown < BKT_THRESHOLDS.weak) { return 'weak' } return 'developing' } |