feat(web): AI 立项方案生成+预填(种子门控 + 按字段接受)
向导阶段(project 未建)一键推演结构化书级蓝图预填立项向导。 - 新 SPEC project_plan_spec(analyst 档,纯预览 reads/writes=())+ schema ProjectPlanResult(书名候选 + 时空背景/叙事结构/故事核心/结局设计/基调, 全字段默认值守解析韧性)+ 注册 SCHEMA_CATALOG;计数三处 21→22 + regen golden。 - 端点 POST /skills/project-plan/generate(不带 project 前缀,绕开 toolbox 404): 请求体序列化向导草稿为 project_context,复用 build_brief_context + run_generator; 种子门控(缺 genre/logline→422);请求 schema 加 max_length 上界。 - run_generator/_build_request 的 project_id 放宽 uuid.UUID|None(向导无 project)。 - 前端 wizard.ts 加 mapPlanResultToWizardForm(错配字段折进 premise 不静默丢)+ applyPlanPatch(仅回填空字段、保护已编辑)+ useProjectPlan hook + PlanAssistant。
This commit is contained in:
59
apps/web/lib/wizard/useProjectPlan.ts
Normal file
59
apps/web/lib/wizard/useProjectPlan.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { useToast } from "@/components/Toast";
|
||||
import { api } from "@/lib/api/client";
|
||||
import { generationErrorMessage } from "@/lib/generation/cards";
|
||||
import type {
|
||||
ProjectPlanGenerateRequest,
|
||||
ProjectPlanView,
|
||||
} from "@/lib/api/types";
|
||||
|
||||
export type ProjectPlanStatus = "idle" | "generating" | "done" | "error";
|
||||
|
||||
export interface UseProjectPlan {
|
||||
status: ProjectPlanStatus;
|
||||
plan: ProjectPlanView | null;
|
||||
generate: (seed: ProjectPlanGenerateRequest) => Promise<void>;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
// AI 立项方案生成器:POST /skills/project-plan/generate → 结构化方案预览(不入库)。
|
||||
// 向导阶段调用(project 未建);种子门控在后端亦校验(缺 genre/logline → 422)。
|
||||
export function useProjectPlan(): UseProjectPlan {
|
||||
const [status, setStatus] = useState<ProjectPlanStatus>("idle");
|
||||
const [plan, setPlan] = useState<ProjectPlanView | null>(null);
|
||||
const toast = useToast();
|
||||
|
||||
const generate = useCallback<UseProjectPlan["generate"]>(
|
||||
async (seed) => {
|
||||
setStatus("generating");
|
||||
setPlan(null);
|
||||
try {
|
||||
const { data, error } = await api.POST(
|
||||
"/skills/project-plan/generate",
|
||||
{ body: seed },
|
||||
);
|
||||
if (error || !data) {
|
||||
setStatus("error");
|
||||
toast(generationErrorMessage(error), "error");
|
||||
return;
|
||||
}
|
||||
setPlan(data);
|
||||
setStatus("done");
|
||||
} catch {
|
||||
setStatus("error");
|
||||
toast("生成请求异常,请检查网络。", "error");
|
||||
}
|
||||
},
|
||||
[toast],
|
||||
);
|
||||
|
||||
const reset = useCallback((): void => {
|
||||
setStatus("idle");
|
||||
setPlan(null);
|
||||
}, []);
|
||||
|
||||
return { status, plan, generate, reset };
|
||||
}
|
||||
Reference in New Issue
Block a user