62 lines
2.6 KiB
TypeScript
62 lines
2.6 KiB
TypeScript
import type { NextRequest } from 'next/server';
|
|
import { readCourseRecordReconciled } from '@/lib/course-framework/store';
|
|
import { authorizeLearningRuntime, runtimeUnauthorized } from '@/lib/makelore-runtime/auth';
|
|
import { LEARNING_GENERATION_CONTRACT_VERSION } from '@/lib/makelore-runtime/generation-request';
|
|
import { isValidClassroomJobId, readClassroomGenerationJob } from '@/lib/server/classroom-job-store';
|
|
|
|
function largeCourseProgress(status: string, succeeded: number, total: number): number {
|
|
if (status === 'completed') return 100;
|
|
if (status === 'framework_ready') return 25;
|
|
if (status === 'framework_generating') return 10;
|
|
if (status === 'queued') return 0;
|
|
if (total > 0) return Math.min(99, Math.round(25 + (succeeded / total) * 75));
|
|
return 0;
|
|
}
|
|
|
|
export async function GET(request: NextRequest, context: { params: Promise<{ jobId: string }> }) {
|
|
if (!authorizeLearningRuntime(request)) return runtimeUnauthorized();
|
|
const { jobId } = await context.params;
|
|
const owner = request.headers.get('x-owner-user-id')?.trim();
|
|
if (!owner || !isValidClassroomJobId(jobId)) return Response.json({ error: 'invalid_request' }, { status: 400 });
|
|
const job = await readClassroomGenerationJob(jobId);
|
|
if (job) {
|
|
if (job.ownerPrincipalId !== owner) return Response.json({ error: 'job_not_found' }, { status: 404 });
|
|
return Response.json({
|
|
contractVersion: LEARNING_GENERATION_CONTRACT_VERSION,
|
|
jobId,
|
|
mode: 'single',
|
|
status: job.status,
|
|
step: job.step,
|
|
progress: job.progress,
|
|
message: job.message,
|
|
scenesGenerated: job.scenesGenerated,
|
|
totalScenes: job.totalScenes,
|
|
courseId: job.result?.classroomId,
|
|
error: job.error,
|
|
done: ['succeeded', 'failed', 'cancelled'].includes(job.status),
|
|
});
|
|
}
|
|
|
|
const course = await readCourseRecordReconciled(jobId);
|
|
if (!course || course.ownerPrincipalId !== owner) {
|
|
return Response.json({ error: 'job_not_found' }, { status: 404 });
|
|
}
|
|
const succeeded = course.modules.filter((module) => module.status === 'succeeded').length;
|
|
const total = course.modules.length;
|
|
return Response.json({
|
|
contractVersion: LEARNING_GENERATION_CONTRACT_VERSION,
|
|
jobId,
|
|
mode: 'large',
|
|
status: course.status,
|
|
step: course.status,
|
|
progress: largeCourseProgress(course.status, succeeded, total),
|
|
message:
|
|
course.status === 'framework_ready'
|
|
? 'Course framework is ready for operations review'
|
|
: undefined,
|
|
courseId: course.id,
|
|
error: course.error,
|
|
done: ['completed', 'failed', 'cancelled'].includes(course.status),
|
|
});
|
|
}
|