@studious-lms/server 1.26.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -1
- package/.github/workflows/npm-publish.yml +1 -0
- package/AGENTS.md +84 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -4
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +9 -4
- package/dist/instrument.js.map +1 -1
- package/dist/lib/fileUpload.d.ts +15 -0
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +43 -2
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +11 -0
- package/dist/models/cloudStorage.d.ts.map +1 -1
- package/dist/models/cloudStorage.js +18 -2
- package/dist/models/cloudStorage.js.map +1 -1
- package/dist/models/conversation.d.ts +1 -0
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +40 -0
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/labChat.js +32 -2
- package/dist/models/labChat.js.map +1 -1
- package/dist/models/message.d.ts +3 -0
- package/dist/models/message.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts +2 -0
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +60 -16
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +170 -2
- package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.js +30 -2
- package/dist/pipelines/aiLabChatContract.js.map +1 -1
- package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
- package/dist/pipelines/aiNewtonChat.js +30 -5
- package/dist/pipelines/aiNewtonChat.js.map +1 -1
- package/dist/pipelines/generateVisualization.d.ts +33 -0
- package/dist/pipelines/generateVisualization.d.ts.map +1 -0
- package/dist/pipelines/generateVisualization.js +79 -0
- package/dist/pipelines/generateVisualization.js.map +1 -0
- package/dist/pipelines/labChatPrompt.d.ts +1 -1
- package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
- package/dist/pipelines/labChatPrompt.js +13 -14
- package/dist/pipelines/labChatPrompt.js.map +1 -1
- package/dist/routers/_app.d.ts +1118 -70
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/admin.d.ts +297 -1
- package/dist/routers/admin.d.ts.map +1 -1
- package/dist/routers/admin.js +43 -2
- package/dist/routers/admin.js.map +1 -1
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +16 -3
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/conversation.d.ts +1 -0
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/labChat.d.ts +10 -0
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/labChat.js +6 -3
- package/dist/routers/labChat.js.map +1 -1
- package/dist/routers/message.d.ts +37 -4
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/message.js +24 -7
- package/dist/routers/message.js.map +1 -1
- package/dist/routers/module.d.ts +1 -1
- package/dist/routers/parent.d.ts +18 -0
- package/dist/routers/parent.d.ts.map +1 -1
- package/dist/routers/parent.js +10 -3
- package/dist/routers/parent.js.map +1 -1
- package/dist/routers/studentProgress.d.ts +44 -0
- package/dist/routers/studentProgress.d.ts.map +1 -1
- package/dist/routers/studentProgress.js +12 -3
- package/dist/routers/studentProgress.js.map +1 -1
- package/dist/routers/visualization.d.ts +124 -0
- package/dist/routers/visualization.d.ts.map +1 -0
- package/dist/routers/visualization.js +41 -0
- package/dist/routers/visualization.js.map +1 -0
- package/dist/routes/aiStream.js +32 -2
- package/dist/routes/aiStream.js.map +1 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/seedDatabase.js +107 -3
- package/dist/seedDatabase.js.map +1 -1
- package/dist/services/adminClass.d.ts +153 -0
- package/dist/services/adminClass.d.ts.map +1 -0
- package/dist/services/adminClass.js +196 -0
- package/dist/services/adminClass.js.map +1 -0
- package/dist/services/adminInstitution.d.ts +2 -0
- package/dist/services/adminInstitution.d.ts.map +1 -1
- package/dist/services/adminInstitution.js +11 -4
- package/dist/services/adminInstitution.js.map +1 -1
- package/dist/services/adminMetrics.d.ts +8 -0
- package/dist/services/adminMetrics.d.ts.map +1 -1
- package/dist/services/adminMetrics.js +30 -3
- package/dist/services/adminMetrics.js.map +1 -1
- package/dist/services/adminSpam.d.ts +76 -0
- package/dist/services/adminSpam.d.ts.map +1 -0
- package/dist/services/adminSpam.js +163 -0
- package/dist/services/adminSpam.js.map +1 -0
- package/dist/services/adminSql.d.ts +36 -0
- package/dist/services/adminSql.d.ts.map +1 -0
- package/dist/services/adminSql.js +172 -0
- package/dist/services/adminSql.js.map +1 -0
- package/dist/services/adminTelemetry.d.ts +56 -0
- package/dist/services/adminTelemetry.d.ts.map +1 -0
- package/dist/services/adminTelemetry.js +147 -0
- package/dist/services/adminTelemetry.js.map +1 -0
- package/dist/services/adminUser.d.ts +45 -1
- package/dist/services/adminUser.d.ts.map +1 -1
- package/dist/services/adminUser.js +53 -13
- package/dist/services/adminUser.js.map +1 -1
- package/dist/services/aiChatStream.d.ts +15 -0
- package/dist/services/aiChatStream.d.ts.map +1 -1
- package/dist/services/aiChatStream.js +144 -74
- package/dist/services/aiChatStream.js.map +1 -1
- package/dist/services/aiGeneration.d.ts +4 -0
- package/dist/services/aiGeneration.d.ts.map +1 -0
- package/dist/services/aiGeneration.js +88 -0
- package/dist/services/aiGeneration.js.map +1 -0
- package/dist/services/aiProposalTools.d.ts +4 -1
- package/dist/services/aiProposalTools.d.ts.map +1 -1
- package/dist/services/aiProposalTools.js +128 -3
- package/dist/services/aiProposalTools.js.map +1 -1
- package/dist/services/aiProposals.d.ts +70 -0
- package/dist/services/aiProposals.d.ts.map +1 -0
- package/dist/services/aiProposals.js +363 -0
- package/dist/services/aiProposals.js.map +1 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +10 -4
- package/dist/services/auth.js.map +1 -1
- package/dist/services/conversation.d.ts +1 -0
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/fees.d.ts.map +1 -1
- package/dist/services/fees.js +7 -3
- package/dist/services/fees.js.map +1 -1
- package/dist/services/labChat.d.ts +10 -0
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +52 -3
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts +24 -8
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +170 -117
- package/dist/services/message.js.map +1 -1
- package/dist/services/module.d.ts.map +1 -1
- package/dist/services/module.js +23 -4
- package/dist/services/module.js.map +1 -1
- package/dist/services/parentPortal.d.ts +14 -0
- package/dist/services/parentPortal.d.ts.map +1 -1
- package/dist/services/parentPortal.js +72 -2
- package/dist/services/parentPortal.js.map +1 -1
- package/dist/services/studentProgress.d.ts +50 -0
- package/dist/services/studentProgress.d.ts.map +1 -1
- package/dist/services/studentProgress.js +107 -2
- package/dist/services/studentProgress.js.map +1 -1
- package/dist/services/visualization.d.ts +72 -0
- package/dist/services/visualization.d.ts.map +1 -0
- package/dist/services/visualization.js +122 -0
- package/dist/services/visualization.js.map +1 -0
- package/dist/utils/inference.d.ts +10 -0
- package/dist/utils/inference.d.ts.map +1 -1
- package/dist/utils/inference.js +77 -2
- package/dist/utils/inference.js.map +1 -1
- package/dist/utils/sentryTrpc.d.ts +3 -0
- package/dist/utils/sentryTrpc.d.ts.map +1 -0
- package/dist/utils/sentryTrpc.js +26 -0
- package/dist/utils/sentryTrpc.js.map +1 -0
- package/dist/workers/processors/createRunJobWorker.js +17 -16
- package/dist/workers/processors/createRunJobWorker.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260811130000_add_ai_message_feedback/migration.sql +7 -0
- package/prisma/migrations/20261025120000_add_visualizations/migration.sql +27 -0
- package/prisma/schema.prisma +32 -0
- package/src/index.ts +30 -4
- package/src/instrument.ts +8 -2
- package/src/lib/fileUpload.ts +49 -0
- package/src/models/cloudStorage.ts +19 -0
- package/src/models/labChat.ts +34 -0
- package/src/pipelines/aiLabChat.ts +79 -18
- package/src/pipelines/aiLabChatContract.ts +35 -0
- package/src/pipelines/aiNewtonChat.ts +34 -2
- package/src/pipelines/generateVisualization.ts +107 -0
- package/src/pipelines/labChatPrompt.ts +11 -12
- package/src/routers/_app.ts +2 -0
- package/src/routers/admin.ts +72 -0
- package/src/routers/class.ts +14 -1
- package/src/routers/labChat.ts +5 -0
- package/src/routers/message.ts +34 -5
- package/src/routers/parent.ts +11 -0
- package/src/routers/studentProgress.ts +15 -0
- package/src/routers/visualization.ts +60 -0
- package/src/routes/aiStream.ts +32 -0
- package/src/seedDatabase.ts +107 -2
- package/src/services/adminClass.ts +222 -0
- package/src/services/adminInstitution.ts +9 -2
- package/src/services/adminMetrics.ts +35 -0
- package/src/services/adminSpam.ts +224 -0
- package/src/services/adminSql.ts +214 -0
- package/src/services/adminTelemetry.ts +194 -0
- package/src/services/adminUser.ts +66 -11
- package/src/services/aiChatStream.ts +83 -7
- package/src/services/aiGeneration.ts +92 -0
- package/src/services/aiProposalTools.ts +166 -1
- package/src/services/aiProposals.ts +428 -0
- package/src/services/auth.ts +8 -2
- package/src/services/fees.ts +5 -1
- package/src/services/labChat.ts +65 -0
- package/src/services/message.ts +205 -142
- package/src/services/module.ts +29 -2
- package/src/services/parentPortal.ts +85 -0
- package/src/services/studentProgress.ts +135 -0
- package/src/services/visualization.ts +147 -0
- package/src/utils/inference.ts +85 -0
- package/src/utils/sentryTrpc.ts +25 -0
- package/src/workers/processors/createRunJobWorker.ts +17 -17
- package/tests/unit/lib/fileUploadSession.test.ts +67 -0
- package/tests/unit/services/adminClass.test.ts +102 -0
- package/tests/unit/services/adminSpam.test.ts +108 -0
- package/tests/unit/services/adminSql.test.ts +56 -0
- package/tests/unit/services/adminTelemetry.test.ts +47 -0
- package/tests/unit/services/adminUser.test.ts +77 -0
- package/tests/unit/services/visualization.test.ts +130 -0
- package/tests/unit/utils/adminPanelAccess.test.ts +26 -0
- package/tests/unit/utils/sentryTrpc.test.ts +15 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"studentProgress.js","sources":["services/studentProgress.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Student progress service - assignment recommendations and progress chat.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport type { AssignmentType } from \"@prisma/client\";\nimport { z } from \"zod\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { isTeacherInClass } from \"../models/class.js\";\nimport { inference } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n getStudentProgressInferenceCacheHit,\n setStudentProgressInferenceCache,\n} from \"./studentProgressInferenceCache.js\";\n\ntype ProgressChatMessage = {\n role: \"user\" | \"assistant\";\n content: string;\n};\n\ntype GradeSubmission = {\n id: string;\n gradeReceived: number | null;\n submitted: boolean | null;\n returned: boolean | null;\n submittedAt: Date | null;\n recommendationState: \"NONE\" | \"OPEN\" | \"ASSIGNED\" | \"DISMISSED\";\n targetedAssignmentId: string | null;\n assignment: {\n id: string;\n title: string;\n dueDate: Date;\n maxGrade: number | null;\n weight: number;\n type: AssignmentType;\n section: { id: string; name: string } | null;\n };\n};\n\ntype ProgressStudent = {\n id: string;\n username: string;\n profile: { displayName: string | null } | null;\n};\n\nconst insightItemSchema = z.object({\n label: z.string(),\n evidence: z.string(),\n});\n\nconst studentProgressInsightsSchema = z.object({\n summary: z.string(),\n strengths: z.array(insightItemSchema).min(2).max(4),\n growth: z.array(insightItemSchema).min(2).max(4),\n talkingPoints: z.array(z.string()).min(3).max(5),\n});\n\nconst studentProgressForecastSchema = z.object({\n forecastLow: z.number().min(0).max(100),\n forecastHigh: z.number().min(0).max(100),\n risk: z.enum([\"on_track\", \"watch\", \"at_risk\"]),\n reason: z.string(),\n});\n\nconst studentProgressFocusSchema = z.object({\n focusItems: z.array(z.string()).min(3).max(5),\n});\n\nexport type StudentProgressInsights = z.infer<\n typeof studentProgressInsightsSchema\n>;\nexport type StudentProgressForecast = z.infer<\n typeof studentProgressForecastSchema\n>;\nexport type StudentProgressFocus = z.infer<typeof studentProgressFocusSchema>;\n\ntype RecommendationType = \"missing\" | \"low_score\" | \"awaiting_feedback\";\n\nfunction calculatePercentage(submission: GradeSubmission) {\n if (submission.gradeReceived == null || !submission.assignment.maxGrade) {\n return null;\n }\n\n return (\n Math.round(\n (submission.gradeReceived / submission.assignment.maxGrade) * 1000,\n ) / 10\n );\n}\n\nfunction calculateTrend(submissions: GradeSubmission[]) {\n const graded = submissions\n .filter(\n (submission) =>\n submission.gradeReceived != null && submission.assignment.maxGrade,\n )\n .sort((a, b) => {\n const aTime = a.submittedAt?.getTime() ?? a.assignment.dueDate.getTime();\n const bTime = b.submittedAt?.getTime() ?? b.assignment.dueDate.getTime();\n return aTime - bTime;\n })\n .map((submission) => calculatePercentage(submission))\n .filter((value): value is number => value != null);\n\n if (graded.length < 2) return 0;\n\n const midpoint = Math.floor(graded.length / 2);\n const first = graded.slice(0, midpoint);\n const second = graded.slice(midpoint);\n const average = (values: number[]) =>\n values.reduce((sum, value) => sum + value, 0) / values.length;\n\n return Math.round((average(second) - average(first)) * 10) / 10;\n}\n\nfunction getOverallGrade(submissions: GradeSubmission[]) {\n let totalWeighted = 0;\n let totalWeight = 0;\n\n for (const submission of submissions) {\n if (\n submission.gradeReceived != null &&\n submission.assignment.maxGrade &&\n submission.assignment.weight\n ) {\n totalWeighted +=\n (submission.gradeReceived / submission.assignment.maxGrade) *\n submission.assignment.weight;\n totalWeight += submission.assignment.weight;\n }\n }\n\n return totalWeight > 0\n ? Math.round((totalWeighted / totalWeight) * 1000) / 10\n : null;\n}\n\nfunction normalizeAssignmentType(\n assignmentType: AssignmentType,\n): AssignmentType {\n if (assignmentType === \"TEST\" || assignmentType === \"QUIZ\") {\n return \"HOMEWORK\";\n }\n\n return assignmentType;\n}\n\nfunction buildSuggestedAssignment(\n recommendationType: RecommendationType,\n submission: GradeSubmission,\n displayName: string,\n percentage: number | null,\n) {\n const sourceTitle = submission.assignment.title;\n const section = submission.assignment.section?.name;\n const titleByType: Record<RecommendationType, string> = {\n missing: `Make-up: ${sourceTitle}`,\n low_score: `Targeted practice: ${sourceTitle}`,\n awaiting_feedback: `Revision follow-up: ${sourceTitle}`,\n };\n const leadByType: Record<RecommendationType, string> = {\n missing: `${displayName} missed the original assignment and needs a focused make-up task on the same material.`,\n low_score:\n percentage != null\n ? `${displayName} scored ${percentage}% and needs targeted reinforcement on the underlying concepts.`\n : `${displayName} needs targeted reinforcement on the underlying concepts.`,\n awaiting_feedback: `${displayName} has work in progress here, so a short follow-up can keep momentum once feedback lands.`,\n };\n\n return {\n title: titleByType[recommendationType],\n instructions: [\n leadByType[recommendationType],\n `Source assignment: ${sourceTitle}.`,\n section ? `Section: ${section}.` : null,\n \"Keep the work concise and focused on the specific area of concern.\",\n ]\n .filter((line): line is string => Boolean(line))\n .join(\"\\n\\n\"),\n type: normalizeAssignmentType(submission.assignment.type),\n maxGrade: submission.assignment.maxGrade ?? 100,\n weight: submission.assignment.weight || 1,\n graded: true,\n sectionId: submission.assignment.section?.id ?? null,\n sourceAssignmentId: submission.assignment.id,\n };\n}\n\nfunction buildRecommendationCandidate(\n submission: GradeSubmission,\n displayName: string,\n now: Date,\n) {\n if (\n submission.recommendationState === \"ASSIGNED\" ||\n submission.recommendationState === \"DISMISSED\"\n ) {\n return null;\n }\n\n const percentage = calculatePercentage(submission);\n const isMissing =\n !submission.submitted &&\n submission.assignment.dueDate.getTime() < now.getTime();\n const isLowScore = percentage != null && percentage < 70;\n const isUnreturned =\n Boolean(submission.submitted) &&\n submission.gradeReceived == null &&\n !submission.returned;\n const reasons: string[] = [];\n let priorityScore = 0;\n let recommendationType: RecommendationType | null = null;\n\n if (isMissing) {\n reasons.push(\"Missing past-due work\");\n priorityScore += 100;\n recommendationType = \"missing\";\n }\n if (isLowScore) {\n reasons.push(`Scored ${percentage}%`);\n priorityScore += 85 - (percentage ?? 0);\n recommendationType ??= \"low_score\";\n }\n if (isUnreturned) {\n reasons.push(\"Awaiting grade or feedback\");\n priorityScore += 15;\n recommendationType ??= \"awaiting_feedback\";\n }\n\n if (priorityScore <= 0 || !recommendationType) {\n return null;\n }\n\n return {\n assignmentId: submission.assignment.id,\n submissionId: submission.id,\n title: submission.assignment.title,\n type: submission.assignment.type,\n sectionId: submission.assignment.section?.id ?? null,\n sectionName: submission.assignment.section?.name ?? null,\n dueDate: submission.assignment.dueDate,\n gradeReceived: submission.gradeReceived,\n maxGrade: submission.assignment.maxGrade,\n percentage,\n submitted: Boolean(submission.submitted),\n returned: Boolean(submission.returned),\n recommendationType,\n reasons,\n priorityScore,\n suggestedAssignment: buildSuggestedAssignment(\n recommendationType,\n submission,\n displayName,\n percentage,\n ),\n };\n}\n\nfunction summarizeStudentRecommendations(\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const now = new Date();\n const displayName = student.profile?.displayName ?? student.username;\n const recommendationCandidates = submissions\n .map((submission) =>\n buildRecommendationCandidate(submission, displayName, now),\n )\n .filter(\n (\n candidate,\n ): candidate is NonNullable<\n ReturnType<typeof buildRecommendationCandidate>\n > => candidate != null,\n )\n .sort((a, b) => b.priorityScore - a.priorityScore);\n\n const recommendations = recommendationCandidates\n .slice(0, 5)\n .map(({ priorityScore, ...candidate }) => candidate);\n\n const gradedPercentages = submissions\n .map(calculatePercentage)\n .filter((value): value is number => value != null);\n const lowScoreCount = gradedPercentages.filter(\n (percentage) => percentage < 70,\n ).length;\n const missingCount = submissions.filter(\n (submission) =>\n !submission.submitted &&\n submission.assignment.dueDate.getTime() < now.getTime(),\n ).length;\n const trend = calculateTrend(submissions);\n const overallGrade = getOverallGrade(submissions);\n\n const nextSteps = [\n missingCount > 0\n ? `Prioritize ${missingCount} missing assignment${missingCount === 1 ? \"\" : \"s\"}.`\n : null,\n lowScoreCount > 0\n ? `Review ${lowScoreCount} low-scoring assignment${lowScoreCount === 1 ? \"\" : \"s\"} before introducing new material.`\n : null,\n trend < -5\n ? \"Schedule a check-in because recent performance is trending down.\"\n : null,\n recommendationCandidates.length === 0\n ? \"No urgent assignment issues detected from the available grades.\"\n : null,\n ].filter((step): step is string => Boolean(step));\n\n return {\n student: {\n id: student.id,\n username: student.username,\n displayName,\n },\n summary: {\n overallGrade,\n trend,\n completedAssignments: submissions.filter((submission) =>\n Boolean(submission.submitted),\n ).length,\n totalAssignments: submissions.length,\n missingCount,\n lowScoreCount,\n },\n recommendations,\n recommendationCandidates,\n nextSteps,\n priorityScore: recommendationCandidates[0]?.priorityScore ?? 0,\n };\n}\n\nasync function syncRecommendationStates(\n submissions: GradeSubmission[],\n recommendationCandidates: Array<\n NonNullable<ReturnType<typeof buildRecommendationCandidate>>\n >,\n) {\n const candidateSubmissionIds = new Set(\n recommendationCandidates.map((candidate) => candidate.submissionId),\n );\n const updates: Promise<unknown>[] = [];\n\n for (const submission of submissions) {\n const shouldBeOpen = candidateSubmissionIds.has(submission.id);\n\n if (shouldBeOpen && submission.recommendationState === \"NONE\") {\n updates.push(\n prisma.submission.update({\n where: { id: submission.id },\n data: {\n recommendationState: \"OPEN\",\n recommendationUpdatedAt: new Date(),\n },\n }),\n );\n continue;\n }\n\n if (!shouldBeOpen && submission.recommendationState === \"OPEN\") {\n updates.push(\n prisma.submission.update({\n where: { id: submission.id },\n data: {\n recommendationState: \"NONE\",\n recommendationUpdatedAt: new Date(),\n },\n }),\n );\n }\n }\n\n if (updates.length) {\n await Promise.all(updates);\n }\n}\n\nasync function summarizeStudentRecommendationsWithCases(\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const summary = summarizeStudentRecommendations(student, submissions);\n await syncRecommendationStates(submissions, summary.recommendationCandidates);\n return summary;\n}\n\nasync function loadStudentProgressContext(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const isTeacher = await isTeacherInClass(classId, viewerId);\n if (viewerId !== studentId && !isTeacher) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You can only view your own progress\",\n });\n }\n\n const [classData, student, submissions] = await Promise.all([\n prisma.class.findUnique({\n where: { id: classId },\n select: { id: true, name: true, subject: true },\n }),\n prisma.user.findFirst({\n where: {\n id: studentId,\n studentIn: { some: { id: classId } },\n },\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true } },\n },\n }),\n prisma.submission.findMany({\n where: {\n studentId,\n assignment: { classId, graded: true },\n },\n include: {\n assignment: {\n select: {\n id: true,\n title: true,\n dueDate: true,\n maxGrade: true,\n weight: true,\n type: true,\n section: { select: { id: true, name: true } },\n },\n },\n },\n orderBy: { assignment: { dueDate: \"asc\" } },\n }),\n ]);\n\n if (!classData) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n if (!student) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Student not found in this class\",\n });\n }\n\n return { classData, student, submissions };\n}\n\nexport async function getStudentProgressRecommendations(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const { student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n const summary = await summarizeStudentRecommendationsWithCases(\n student,\n submissions,\n );\n const {\n recommendationCandidates: _recommendationCandidates,\n ...summaryResponse\n } = summary;\n return {\n student: summaryResponse.student,\n summary: summaryResponse.summary,\n recommendations: summaryResponse.recommendations,\n nextSteps: summaryResponse.nextSteps,\n };\n}\n\nexport async function getClassProgressRecommendations(\n viewerId: string,\n classId: string,\n) {\n const teacherInClass = await isTeacherInClass(classId, viewerId);\n if (!teacherInClass) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Only teachers can view class-wide recommendations\",\n });\n }\n\n const classData = await prisma.class.findUnique({\n where: { id: classId },\n select: {\n id: true,\n name: true,\n subject: true,\n students: {\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true } },\n submissions: {\n where: {\n assignment: { classId, graded: true },\n },\n include: {\n assignment: {\n select: {\n id: true,\n title: true,\n dueDate: true,\n maxGrade: true,\n weight: true,\n type: true,\n section: { select: { id: true, name: true } },\n },\n },\n },\n orderBy: { assignment: { dueDate: \"asc\" } },\n },\n },\n },\n },\n });\n\n if (!classData) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n const students = (\n await Promise.all(\n classData.students.map((student) =>\n summarizeStudentRecommendationsWithCases(student, student.submissions),\n ),\n )\n )\n .map(\n ({ recommendationCandidates: _recommendationCandidates, ...student }) =>\n student,\n )\n .filter((student) => student.recommendations.length > 0)\n .sort((a, b) => b.priorityScore - a.priorityScore);\n\n const totalRecommendations = students.reduce(\n (sum, student) => sum + student.recommendations.length,\n 0,\n );\n const studentsWithConcerns = students.length;\n const totalMissingAssignments = students.reduce(\n (sum, student) => sum + student.summary.missingCount,\n 0,\n );\n const totalLowScoreAssignments = students.reduce(\n (sum, student) => sum + student.summary.lowScoreCount,\n 0,\n );\n\n return {\n class: {\n id: classData.id,\n name: classData.name,\n subject: classData.subject,\n },\n summary: {\n studentsWithConcerns,\n totalRecommendations,\n totalMissingAssignments,\n totalLowScoreAssignments,\n },\n students: students.map(({ priorityScore, ...student }) => student),\n };\n}\n\nexport async function dismissStudentRecommendation(\n viewerId: string,\n input: {\n classId: string;\n studentId: string;\n submissionId: string;\n },\n) {\n const teacherInClass = await isTeacherInClass(input.classId, viewerId);\n if (!teacherInClass) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Only teachers can dismiss recommendations\",\n });\n }\n\n const submission = await prisma.submission.findFirst({\n where: {\n id: input.submissionId,\n studentId: input.studentId,\n assignment: {\n classId: input.classId,\n },\n },\n select: { id: true },\n });\n\n if (!submission) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Submission not found for this student in this class\",\n });\n }\n\n await prisma.submission.update({\n where: { id: input.submissionId },\n data: {\n recommendationState: \"DISMISSED\",\n recommendationUpdatedAt: new Date(),\n },\n });\n\n return { success: true };\n}\n\nfunction buildProgressSummary(submissions: GradeSubmission[]) {\n return submissions.map((submission) => ({\n title: submission.assignment.title,\n type: submission.assignment.type,\n dueDate: submission.assignment.dueDate.toISOString(),\n submitted: Boolean(submission.submitted),\n returned: Boolean(submission.returned),\n gradeReceived: submission.gradeReceived,\n maxGrade: submission.assignment.maxGrade,\n percentage: calculatePercentage(submission),\n section: submission.assignment.section?.name ?? null,\n }));\n}\n\nfunction buildStructuredProgressContext(\n classData: { id: string; name: string; subject: string | null },\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const displayName = student.profile?.displayName ?? student.username;\n const recommendationSummary = summarizeStudentRecommendations(\n student,\n submissions,\n );\n\n return {\n class: classData,\n student: { id: student.id, username: student.username, displayName },\n progress: {\n overallGrade: getOverallGrade(submissions),\n trend: calculateTrend(submissions),\n summary: recommendationSummary.summary,\n assignments: buildProgressSummary(submissions),\n recommendations: recommendationSummary.recommendations.map(\n (recommendation) => ({\n title: recommendation.title,\n recommendationType: recommendation.recommendationType,\n percentage: recommendation.percentage,\n submitted: recommendation.submitted,\n reasons: recommendation.reasons,\n sectionName: recommendation.sectionName,\n }),\n ),\n },\n };\n}\n\nfunction buildStructuredInferenceMessages(\n instruction: string,\n context: ReturnType<typeof buildStructuredProgressContext>,\n) {\n return [\n {\n role: \"system\" as const,\n content:\n \"You are an educational progress analyst. Use only the provided class and grade context. Be specific, concise, supportive, and do not fabricate assignments, grades, or sections.\",\n },\n {\n role: \"user\" as const,\n content: JSON.stringify(context),\n },\n {\n role: \"user\" as const,\n content: instruction,\n },\n ];\n}\n\ntype ProgressInferenceCacheRow<T> = {\n epoch: number;\n cachedAt: number;\n value: T;\n};\n\nconst studentProgressInsightsCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressInsights>\n>();\nconst studentProgressForecastCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressForecast>\n>();\nconst studentProgressFocusCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressFocus>\n>();\n\nexport async function getStudentProgressInsights(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressInsightsCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n\n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressInsights>(\n buildStructuredInferenceMessages(\n [\n \"Generate an AI analytics summary for this one student's dashboard.\",\n \"The summary must be 2-4 plain-prose sentences: lead with overall grade and trajectory, then call out one strength and one concern with assignment titles.\",\n \"Strengths and growth items need 2-6 word labels and one-line evidence grounded in assignment titles or sections.\",\n \"Talking points must be 3-5 specific teacher check-in prompts with no numbering.\",\n ].join(\" \"),\n context,\n ),\n studentProgressInsightsSchema,\n {\n reason: \"student_progress_insights\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressInsightsCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function getStudentProgressForecast(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressForecastCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n\n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressForecast>(\n buildStructuredInferenceMessages(\n \"Predict the student's next graded assignment percentage band and risk status. Base the forecast on trajectory, missing work, low scores, and assignment recency. Keep the reason to one sentence.\",\n context,\n ),\n studentProgressForecastSchema,\n {\n reason: \"student_progress_forecast\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressForecastCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function getStudentProgressFocus(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressFocusCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n \n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressFocus>(\n buildStructuredInferenceMessages(\n \"Generate 3-5 student-facing weekly focus items. Each item should be specific, actionable, and grounded in the student's grade pattern or assignment titles. No numbering in the strings.\",\n context,\n ),\n studentProgressFocusSchema,\n {\n reason: \"student_progress_focus\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressFocusCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function chatAboutStudentProgress(\n viewerId: string,\n input: {\n classId: string;\n studentId: string;\n message: string;\n history?: ProgressChatMessage[];\n },\n) {\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n input.classId,\n input.studentId,\n );\n\n const displayName = student.profile?.displayName ?? student.username;\n const summary = {\n overallGrade: getOverallGrade(submissions),\n trend: calculateTrend(submissions),\n assignments: buildProgressSummary(submissions),\n };\n\n const messages = [\n {\n role: \"system\" as const,\n content:\n \"You are an educational progress assistant for teachers and students. Use only the provided class and grade context. Be concise, specific, supportive, and avoid fabricating grades or assignments.\",\n },\n {\n role: \"user\" as const,\n content: JSON.stringify({\n class: classData,\n student: { id: student.id, username: student.username, displayName },\n progress: summary,\n }),\n },\n ...(input.history ?? []).slice(-8).map((message) => ({\n role: message.role,\n content: message.content,\n })),\n { role: \"user\" as const, content: input.message },\n ];\n\n try {\n const response = await inference<string>(messages, undefined, {\n reason: \"student_progress_chat\",\n metadata: {\n viewerId,\n classId: input.classId,\n studentId: input.studentId,\n },\n attribution: { userId: viewerId, classId: input.classId },\n });\n if (typeof response !== \"string\" || response.trim().length === 0) {\n throw new Error(\"Student progress chat returned an empty response\");\n }\n return { message: response, isFallback: false };\n } catch (error) {\n logger.error(\"Failed to generate student progress chat response\", {\n error,\n classId: input.classId,\n studentId: input.studentId,\n });\n\n const overall =\n summary.overallGrade == null\n ? \"not enough graded work\"\n : `${summary.overallGrade}%`;\n const missingItems = summary.assignments.filter(\n (assignment) =>\n !assignment.submitted &&\n new Date(assignment.dueDate).getTime() < Date.now(),\n ).length;\n const lowScores = summary.assignments.filter(\n (assignment) =>\n assignment.percentage != null && assignment.percentage < 70,\n ).length;\n const awaitingFeedback = summary.assignments.filter(\n (assignment) =>\n assignment.submitted &&\n assignment.gradeReceived == null &&\n !assignment.returned,\n ).length;\n\n const fallbackParts = [\n `${displayName}'s current overall grade is ${overall}.`,\n missingItems > 0\n ? `${missingItems} assignment${missingItems === 1 ? \"\" : \"s\"} ${missingItems === 1 ? \"appears\" : \"appear\"} overdue.`\n : null,\n lowScores > 0\n ? `${lowScores} graded assignment${lowScores === 1 ? \" is\" : \"s are\"} below 70%.`\n : null,\n awaitingFeedback > 0\n ? `${awaitingFeedback} assignment${awaitingFeedback === 1 ? \" is\" : \"s are\"} still awaiting feedback.`\n : null,\n summary.trend < -5\n ? \"Recent performance is trending down, so a check-in would be reasonable.\"\n : \"Performance looks relatively steady from the available data.\",\n ].filter((part): part is string => Boolean(part));\n\n return {\n message: fallbackParts.join(\" \"),\n isFallback: true,\n };\n }\n}\n"],"names":[],"mappings":"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","debug_id":"6599ea6f-6b1e-5e33-98c2-31a09ed91bc9"}
|
|
1
|
+
{"version":3,"file":"studentProgress.js","sources":["services/studentProgress.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Student progress service - assignment recommendations and progress chat.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport type { AssignmentType } from \"@prisma/client\";\nimport { z } from \"zod\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { isTeacherInClass } from \"../models/class.js\";\nimport { createAssignmentRecord } from \"./assignment.js\";\nimport { inference } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n getStudentProgressInferenceCacheHit,\n setStudentProgressInferenceCache,\n} from \"./studentProgressInferenceCache.js\";\n\ntype ProgressChatMessage = {\n role: \"user\" | \"assistant\";\n content: string;\n};\n\ntype GradeSubmission = {\n id: string;\n gradeReceived: number | null;\n submitted: boolean | null;\n returned: boolean | null;\n submittedAt: Date | null;\n recommendationState: \"NONE\" | \"OPEN\" | \"ASSIGNED\" | \"DISMISSED\";\n targetedAssignmentId: string | null;\n assignment: {\n id: string;\n title: string;\n dueDate: Date;\n maxGrade: number | null;\n weight: number;\n type: AssignmentType;\n section: { id: string; name: string } | null;\n };\n};\n\ntype ProgressStudent = {\n id: string;\n username: string;\n profile: { displayName: string | null } | null;\n};\n\nconst insightItemSchema = z.object({\n label: z.string(),\n evidence: z.string(),\n});\n\nconst studentProgressInsightsSchema = z.object({\n summary: z.string(),\n strengths: z.array(insightItemSchema).min(2).max(4),\n growth: z.array(insightItemSchema).min(2).max(4),\n talkingPoints: z.array(z.string()).min(3).max(5),\n});\n\nconst studentProgressForecastSchema = z.object({\n forecastLow: z.number().min(0).max(100),\n forecastHigh: z.number().min(0).max(100),\n risk: z.enum([\"on_track\", \"watch\", \"at_risk\"]),\n reason: z.string(),\n});\n\nconst studentProgressFocusSchema = z.object({\n focusItems: z.array(z.string()).min(3).max(5),\n});\n\nexport type StudentProgressInsights = z.infer<\n typeof studentProgressInsightsSchema\n>;\nexport type StudentProgressForecast = z.infer<\n typeof studentProgressForecastSchema\n>;\nexport type StudentProgressFocus = z.infer<typeof studentProgressFocusSchema>;\n\ntype RecommendationType = \"missing\" | \"low_score\" | \"awaiting_feedback\";\n\nfunction calculatePercentage(submission: GradeSubmission) {\n if (submission.gradeReceived == null || !submission.assignment.maxGrade) {\n return null;\n }\n\n return (\n Math.round(\n (submission.gradeReceived / submission.assignment.maxGrade) * 1000,\n ) / 10\n );\n}\n\nfunction calculateTrend(submissions: GradeSubmission[]) {\n const graded = submissions\n .filter(\n (submission) =>\n submission.gradeReceived != null && submission.assignment.maxGrade,\n )\n .sort((a, b) => {\n const aTime = a.submittedAt?.getTime() ?? a.assignment.dueDate.getTime();\n const bTime = b.submittedAt?.getTime() ?? b.assignment.dueDate.getTime();\n return aTime - bTime;\n })\n .map((submission) => calculatePercentage(submission))\n .filter((value): value is number => value != null);\n\n if (graded.length < 2) return 0;\n\n const midpoint = Math.floor(graded.length / 2);\n const first = graded.slice(0, midpoint);\n const second = graded.slice(midpoint);\n const average = (values: number[]) =>\n values.reduce((sum, value) => sum + value, 0) / values.length;\n\n return Math.round((average(second) - average(first)) * 10) / 10;\n}\n\nfunction getOverallGrade(submissions: GradeSubmission[]) {\n let totalWeighted = 0;\n let totalWeight = 0;\n\n for (const submission of submissions) {\n if (\n submission.gradeReceived != null &&\n submission.assignment.maxGrade &&\n submission.assignment.weight\n ) {\n totalWeighted +=\n (submission.gradeReceived / submission.assignment.maxGrade) *\n submission.assignment.weight;\n totalWeight += submission.assignment.weight;\n }\n }\n\n return totalWeight > 0\n ? Math.round((totalWeighted / totalWeight) * 1000) / 10\n : null;\n}\n\nfunction normalizeAssignmentType(\n assignmentType: AssignmentType,\n): AssignmentType {\n if (assignmentType === \"TEST\" || assignmentType === \"QUIZ\") {\n return \"HOMEWORK\";\n }\n\n return assignmentType;\n}\n\nfunction buildSuggestedAssignment(\n recommendationType: RecommendationType,\n submission: GradeSubmission,\n displayName: string,\n percentage: number | null,\n) {\n const sourceTitle = submission.assignment.title;\n const section = submission.assignment.section?.name;\n const titleByType: Record<RecommendationType, string> = {\n missing: `Make-up: ${sourceTitle}`,\n low_score: `Targeted practice: ${sourceTitle}`,\n awaiting_feedback: `Revision follow-up: ${sourceTitle}`,\n };\n const leadByType: Record<RecommendationType, string> = {\n missing: `${displayName} missed the original assignment and needs a focused make-up task on the same material.`,\n low_score:\n percentage != null\n ? `${displayName} scored ${percentage}% and needs targeted reinforcement on the underlying concepts.`\n : `${displayName} needs targeted reinforcement on the underlying concepts.`,\n awaiting_feedback: `${displayName} has work in progress here, so a short follow-up can keep momentum once feedback lands.`,\n };\n\n return {\n title: titleByType[recommendationType],\n instructions: [\n leadByType[recommendationType],\n `Source assignment: ${sourceTitle}.`,\n section ? `Section: ${section}.` : null,\n \"Keep the work concise and focused on the specific area of concern.\",\n ]\n .filter((line): line is string => Boolean(line))\n .join(\"\\n\\n\"),\n type: normalizeAssignmentType(submission.assignment.type),\n maxGrade: submission.assignment.maxGrade ?? 100,\n weight: submission.assignment.weight || 1,\n graded: true,\n sectionId: submission.assignment.section?.id ?? null,\n sourceAssignmentId: submission.assignment.id,\n };\n}\n\nfunction buildRecommendationCandidate(\n submission: GradeSubmission,\n displayName: string,\n now: Date,\n) {\n if (\n submission.recommendationState === \"ASSIGNED\" ||\n submission.recommendationState === \"DISMISSED\"\n ) {\n return null;\n }\n\n const percentage = calculatePercentage(submission);\n const isMissing =\n !submission.submitted &&\n submission.assignment.dueDate.getTime() < now.getTime();\n const isLowScore = percentage != null && percentage < 70;\n const isUnreturned =\n Boolean(submission.submitted) &&\n submission.gradeReceived == null &&\n !submission.returned;\n const reasons: string[] = [];\n let priorityScore = 0;\n let recommendationType: RecommendationType | null = null;\n\n if (isMissing) {\n reasons.push(\"Missing past-due work\");\n priorityScore += 100;\n recommendationType = \"missing\";\n }\n if (isLowScore) {\n reasons.push(`Scored ${percentage}%`);\n priorityScore += 85 - (percentage ?? 0);\n recommendationType ??= \"low_score\";\n }\n if (isUnreturned) {\n reasons.push(\"Awaiting grade or feedback\");\n priorityScore += 15;\n recommendationType ??= \"awaiting_feedback\";\n }\n\n if (priorityScore <= 0 || !recommendationType) {\n return null;\n }\n\n return {\n assignmentId: submission.assignment.id,\n submissionId: submission.id,\n title: submission.assignment.title,\n type: submission.assignment.type,\n sectionId: submission.assignment.section?.id ?? null,\n sectionName: submission.assignment.section?.name ?? null,\n dueDate: submission.assignment.dueDate,\n gradeReceived: submission.gradeReceived,\n maxGrade: submission.assignment.maxGrade,\n percentage,\n submitted: Boolean(submission.submitted),\n returned: Boolean(submission.returned),\n recommendationType,\n reasons,\n priorityScore,\n suggestedAssignment: buildSuggestedAssignment(\n recommendationType,\n submission,\n displayName,\n percentage,\n ),\n };\n}\n\nfunction summarizeStudentRecommendations(\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const now = new Date();\n const displayName = student.profile?.displayName ?? student.username;\n const recommendationCandidates = submissions\n .map((submission) =>\n buildRecommendationCandidate(submission, displayName, now),\n )\n .filter(\n (\n candidate,\n ): candidate is NonNullable<\n ReturnType<typeof buildRecommendationCandidate>\n > => candidate != null,\n )\n .sort((a, b) => b.priorityScore - a.priorityScore);\n\n const recommendations = recommendationCandidates\n .slice(0, 5)\n .map(({ priorityScore, ...candidate }) => candidate);\n\n const gradedPercentages = submissions\n .map(calculatePercentage)\n .filter((value): value is number => value != null);\n const lowScoreCount = gradedPercentages.filter(\n (percentage) => percentage < 70,\n ).length;\n const missingCount = submissions.filter(\n (submission) =>\n !submission.submitted &&\n submission.assignment.dueDate.getTime() < now.getTime(),\n ).length;\n const trend = calculateTrend(submissions);\n const overallGrade = getOverallGrade(submissions);\n\n const nextSteps = [\n missingCount > 0\n ? `Prioritize ${missingCount} missing assignment${missingCount === 1 ? \"\" : \"s\"}.`\n : null,\n lowScoreCount > 0\n ? `Review ${lowScoreCount} low-scoring assignment${lowScoreCount === 1 ? \"\" : \"s\"} before introducing new material.`\n : null,\n trend < -5\n ? \"Schedule a check-in because recent performance is trending down.\"\n : null,\n recommendationCandidates.length === 0\n ? \"No urgent assignment issues detected from the available grades.\"\n : null,\n ].filter((step): step is string => Boolean(step));\n\n return {\n student: {\n id: student.id,\n username: student.username,\n displayName,\n },\n summary: {\n overallGrade,\n trend,\n completedAssignments: submissions.filter((submission) =>\n Boolean(submission.submitted),\n ).length,\n totalAssignments: submissions.length,\n missingCount,\n lowScoreCount,\n },\n recommendations,\n recommendationCandidates,\n nextSteps,\n priorityScore: recommendationCandidates[0]?.priorityScore ?? 0,\n };\n}\n\nasync function syncRecommendationStates(\n submissions: GradeSubmission[],\n recommendationCandidates: Array<\n NonNullable<ReturnType<typeof buildRecommendationCandidate>>\n >,\n) {\n const candidateSubmissionIds = new Set(\n recommendationCandidates.map((candidate) => candidate.submissionId),\n );\n const updates: Promise<unknown>[] = [];\n\n for (const submission of submissions) {\n const shouldBeOpen = candidateSubmissionIds.has(submission.id);\n\n if (shouldBeOpen && submission.recommendationState === \"NONE\") {\n updates.push(\n prisma.submission.update({\n where: { id: submission.id },\n data: {\n recommendationState: \"OPEN\",\n recommendationUpdatedAt: new Date(),\n },\n }),\n );\n continue;\n }\n\n if (!shouldBeOpen && submission.recommendationState === \"OPEN\") {\n updates.push(\n prisma.submission.update({\n where: { id: submission.id },\n data: {\n recommendationState: \"NONE\",\n recommendationUpdatedAt: new Date(),\n },\n }),\n );\n }\n }\n\n if (updates.length) {\n await Promise.all(updates);\n }\n}\n\nasync function summarizeStudentRecommendationsWithCases(\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const summary = summarizeStudentRecommendations(student, submissions);\n await syncRecommendationStates(submissions, summary.recommendationCandidates);\n return summary;\n}\n\nasync function loadStudentProgressContext(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const isTeacher = await isTeacherInClass(classId, viewerId);\n if (viewerId !== studentId && !isTeacher) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You can only view your own progress\",\n });\n }\n\n const [classData, student, submissions] = await Promise.all([\n prisma.class.findUnique({\n where: { id: classId },\n select: { id: true, name: true, subject: true },\n }),\n prisma.user.findFirst({\n where: {\n id: studentId,\n studentIn: { some: { id: classId } },\n },\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true } },\n },\n }),\n prisma.submission.findMany({\n where: {\n studentId,\n assignment: { classId, graded: true },\n },\n include: {\n assignment: {\n select: {\n id: true,\n title: true,\n dueDate: true,\n maxGrade: true,\n weight: true,\n type: true,\n section: { select: { id: true, name: true } },\n },\n },\n },\n orderBy: { assignment: { dueDate: \"asc\" } },\n }),\n ]);\n\n if (!classData) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n if (!student) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Student not found in this class\",\n });\n }\n\n return { classData, student, submissions };\n}\n\nexport async function getStudentProgressRecommendations(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const { student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n const summary = await summarizeStudentRecommendationsWithCases(\n student,\n submissions,\n );\n const {\n recommendationCandidates: _recommendationCandidates,\n ...summaryResponse\n } = summary;\n return {\n student: summaryResponse.student,\n summary: summaryResponse.summary,\n recommendations: summaryResponse.recommendations,\n nextSteps: summaryResponse.nextSteps,\n };\n}\n\nexport async function getClassProgressRecommendations(\n viewerId: string,\n classId: string,\n) {\n const teacherInClass = await isTeacherInClass(classId, viewerId);\n if (!teacherInClass) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Only teachers can view class-wide recommendations\",\n });\n }\n\n const classData = await prisma.class.findUnique({\n where: { id: classId },\n select: {\n id: true,\n name: true,\n subject: true,\n students: {\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true } },\n submissions: {\n where: {\n assignment: { classId, graded: true },\n },\n include: {\n assignment: {\n select: {\n id: true,\n title: true,\n dueDate: true,\n maxGrade: true,\n weight: true,\n type: true,\n section: { select: { id: true, name: true } },\n },\n },\n },\n orderBy: { assignment: { dueDate: \"asc\" } },\n },\n },\n },\n },\n });\n\n if (!classData) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n\n const students = (\n await Promise.all(\n classData.students.map((student) =>\n summarizeStudentRecommendationsWithCases(student, student.submissions),\n ),\n )\n )\n .map(\n ({ recommendationCandidates: _recommendationCandidates, ...student }) =>\n student,\n )\n .filter((student) => student.recommendations.length > 0)\n .sort((a, b) => b.priorityScore - a.priorityScore);\n\n const totalRecommendations = students.reduce(\n (sum, student) => sum + student.recommendations.length,\n 0,\n );\n const studentsWithConcerns = students.length;\n const totalMissingAssignments = students.reduce(\n (sum, student) => sum + student.summary.missingCount,\n 0,\n );\n const totalLowScoreAssignments = students.reduce(\n (sum, student) => sum + student.summary.lowScoreCount,\n 0,\n );\n\n return {\n class: {\n id: classData.id,\n name: classData.name,\n subject: classData.subject,\n },\n summary: {\n studentsWithConcerns,\n totalRecommendations,\n totalMissingAssignments,\n totalLowScoreAssignments,\n },\n students: students.map(({ priorityScore, ...student }) => student),\n };\n}\n\nexport async function dismissStudentRecommendation(\n viewerId: string,\n input: {\n classId: string;\n studentId: string;\n submissionId: string;\n },\n) {\n const teacherInClass = await isTeacherInClass(input.classId, viewerId);\n if (!teacherInClass) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Only teachers can dismiss recommendations\",\n });\n }\n\n const submission = await prisma.submission.findFirst({\n where: {\n id: input.submissionId,\n studentId: input.studentId,\n assignment: {\n classId: input.classId,\n },\n },\n select: { id: true },\n });\n\n if (!submission) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Submission not found for this student in this class\",\n });\n }\n\n await prisma.submission.update({\n where: { id: input.submissionId },\n data: {\n recommendationState: \"DISMISSED\",\n recommendationUpdatedAt: new Date(),\n },\n });\n\n return { success: true };\n}\n\nconst followUpAssignmentSchema = z.object({\n title: z.string().min(1).max(200),\n instructions: z.string().min(1),\n});\n\nexport type FollowUpAssignmentDraft = z.infer<typeof followUpAssignmentSchema>;\n\nexport async function generateFollowUpAssignment(\n viewerId: string,\n input: {\n classId: string;\n studentId: string;\n submissionId: string;\n prompt: string;\n dueDate?: string;\n },\n) {\n const teacherInClass = await isTeacherInClass(input.classId, viewerId);\n if (!teacherInClass) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Only teachers can generate follow-up assignments\",\n });\n }\n\n const submission = await prisma.submission.findFirst({\n where: {\n id: input.submissionId,\n studentId: input.studentId,\n assignment: { classId: input.classId },\n },\n select: {\n id: true,\n gradeReceived: true,\n teacherComments: true,\n student: {\n select: {\n id: true,\n username: true,\n profile: { select: { displayName: true } },\n },\n },\n assignment: {\n select: {\n id: true,\n title: true,\n instructions: true,\n type: true,\n maxGrade: true,\n weight: true,\n section: { select: { id: true, name: true } },\n },\n },\n },\n });\n\n if (!submission) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Submission not found for this student in this class\",\n });\n }\n\n const displayName =\n submission.student.profile?.displayName ?? submission.student.username;\n const percentage =\n submission.gradeReceived != null && submission.assignment.maxGrade\n ? Math.round(\n (submission.gradeReceived / submission.assignment.maxGrade) * 1000,\n ) / 10\n : null;\n\n const draft = await inference<FollowUpAssignmentDraft>(\n [\n {\n role: \"system\" as const,\n content:\n \"You are an experienced teacher creating a targeted follow-up assignment for one student. Ground the task in the source assignment and the teacher's request. Do not fabricate material beyond the source assignment's topic. Return a concise title and clear, student-facing instructions.\",\n },\n {\n role: \"user\" as const,\n content: JSON.stringify({\n student: { displayName },\n sourceAssignment: {\n title: submission.assignment.title,\n instructions: submission.assignment.instructions,\n type: submission.assignment.type,\n maxGrade: submission.assignment.maxGrade,\n section: submission.assignment.section?.name ?? null,\n },\n submission: {\n gradeReceived: submission.gradeReceived,\n percentage,\n teacherFeedback: submission.teacherComments,\n },\n }),\n },\n { role: \"user\" as const, content: input.prompt },\n ],\n followUpAssignmentSchema,\n {\n reason: \"student_progress_follow_up_assignment\",\n metadata: {\n viewerId,\n classId: input.classId,\n studentId: input.studentId,\n submissionId: input.submissionId,\n },\n attribution: { userId: viewerId, classId: input.classId },\n },\n );\n\n const dueDate =\n input.dueDate ??\n new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();\n\n const assignment = await createAssignmentRecord(viewerId, {\n classId: input.classId,\n title: draft.title,\n instructions: draft.instructions,\n dueDate,\n studentIds: [input.studentId],\n maxGrade: submission.assignment.maxGrade ?? 100,\n graded: true,\n weight: submission.assignment.weight || 1,\n sectionId: submission.assignment.section?.id ?? undefined,\n type: normalizeAssignmentType(submission.assignment.type),\n acceptExtendedResponse: true,\n sourceAssignmentId: submission.assignment.id,\n });\n\n return { assignment, draft };\n}\n\nfunction buildProgressSummary(submissions: GradeSubmission[]) {\n return submissions.map((submission) => ({\n title: submission.assignment.title,\n type: submission.assignment.type,\n dueDate: submission.assignment.dueDate.toISOString(),\n submitted: Boolean(submission.submitted),\n returned: Boolean(submission.returned),\n gradeReceived: submission.gradeReceived,\n maxGrade: submission.assignment.maxGrade,\n percentage: calculatePercentage(submission),\n section: submission.assignment.section?.name ?? null,\n }));\n}\n\nfunction buildStructuredProgressContext(\n classData: { id: string; name: string; subject: string | null },\n student: ProgressStudent,\n submissions: GradeSubmission[],\n) {\n const displayName = student.profile?.displayName ?? student.username;\n const recommendationSummary = summarizeStudentRecommendations(\n student,\n submissions,\n );\n\n return {\n class: classData,\n student: { id: student.id, username: student.username, displayName },\n progress: {\n overallGrade: getOverallGrade(submissions),\n trend: calculateTrend(submissions),\n summary: recommendationSummary.summary,\n assignments: buildProgressSummary(submissions),\n recommendations: recommendationSummary.recommendations.map(\n (recommendation) => ({\n title: recommendation.title,\n recommendationType: recommendation.recommendationType,\n percentage: recommendation.percentage,\n submitted: recommendation.submitted,\n reasons: recommendation.reasons,\n sectionName: recommendation.sectionName,\n }),\n ),\n },\n };\n}\n\nfunction buildStructuredInferenceMessages(\n instruction: string,\n context: ReturnType<typeof buildStructuredProgressContext>,\n) {\n return [\n {\n role: \"system\" as const,\n content:\n \"You are an educational progress analyst. Use only the provided class and grade context. Be specific, concise, supportive, and do not fabricate assignments, grades, or sections.\",\n },\n {\n role: \"user\" as const,\n content: JSON.stringify(context),\n },\n {\n role: \"user\" as const,\n content: instruction,\n },\n ];\n}\n\ntype ProgressInferenceCacheRow<T> = {\n epoch: number;\n cachedAt: number;\n value: T;\n};\n\nconst studentProgressInsightsCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressInsights>\n>();\nconst studentProgressForecastCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressForecast>\n>();\nconst studentProgressFocusCache = new Map<\n string,\n ProgressInferenceCacheRow<StudentProgressFocus>\n>();\n\nexport async function getStudentProgressInsights(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressInsightsCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n\n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressInsights>(\n buildStructuredInferenceMessages(\n [\n \"Generate an AI analytics summary for this one student's dashboard.\",\n \"The summary must be 2-4 plain-prose sentences: lead with overall grade and trajectory, then call out one strength and one concern with assignment titles.\",\n \"Strengths and growth items need 2-6 word labels and one-line evidence grounded in assignment titles or sections.\",\n \"Talking points must be 3-5 specific teacher check-in prompts with no numbering.\",\n ].join(\" \"),\n context,\n ),\n studentProgressInsightsSchema,\n {\n reason: \"student_progress_insights\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressInsightsCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function getStudentProgressForecast(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressForecastCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n\n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressForecast>(\n buildStructuredInferenceMessages(\n \"Predict the student's next graded assignment percentage band and risk status. Base the forecast on trajectory, missing work, low scores, and assignment recency. Keep the reason to one sentence.\",\n context,\n ),\n studentProgressForecastSchema,\n {\n reason: \"student_progress_forecast\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressForecastCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function getStudentProgressFocus(\n viewerId: string,\n classId: string,\n studentId: string,\n) {\n const cached = getStudentProgressInferenceCacheHit(\n studentProgressFocusCache,\n classId,\n studentId,\n );\n\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n classId,\n studentId,\n );\n\n if (cached !== undefined) {\n return cached;\n }\n \n const context = buildStructuredProgressContext(\n classData,\n student,\n submissions,\n );\n\n const value = await inference<StudentProgressFocus>(\n buildStructuredInferenceMessages(\n \"Generate 3-5 student-facing weekly focus items. Each item should be specific, actionable, and grounded in the student's grade pattern or assignment titles. No numbering in the strings.\",\n context,\n ),\n studentProgressFocusSchema,\n {\n reason: \"student_progress_focus\",\n metadata: { viewerId, classId, studentId },\n attribution: { userId: viewerId, classId },\n },\n );\n setStudentProgressInferenceCache(\n studentProgressFocusCache,\n classId,\n studentId,\n value,\n );\n return value;\n}\n\nexport async function chatAboutStudentProgress(\n viewerId: string,\n input: {\n classId: string;\n studentId: string;\n message: string;\n history?: ProgressChatMessage[];\n },\n) {\n const { classData, student, submissions } = await loadStudentProgressContext(\n viewerId,\n input.classId,\n input.studentId,\n );\n\n const displayName = student.profile?.displayName ?? student.username;\n const summary = {\n overallGrade: getOverallGrade(submissions),\n trend: calculateTrend(submissions),\n assignments: buildProgressSummary(submissions),\n };\n\n const messages = [\n {\n role: \"system\" as const,\n content:\n \"You are an educational progress assistant for teachers and students. Use only the provided class and grade context. Be concise, specific, supportive, and avoid fabricating grades or assignments.\",\n },\n {\n role: \"user\" as const,\n content: JSON.stringify({\n class: classData,\n student: { id: student.id, username: student.username, displayName },\n progress: summary,\n }),\n },\n ...(input.history ?? []).slice(-8).map((message) => ({\n role: message.role,\n content: message.content,\n })),\n { role: \"user\" as const, content: input.message },\n ];\n\n try {\n const response = await inference<string>(messages, undefined, {\n reason: \"student_progress_chat\",\n metadata: {\n viewerId,\n classId: input.classId,\n studentId: input.studentId,\n },\n attribution: { userId: viewerId, classId: input.classId },\n });\n if (typeof response !== \"string\" || response.trim().length === 0) {\n throw new Error(\"Student progress chat returned an empty response\");\n }\n return { message: response, isFallback: false };\n } catch (error) {\n logger.error(\"Failed to generate student progress chat response\", {\n error,\n classId: input.classId,\n studentId: input.studentId,\n });\n\n const overall =\n summary.overallGrade == null\n ? \"not enough graded work\"\n : `${summary.overallGrade}%`;\n const missingItems = summary.assignments.filter(\n (assignment) =>\n !assignment.submitted &&\n new Date(assignment.dueDate).getTime() < Date.now(),\n ).length;\n const lowScores = summary.assignments.filter(\n (assignment) =>\n assignment.percentage != null && assignment.percentage < 70,\n ).length;\n const awaitingFeedback = summary.assignments.filter(\n (assignment) =>\n assignment.submitted &&\n assignment.gradeReceived == null &&\n !assignment.returned,\n ).length;\n\n const fallbackParts = [\n `${displayName}'s current overall grade is ${overall}.`,\n missingItems > 0\n ? `${missingItems} assignment${missingItems === 1 ? \"\" : \"s\"} ${missingItems === 1 ? \"appears\" : \"appear\"} overdue.`\n : null,\n lowScores > 0\n ? `${lowScores} graded assignment${lowScores === 1 ? \" is\" : \"s are\"} below 70%.`\n : null,\n awaitingFeedback > 0\n ? `${awaitingFeedback} assignment${awaitingFeedback === 1 ? \" is\" : \"s are\"} still awaiting feedback.`\n : null,\n summary.trend < -5\n ? \"Recent performance is trending down, so a check-in would be reasonable.\"\n : \"Performance looks relatively steady from the available data.\",\n ].filter((part): part is string => Boolean(part));\n\n return {\n message: fallbackParts.join(\" \"),\n isFallback: true,\n };\n }\n}\n"],"names":[],"mappings":"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","debug_id":"95393c1d-f8f7-5a00-adf1-4b143ba57f36"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Teachers see every visualisation in the class; students only published ones. */
|
|
2
|
+
export declare function listVisualizations(userId: string, classId: string): Promise<{
|
|
3
|
+
id: string;
|
|
4
|
+
createdAt: Date;
|
|
5
|
+
updatedAt: Date;
|
|
6
|
+
classId: string;
|
|
7
|
+
title: string;
|
|
8
|
+
prompt: string | null;
|
|
9
|
+
published: boolean;
|
|
10
|
+
}[]>;
|
|
11
|
+
export declare function getVisualization(userId: string, classId: string, id: string): Promise<{
|
|
12
|
+
id: string;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
updatedAt: Date;
|
|
15
|
+
classId: string;
|
|
16
|
+
title: string;
|
|
17
|
+
prompt: string | null;
|
|
18
|
+
published: boolean;
|
|
19
|
+
html: string;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function createVisualization(userId: string, input: {
|
|
22
|
+
classId: string;
|
|
23
|
+
prompt: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
id: string;
|
|
27
|
+
createdAt: Date;
|
|
28
|
+
updatedAt: Date;
|
|
29
|
+
classId: string;
|
|
30
|
+
title: string;
|
|
31
|
+
prompt: string | null;
|
|
32
|
+
published: boolean;
|
|
33
|
+
html: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function reviseVisualizationRecord(userId: string, input: {
|
|
36
|
+
classId: string;
|
|
37
|
+
id: string;
|
|
38
|
+
instruction: string;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
id: string;
|
|
41
|
+
createdAt: Date;
|
|
42
|
+
updatedAt: Date;
|
|
43
|
+
classId: string;
|
|
44
|
+
title: string;
|
|
45
|
+
prompt: string | null;
|
|
46
|
+
published: boolean;
|
|
47
|
+
html: string;
|
|
48
|
+
}>;
|
|
49
|
+
export declare function updateVisualization(input: {
|
|
50
|
+
classId: string;
|
|
51
|
+
id: string;
|
|
52
|
+
title?: string;
|
|
53
|
+
html?: string;
|
|
54
|
+
published?: boolean;
|
|
55
|
+
}): Promise<{
|
|
56
|
+
id: string;
|
|
57
|
+
createdAt: Date;
|
|
58
|
+
updatedAt: Date;
|
|
59
|
+
classId: string;
|
|
60
|
+
title: string;
|
|
61
|
+
prompt: string | null;
|
|
62
|
+
published: boolean;
|
|
63
|
+
html: string;
|
|
64
|
+
}>;
|
|
65
|
+
/** Deletes the visualisation and any module items that pointed at it. */
|
|
66
|
+
export declare function deleteVisualization(input: {
|
|
67
|
+
classId: string;
|
|
68
|
+
id: string;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
id: string;
|
|
71
|
+
}>;
|
|
72
|
+
//# sourceMappingURL=visualization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualization.d.ts","sourceRoot":"/","sources":["services/visualization.ts"],"names":[],"mappings":"AA+CA,mFAAmF;AACnF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;KAOvE;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;GAUjF;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAmB3D;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAkB5D;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;;;;;;;;;GAcA;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;;GAS/E"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ce0610d2-b722-5212-95c5-af7baafc7cb6")}catch(e){}}();
|
|
3
|
+
import { TRPCError } from "@trpc/server";
|
|
4
|
+
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import { isTeacherInClass } from "../models/class.js";
|
|
6
|
+
import { generateVisualization, MAX_VISUALIZATION_HTML_LENGTH, reviseVisualization, } from "../pipelines/generateVisualization.js";
|
|
7
|
+
const summarySelect = {
|
|
8
|
+
id: true,
|
|
9
|
+
classId: true,
|
|
10
|
+
title: true,
|
|
11
|
+
prompt: true,
|
|
12
|
+
published: true,
|
|
13
|
+
createdAt: true,
|
|
14
|
+
updatedAt: true,
|
|
15
|
+
};
|
|
16
|
+
const detailSelect = { ...summarySelect, html: true };
|
|
17
|
+
async function getClassContext(classId) {
|
|
18
|
+
return prisma.class.findUnique({
|
|
19
|
+
where: { id: classId },
|
|
20
|
+
select: { name: true, subject: true, schoolId: true },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function findTeacherVisualization(classId, id) {
|
|
24
|
+
const viz = await prisma.visualization.findFirst({
|
|
25
|
+
where: { id, classId },
|
|
26
|
+
select: detailSelect,
|
|
27
|
+
});
|
|
28
|
+
if (!viz) {
|
|
29
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "Visualisation not found" });
|
|
30
|
+
}
|
|
31
|
+
return viz;
|
|
32
|
+
}
|
|
33
|
+
function aiError(error) {
|
|
34
|
+
throw new TRPCError({
|
|
35
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
36
|
+
message: "Newton couldn't build that visualisation. Try rephrasing it.",
|
|
37
|
+
cause: error,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** Teachers see every visualisation in the class; students only published ones. */
|
|
41
|
+
export async function listVisualizations(userId, classId) {
|
|
42
|
+
const isTeacher = !!(await isTeacherInClass(classId, userId));
|
|
43
|
+
return prisma.visualization.findMany({
|
|
44
|
+
where: { classId, ...(isTeacher ? {} : { published: true }) },
|
|
45
|
+
select: summarySelect,
|
|
46
|
+
orderBy: { updatedAt: "desc" },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export async function getVisualization(userId, classId, id) {
|
|
50
|
+
const isTeacher = !!(await isTeacherInClass(classId, userId));
|
|
51
|
+
const viz = await prisma.visualization.findFirst({
|
|
52
|
+
where: { id, classId, ...(isTeacher ? {} : { published: true }) },
|
|
53
|
+
select: detailSelect,
|
|
54
|
+
});
|
|
55
|
+
if (!viz) {
|
|
56
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "Visualisation not found" });
|
|
57
|
+
}
|
|
58
|
+
return viz;
|
|
59
|
+
}
|
|
60
|
+
export async function createVisualization(userId, input) {
|
|
61
|
+
const cls = await getClassContext(input.classId);
|
|
62
|
+
const generated = await generateVisualization(input.prompt, {
|
|
63
|
+
className: cls?.name,
|
|
64
|
+
subject: cls?.subject,
|
|
65
|
+
attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },
|
|
66
|
+
}).catch(aiError);
|
|
67
|
+
return prisma.visualization.create({
|
|
68
|
+
data: {
|
|
69
|
+
classId: input.classId,
|
|
70
|
+
createdById: userId,
|
|
71
|
+
title: input.title?.trim() || generated.title,
|
|
72
|
+
prompt: input.prompt,
|
|
73
|
+
html: generated.html,
|
|
74
|
+
},
|
|
75
|
+
select: detailSelect,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export async function reviseVisualizationRecord(userId, input) {
|
|
79
|
+
const current = await findTeacherVisualization(input.classId, input.id);
|
|
80
|
+
const cls = await getClassContext(input.classId);
|
|
81
|
+
const revised = await reviseVisualization(current, input.instruction, {
|
|
82
|
+
className: cls?.name,
|
|
83
|
+
subject: cls?.subject,
|
|
84
|
+
attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },
|
|
85
|
+
}).catch(aiError);
|
|
86
|
+
return prisma.visualization.update({
|
|
87
|
+
where: { id: current.id },
|
|
88
|
+
data: {
|
|
89
|
+
html: revised.html,
|
|
90
|
+
prompt: [current.prompt, input.instruction].filter(Boolean).join("\n\n"),
|
|
91
|
+
},
|
|
92
|
+
select: detailSelect,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
export async function updateVisualization(input) {
|
|
96
|
+
const current = await findTeacherVisualization(input.classId, input.id);
|
|
97
|
+
if (input.html !== undefined && input.html.length > MAX_VISUALIZATION_HTML_LENGTH) {
|
|
98
|
+
throw new TRPCError({ code: "BAD_REQUEST", message: "Visualisation is too large" });
|
|
99
|
+
}
|
|
100
|
+
return prisma.visualization.update({
|
|
101
|
+
where: { id: current.id },
|
|
102
|
+
data: {
|
|
103
|
+
...(input.title !== undefined ? { title: input.title } : {}),
|
|
104
|
+
...(input.html !== undefined ? { html: input.html } : {}),
|
|
105
|
+
...(input.published !== undefined ? { published: input.published } : {}),
|
|
106
|
+
},
|
|
107
|
+
select: detailSelect,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/** Deletes the visualisation and any module items that pointed at it. */
|
|
111
|
+
export async function deleteVisualization(input) {
|
|
112
|
+
const current = await findTeacherVisualization(input.classId, input.id);
|
|
113
|
+
await prisma.$transaction([
|
|
114
|
+
prisma.courseModuleItem.deleteMany({
|
|
115
|
+
where: { itemType: "VISUALIZATION", itemId: current.id },
|
|
116
|
+
}),
|
|
117
|
+
prisma.visualization.delete({ where: { id: current.id } }),
|
|
118
|
+
]);
|
|
119
|
+
return { id: current.id };
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=visualization.js.map
|
|
122
|
+
//# debugId=ce0610d2-b722-5212-95c5-af7baafc7cb6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualization.js","sources":["services/visualization.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { isTeacherInClass } from \"../models/class.js\";\nimport {\n generateVisualization,\n MAX_VISUALIZATION_HTML_LENGTH,\n reviseVisualization,\n} from \"../pipelines/generateVisualization.js\";\n\nconst summarySelect = {\n id: true,\n classId: true,\n title: true,\n prompt: true,\n published: true,\n createdAt: true,\n updatedAt: true,\n} as const;\n\nconst detailSelect = { ...summarySelect, html: true } as const;\n\nasync function getClassContext(classId: string) {\n return prisma.class.findUnique({\n where: { id: classId },\n select: { name: true, subject: true, schoolId: true },\n });\n}\n\nasync function findTeacherVisualization(classId: string, id: string) {\n const viz = await prisma.visualization.findFirst({\n where: { id, classId },\n select: detailSelect,\n });\n if (!viz) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Visualisation not found\" });\n }\n return viz;\n}\n\nfunction aiError(error: unknown): never {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Newton couldn't build that visualisation. Try rephrasing it.\",\n cause: error,\n });\n}\n\n/** Teachers see every visualisation in the class; students only published ones. */\nexport async function listVisualizations(userId: string, classId: string) {\n const isTeacher = !!(await isTeacherInClass(classId, userId));\n return prisma.visualization.findMany({\n where: { classId, ...(isTeacher ? {} : { published: true }) },\n select: summarySelect,\n orderBy: { updatedAt: \"desc\" },\n });\n}\n\nexport async function getVisualization(userId: string, classId: string, id: string) {\n const isTeacher = !!(await isTeacherInClass(classId, userId));\n const viz = await prisma.visualization.findFirst({\n where: { id, classId, ...(isTeacher ? {} : { published: true }) },\n select: detailSelect,\n });\n if (!viz) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Visualisation not found\" });\n }\n return viz;\n}\n\nexport async function createVisualization(\n userId: string,\n input: { classId: string; prompt: string; title?: string },\n) {\n const cls = await getClassContext(input.classId);\n const generated = await generateVisualization(input.prompt, {\n className: cls?.name,\n subject: cls?.subject,\n attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },\n }).catch(aiError);\n\n return prisma.visualization.create({\n data: {\n classId: input.classId,\n createdById: userId,\n title: input.title?.trim() || generated.title,\n prompt: input.prompt,\n html: generated.html,\n },\n select: detailSelect,\n });\n}\n\nexport async function reviseVisualizationRecord(\n userId: string,\n input: { classId: string; id: string; instruction: string },\n) {\n const current = await findTeacherVisualization(input.classId, input.id);\n const cls = await getClassContext(input.classId);\n const revised = await reviseVisualization(current, input.instruction, {\n className: cls?.name,\n subject: cls?.subject,\n attribution: { userId, classId: input.classId, schoolId: cls?.schoolId },\n }).catch(aiError);\n\n return prisma.visualization.update({\n where: { id: current.id },\n data: {\n html: revised.html,\n prompt: [current.prompt, input.instruction].filter(Boolean).join(\"\\n\\n\"),\n },\n select: detailSelect,\n });\n}\n\nexport async function updateVisualization(input: {\n classId: string;\n id: string;\n title?: string;\n html?: string;\n published?: boolean;\n}) {\n const current = await findTeacherVisualization(input.classId, input.id);\n if (input.html !== undefined && input.html.length > MAX_VISUALIZATION_HTML_LENGTH) {\n throw new TRPCError({ code: \"BAD_REQUEST\", message: \"Visualisation is too large\" });\n }\n return prisma.visualization.update({\n where: { id: current.id },\n data: {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.html !== undefined ? { html: input.html } : {}),\n ...(input.published !== undefined ? { published: input.published } : {}),\n },\n select: detailSelect,\n });\n}\n\n/** Deletes the visualisation and any module items that pointed at it. */\nexport async function deleteVisualization(input: { classId: string; id: string }) {\n const current = await findTeacherVisualization(input.classId, input.id);\n await prisma.$transaction([\n prisma.courseModuleItem.deleteMany({\n where: { itemType: \"VISUALIZATION\", itemId: current.id },\n }),\n prisma.visualization.delete({ where: { id: current.id } }),\n ]);\n return { id: current.id };\n}\n"],"names":[],"mappings":"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","debug_id":"ce0610d2-b722-5212-95c5-af7baafc7cb6"}
|
|
@@ -122,6 +122,16 @@ export declare function completePendingAIMessage(messageId: string, content: str
|
|
|
122
122
|
createdAt: Date;
|
|
123
123
|
status: JobStatus;
|
|
124
124
|
}>;
|
|
125
|
+
/**
|
|
126
|
+
* Persist the partial output of a cancelled generation and flip the AI
|
|
127
|
+
* message to CANCELLED. Whatever text/tool parts streamed before the stop
|
|
128
|
+
* are kept on the row (content + meta) so they survive reloads. Broadcasts
|
|
129
|
+
* `message-updated` so clients patch the bubble in place.
|
|
130
|
+
*/
|
|
131
|
+
export declare function cancelPendingAIMessage(messageId: string, content: string, options?: {
|
|
132
|
+
meta?: Record<string, any>;
|
|
133
|
+
customSender?: AIMessageSenderInfo;
|
|
134
|
+
}): Promise<void>;
|
|
125
135
|
/**
|
|
126
136
|
* Flip a PENDING AI message to FAILED and broadcast the status change.
|
|
127
137
|
* Does NOT throw — failure paths in the pipelines call this in catch blocks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inference.d.ts","sourceRoot":"/","sources":["utils/inference.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"inference.d.ts","sourceRoot":"/","sources":["utils/inference.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/inference.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Inference util – OpenAI client, inference() for structured output, sendAIMessage for chat.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
5
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ba92dc8c-6ba8-5d95-a027-50c47894fcc3")}catch(e){}}();
|
|
6
6
|
import OpenAI from 'openai';
|
|
7
7
|
import { logger } from './logger.js';
|
|
8
8
|
import { prisma } from '../lib/prisma.js';
|
|
@@ -306,6 +306,68 @@ export async function completePendingAIMessage(messageId, content, options = {})
|
|
|
306
306
|
status: (updated.status ?? JobStatus.COMPLETED),
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Persist the partial output of a cancelled generation and flip the AI
|
|
311
|
+
* message to CANCELLED. Whatever text/tool parts streamed before the stop
|
|
312
|
+
* are kept on the row (content + meta) so they survive reloads. Broadcasts
|
|
313
|
+
* `message-updated` so clients patch the bubble in place.
|
|
314
|
+
*/
|
|
315
|
+
export async function cancelPendingAIMessage(messageId, content, options = {}) {
|
|
316
|
+
try {
|
|
317
|
+
const updated = await prisma.message.update({
|
|
318
|
+
where: { id: messageId },
|
|
319
|
+
data: {
|
|
320
|
+
content,
|
|
321
|
+
status: JobStatus.CANCELLED,
|
|
322
|
+
...(options.meta !== undefined && {
|
|
323
|
+
meta: options.meta,
|
|
324
|
+
}),
|
|
325
|
+
},
|
|
326
|
+
include: {
|
|
327
|
+
attachments: true,
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
logger.info('AI message cancelled', {
|
|
331
|
+
messageId: updated.id,
|
|
332
|
+
conversationId: updated.conversationId,
|
|
333
|
+
contentLength: content.length,
|
|
334
|
+
});
|
|
335
|
+
const senderInfo = buildAISenderInfo(options.customSender);
|
|
336
|
+
try {
|
|
337
|
+
await pusher.trigger(chatChannel(updated.conversationId), 'message-updated', {
|
|
338
|
+
id: updated.id,
|
|
339
|
+
content: updated.content,
|
|
340
|
+
senderId: updated.senderId,
|
|
341
|
+
conversationId: updated.conversationId,
|
|
342
|
+
status: updated.status,
|
|
343
|
+
createdAt: updated.createdAt,
|
|
344
|
+
sender: senderInfo,
|
|
345
|
+
mentionedUserIds: [],
|
|
346
|
+
meta: updated.meta ?? {},
|
|
347
|
+
attachments: updated.attachments.map((attachment) => ({
|
|
348
|
+
id: attachment.id,
|
|
349
|
+
attachmentId: attachment.id,
|
|
350
|
+
name: attachment.name,
|
|
351
|
+
type: attachment.type,
|
|
352
|
+
size: attachment.size,
|
|
353
|
+
path: attachment.path,
|
|
354
|
+
})),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch (broadcastError) {
|
|
358
|
+
logger.error('Failed to broadcast cancelled AI message:', {
|
|
359
|
+
error: broadcastError,
|
|
360
|
+
messageId,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
logger.error('Failed to mark AI message as cancelled:', {
|
|
366
|
+
error,
|
|
367
|
+
messageId,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
309
371
|
/**
|
|
310
372
|
* Flip a PENDING AI message to FAILED and broadcast the status change.
|
|
311
373
|
* Does NOT throw — failure paths in the pipelines call this in catch blocks
|
|
@@ -313,6 +375,19 @@ export async function completePendingAIMessage(messageId, content, options = {})
|
|
|
313
375
|
*/
|
|
314
376
|
export async function failPendingAIMessage(messageId, options = {}) {
|
|
315
377
|
try {
|
|
378
|
+
const current = await prisma.message.findUnique({
|
|
379
|
+
where: { id: messageId },
|
|
380
|
+
select: { status: true },
|
|
381
|
+
});
|
|
382
|
+
// A message the user already cancelled must stay CANCELLED — late
|
|
383
|
+
// failures from the aborted pipeline are a consequence of the cancel.
|
|
384
|
+
if (current?.status === JobStatus.CANCELLED) {
|
|
385
|
+
logger.info('Skipping FAILED flip; AI message already cancelled', {
|
|
386
|
+
messageId,
|
|
387
|
+
reason: options.reason,
|
|
388
|
+
});
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
316
391
|
const updated = await prisma.message.update({
|
|
317
392
|
where: { id: messageId },
|
|
318
393
|
data: { status: JobStatus.FAILED },
|
|
@@ -489,4 +564,4 @@ export function estimateTokenCount(text) {
|
|
|
489
564
|
return Math.ceil(text.length / 4);
|
|
490
565
|
}
|
|
491
566
|
//# sourceMappingURL=inference.js.map
|
|
492
|
-
//# debugId=
|
|
567
|
+
//# debugId=ba92dc8c-6ba8-5d95-a027-50c47894fcc3
|