Phase 3: Check my work, follow-ups and turn-into-deck
Check my work (third homework mode) - One model call with its own system prompt marks the student's own attempt: verdict, what's right, each issue with why + fix, and the corrected version that keeps everything the student got right. Unasked-for extras are never errors. The attempt is typed/pasted (photos of handwriting are documented as unsupported) and stored in the record so Redo re-checks the same work. - Server: mode "check" + solution on POST /api/homework (zod, 400 server.needSolution without one) and the same NDJSON stream; new checkHomework() pipeline with repair-once validation. Follow-ups - New POST /api/homework/refine (plain JSON, RATE_LIMIT_REFINE, zod, auth before body): shorter / more detail / explain, plain text back, language preserved. - Shorter + More detail + Original rewrite the finished answer and the corrected version in place (FollowUpBar); every guide step has Explain step N differently; failed calls say so without losing text. Turn into a study deck - Any result hands its content (answer, corrected version or assembled guide) to New deck through a one-shot sessionStorage seed with the options step pre-filled. UI - Phone step 2 gains the third card: tapping it reveals the solution field + submit; desktop has three cards and the solution field shows with the mode. Homework history labels and share/card previews cover the new mode. Verified: new phase-3 suite 20/20 against a stub Ollama (check payload, missing-solution 400, refine validation, phone + desktop check flows, shorter follow-up with restore, guide explain, deck hand-off) plus regression 74/74, mobile 52/52, declutter 116/116, wizard 80/80, animation 8/8, native 35/35, phase1 38/38, phase2 43/43, i18n 25/25. Key parity 734/734. Lint + build clean. SW freezmo-v27.
This commit is contained in:
parent
a8a8bc0477
commit
4513364019
22 changed files with 947 additions and 56 deletions
74
lib/ai.ts
74
lib/ai.ts
|
|
@ -9,13 +9,17 @@ import { needsLanguageRepair } from "./language";
|
|||
import {
|
||||
buildGenerationUserPrompt,
|
||||
buildGradingUserPrompt,
|
||||
buildHomeworkCheckUserPrompt,
|
||||
buildHomeworkGuideUserPrompt,
|
||||
buildHomeworkMakeUserPrompt,
|
||||
buildRefineUserPrompt,
|
||||
buildRepairPrompt,
|
||||
GENERATION_SYSTEM_PROMPT,
|
||||
GRADING_SYSTEM_PROMPT,
|
||||
HOMEWORK_CHECK_SYSTEM_PROMPT,
|
||||
HOMEWORK_GUIDE_SYSTEM_PROMPT,
|
||||
HOMEWORK_MAKE_SYSTEM_PROMPT,
|
||||
REFINE_SYSTEM_PROMPT,
|
||||
VISION_SYSTEM_PROMPT,
|
||||
VISION_USER_INSTRUCTION,
|
||||
} from "./prompts";
|
||||
|
|
@ -23,12 +27,14 @@ import {
|
|||
extractedNotesSchema,
|
||||
generatedActivitySchema,
|
||||
gradeResultSchema,
|
||||
homeworkCheckSchema,
|
||||
homeworkMakeSchema,
|
||||
homeworkStepSchema,
|
||||
type Difficulty,
|
||||
type ExtractedNotes,
|
||||
type GeneratedActivity,
|
||||
type GradeResult,
|
||||
type HomeworkCheck,
|
||||
type HomeworkGuide,
|
||||
type HomeworkMake,
|
||||
} from "./schemas";
|
||||
|
|
@ -502,6 +508,74 @@ export async function buildHomeworkGuide(input: {
|
|||
return value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Check my work */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const HOMEWORK_CHECK_SHAPE_HINT = `{"title":"...","language":"English name of the language used","verdict":"1-2 sentences","correct":["what is right"],"wrong":[{"issue":"...","why":"...","fix":"..."}],"corrected":"the student's solution with every mistake fixed"}`;
|
||||
|
||||
/** Mode 3: mark the student's own attempt and hand back a corrected version. */
|
||||
export async function checkHomework(input: {
|
||||
model: string;
|
||||
auth: OllamaAuth;
|
||||
assignment: string;
|
||||
solution: string;
|
||||
language?: string;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<HomeworkCheck> {
|
||||
const { value } = await runJsonStep<HomeworkCheck>({
|
||||
model: input.model,
|
||||
auth: input.auth,
|
||||
system: HOMEWORK_CHECK_SYSTEM_PROMPT,
|
||||
user: buildHomeworkCheckUserPrompt({
|
||||
assignment: input.assignment,
|
||||
solution: input.solution,
|
||||
language: input.language,
|
||||
}),
|
||||
validate: (parsed) => {
|
||||
const result = homeworkCheckSchema.safeParse(parsed);
|
||||
if (!result.success) return { ok: false, error: summariseZodError(result.error) };
|
||||
if (!result.data.corrected.trim()) return { ok: false, error: "The corrected field is empty." };
|
||||
return { ok: true, value: result.data };
|
||||
},
|
||||
shapeHint: HOMEWORK_CHECK_SHAPE_HINT,
|
||||
label: "Checking the attempt",
|
||||
signal: input.signal,
|
||||
temperature: 0.2,
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Follow-ups: rewrite one finished piece (shorter / more detail / explain). */
|
||||
export async function refineHomeworkText(input: {
|
||||
model: string;
|
||||
auth: OllamaAuth;
|
||||
instruction: "shorter" | "more" | "explain";
|
||||
text: string;
|
||||
context?: string;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<string> {
|
||||
const result = await ollamaChat({
|
||||
model: input.model,
|
||||
auth: input.auth,
|
||||
json: false,
|
||||
signal: input.signal,
|
||||
temperature: 0.4,
|
||||
messages: [
|
||||
{ role: "system", content: REFINE_SYSTEM_PROMPT },
|
||||
{
|
||||
role: "user",
|
||||
content: buildRefineUserPrompt({
|
||||
instruction: input.instruction,
|
||||
text: input.text,
|
||||
context: input.context,
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
return result.content.trim();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Helpers */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue