Files
yuanzonghao 6f8125570a feat(play): always generate new scene for freeform text input + enhance insert-beat
User feedback: custom interactions rarely produce new story content because
the classifier heavily biased toward insert-beat (single reaction, no scene
change). Three changes to fix this:

1. Freeform text input now always triggers a full scene generation (skips
   the classify step entirely) — users who type expect the story to advance.

2. Vision (background click) classifier de-biased: prompt now favors
   change-scene when uncertain, and the code fallback flipped from
   insert-beat to change-scene. insert-beat narrowed to pure observation.

3. Insert-beat enhanced: generates 1-3 beats (was 1) with follow-up
   choices (was: loop back to original beat). Even when vision classifies
   as insert-beat, the player gets richer content and new options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-24 18:36:35 +08:00

40 lines
1.1 KiB
TypeScript

import { interpretClick } from "@infiplot/ai-client";
import type {
ClickIntent,
ProviderConfig,
Scene,
VisionClassify,
} from "@infiplot/types";
import { parseJsonLoose } from "./jsonParser";
import { VISION_SYSTEM_PROMPT, buildVisionUserPrompt } from "./prompts";
export type VisionInterpretation = {
intent: ClickIntent;
classify: VisionClassify;
};
export async function interpret(
config: ProviderConfig,
annotatedImageBase64: string,
scene: Scene | null,
): Promise<VisionInterpretation> {
const userPrompt = `${VISION_SYSTEM_PROMPT}\n\n${buildVisionUserPrompt(scene)}`;
const raw = await interpretClick(config, annotatedImageBase64, userPrompt);
const parsed = parseJsonLoose<{
freeformAction?: string;
classify?: string;
reasoning?: string;
}>(raw);
const classify: VisionClassify =
parsed.classify === "insert-beat" ? "insert-beat" : "change-scene";
return {
intent: {
freeformAction: parsed.freeformAction?.trim() || "玩家点了画面,但意图不明",
reasoning: parsed.reasoning?.trim() || "",
},
classify,
};
}