Initial commit: AI-driven visual novel scaffold

- Monorepo (pnpm workspace): apps/web + packages/{types,ai-client,engine}
- Next.js 16 web app with three-stage AI orchestration
- Three independently configurable providers: text LLM, image generator, vision model
- Warm minimalist editorial UI design
- One-click Vercel deploy ready

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
yuanzonghao
2026-05-09 13:29:58 +08:00
commit cbd95bbea2
45 changed files with 1855 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
import type {
EngineConfig,
InteractRequest,
InteractResponse,
Session,
StartRequest,
StartResponse,
} from "@dada/types";
import { annotateClick } from "./annotate";
import { direct } from "./director";
import { render } from "./renderer";
import { interpret } from "./vision";
function newSessionId(): string {
return `s_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}
export async function startSession(
config: EngineConfig,
req: StartRequest,
): Promise<StartResponse> {
const session: Session = {
id: newSessionId(),
createdAt: Date.now(),
worldSetting: req.worldSetting.trim(),
styleGuide: req.styleGuide.trim(),
history: [],
};
const frame = await direct(config.text, session);
const imageBase64 = await render(config.image, frame, session.styleGuide);
return {
sessionId: session.id,
frame,
imageBase64,
};
}
export async function takeTurn(
config: EngineConfig,
req: InteractRequest,
): Promise<InteractResponse> {
const annotated = await annotateClick(req.prevImageBase64, req.click);
const lastFrame = req.session.history.at(-1)?.frame;
const uiElements = lastFrame?.uiElements ?? [];
const intent = await interpret(config.vision, annotated, uiElements);
const updatedSession: Session = {
...req.session,
history: req.session.history.map((entry, idx, arr) =>
idx === arr.length - 1 ? { ...entry, click: req.click, intent } : entry,
),
};
const nextFrame = await direct(config.text, updatedSession);
const nextImage = await render(
config.image,
nextFrame,
updatedSession.styleGuide,
);
return {
session: updatedSession,
frame: nextFrame,
imageBase64: nextImage,
intent,
};
}