Bigger decks: pick up to 30 activities, built in batches
The create wizard stopped at 15 activities because the API, the prompt and the salvage path all capped at 18: one reply must be one valid JSON object, and past ~18 activities models truncate or drop cards. Raising the cap alone would have shipped decks that came back short. - The count picker offers 8 / 10 / 12 / 15 / 20 / 30; a deck's "add more" row gained +15. The help line says bigger decks take longer. - /api/generate accepts up to 30 (FREEZMO_DEFAULT_ACTIVITY_COUNT now clamps to 30 as well) and sizes its overall deadline from the number of model calls instead of a fixed two. - generateActivities splits anything above 18 evenly across calls (30 → 15 + 15, 25 → 13 + 12) and merges them into one deck. The first call keeps the "add to this deck" contract; later calls are told the title, the types already used and the topics already covered. A normalised content signature drops a card that repeats an earlier one, so the same idea never ships twice. requested/generated still travel in the stream meta. - phase1-test: a stub Ollama answers two 15-card batches (the second repeats one card on purpose) → two calls, the even split, the "already covered" prompt, 29 merged cards, the duplicate shipped once, title from the first reply, and count 31 answered 400 (59 checks). - wizard-test: the picker offers 30, the wizard sends count: 30, and the 30-card deck is stored and opened (99 checks). Version 0.8.4, SW v106.
This commit is contained in:
parent
705808d45a
commit
e3b7bbbd6c
13 changed files with 345 additions and 46 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import { extractNotes, generateActivities, notesToText, type PipelineStage } from "@/lib/ai";
|
||||
import { activityBatches, extractNotes, generateActivities, notesToText, type PipelineStage } from "@/lib/ai";
|
||||
import { getServerConfig, resolveModelName } from "@/lib/config";
|
||||
import { INERT_OLLAMA_AUTH, resolveModelTarget } from "@/lib/providers-server";
|
||||
import { friendlyErrorMessage, OllamaError } from "@/lib/ollama";
|
||||
|
|
@ -26,7 +26,8 @@ const requestSchema = z.object({
|
|||
images: z.array(dataUrlSchema(MAX_IMAGE_CHARS)).max(16).optional(),
|
||||
text: z.string().max(120_000).optional(),
|
||||
difficulty: difficultySchema.default("medium"),
|
||||
count: z.number().int().min(4).max(18).optional(),
|
||||
/** One deck; a big count is built in several model calls (lib/ai.ts). */
|
||||
count: z.number().int().min(4).max(30).optional(),
|
||||
focus: z.string().max(300).optional(),
|
||||
/** Language the deck must be written in (usually detected by the vision step). */
|
||||
language: z.string().max(60).optional(),
|
||||
|
|
@ -129,8 +130,10 @@ export async function POST(request: Request) {
|
|||
const requestedCount = count ?? config.defaultActivityCount;
|
||||
const encode = encoder();
|
||||
const abort = new AbortController();
|
||||
// A single hard deadline for the whole pipeline (two sequential model calls).
|
||||
const globalTimer = setTimeout(() => abort.abort(), config.timeoutMs * 2);
|
||||
// A single hard deadline for the whole pipeline: the vision step (when there
|
||||
// are photos) plus one model call per activity batch.
|
||||
const modelCalls = activityBatches(requestedCount).length + 1;
|
||||
const globalTimer = setTimeout(() => abort.abort(), config.timeoutMs * modelCalls);
|
||||
const onRequestAbort = () => abort.abort();
|
||||
if (request.signal.aborted) abort.abort();
|
||||
else request.signal.addEventListener("abort", onRequestAbort, { once: true });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue