feat: refine agent workflow flow
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-17 18:23:32 +08:00
parent fbbc63f865
commit 64cb485dfa
13 changed files with 1427 additions and 408 deletions

View File

@ -171,6 +171,57 @@ export function AgentWorkflowSettingsClient() {
</Card>
) : (
<div className="space-y-5">
<Card>
<CardHeader>
<CardTitle>基础下拉配置</CardTitle>
<CardDescription>
工作流左侧“品牌 / 店铺”采用后台配置的候选列表,前台支持输入关键字匹配下拉选择。
</CardDescription>
</CardHeader>
<CardContent className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label>品牌列表</Label>
<Textarea
value={(config.inputOptions?.brands || []).join("\n")}
onChange={(event) =>
setConfig((prev) => ({
...prev,
inputOptions: {
brands: event.target.value
.split("\n")
.map((item) => item.trim())
.filter(Boolean),
stores: prev.inputOptions?.stores || [],
},
}))
}
rows={10}
placeholder={"例如:\n宜家\n顾家家居\n林氏家居"}
/>
</div>
<div className="space-y-2">
<Label>店铺列表</Label>
<Textarea
value={(config.inputOptions?.stores || []).join("\n")}
onChange={(event) =>
setConfig((prev) => ({
...prev,
inputOptions: {
brands: prev.inputOptions?.brands || [],
stores: event.target.value
.split("\n")
.map((item) => item.trim())
.filter(Boolean),
},
}))
}
rows={10}
placeholder={"例如:\n天猫旗舰店\n京东自营店\n抖音官方店"}
/>
</div>
</CardContent>
</Card>
{sortedSteps.map((step) => (
<Card key={step.key}>
<CardHeader>

View File

@ -517,6 +517,12 @@ const updateSchema = z.object({
.optional(),
agentWorkflowUiConfig: z
.object({
inputOptions: z
.object({
brands: z.array(z.string().trim().min(1).max(64)).max(300).optional(),
stores: z.array(z.string().trim().min(1).max(64)).max(300).optional(),
})
.optional(),
steps: z
.array(
z.object({

View File

@ -5,6 +5,7 @@ import { useRouter, useParams, useSearchParams } from "next/navigation";
import useSWR from "swr";
import {
AlertCircle,
ArrowLeft,
Save,
Undo2,
Redo2,
@ -73,7 +74,10 @@ import {
defaultAgentWorkflowUiConfig,
normalizeAgentWorkflowUiConfig,
} from "@/lib/agents/workflow-ui-config";
import { buildAgentWorkflowComposerContext } from "@/lib/agents/workflow-composer";
import {
buildAgentWorkflowComposerContext,
getAgentWorkflowProgress,
} from "@/lib/agents/workflow-composer";
import type {
AgentWorkflowComposerContext,
AgentWorkflowPersistedState,
@ -161,6 +165,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
Partial<Record<AgentWorkflowStepKey, string>>
>({});
const [selectedAgentPresetId, setSelectedAgentPresetId] = useState<string | null>(null);
const [currentAgentStage, setCurrentAgentStage] = useState<"workflow" | "mode">("workflow");
const [workflowHydrationSource, setWorkflowHydrationSource] = useState<
"pending" | "project" | "local" | "empty"
>("pending");
@ -286,6 +291,9 @@ export default function CanvasEditorPage({ params }: PageProps) {
setSelectedAgentPresetId(
String(persistedWorkflow.selectedAgentPresetId || "").trim() || null
);
setCurrentAgentStage(
persistedWorkflow.currentStage === "mode" ? "mode" : "workflow"
);
setWorkflowHydrationSource("project");
} else {
setWorkflowHydrationSource("empty");
@ -336,6 +344,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
},
selections: workflowSelections,
selectedAgentPresetId: selectedAgentPresetId || null,
currentStage: currentAgentStage,
};
return {
@ -364,6 +373,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
});
setWorkflowSelections(parsed.selections || {});
setSelectedAgentPresetId(String(parsed.selectedAgentPresetId || "").trim() || null);
setCurrentAgentStage(parsed.currentStage === "mode" ? "mode" : "workflow");
} catch (error) {
console.warn("[Canvas] Failed to hydrate workflow state from localStorage:", error);
} finally {
@ -381,6 +391,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
inputs: workflowInputs,
selections: workflowSelections,
selectedAgentPresetId,
currentAgentStage,
})
);
} catch (error) {
@ -392,6 +403,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
workflowSelections,
workflowStorageKey,
selectedAgentPresetId,
currentAgentStage,
]);
const persistCanvasState = useCallback(
@ -827,6 +839,14 @@ export default function CanvasEditorPage({ params }: PageProps) {
selections: workflowSelections,
});
}, [resolvedWorkflowUiConfig, workflowInputs, workflowSelections]);
const workflowProgress = useMemo(
() =>
getAgentWorkflowProgress({
config: resolvedWorkflowUiConfig || defaultAgentWorkflowUiConfig,
selections: workflowSelections,
}),
[resolvedWorkflowUiConfig, workflowSelections]
);
if (isLoading) {
return (
@ -883,8 +903,8 @@ export default function CanvasEditorPage({ params }: PageProps) {
<div className="absolute inset-0 flex pt-[72px]">
<div className="min-w-0 flex-1 border-r bg-white dark:bg-zinc-950">
<div className="grid h-full grid-rows-[minmax(0,1fr)_minmax(0,1fr)]">
<div className="min-h-0 border-b">
{currentAgentStage === "workflow" ? (
<div className="h-full">
<AgentWorkflowPanel
embedded
config={resolvedWorkflowUiConfig}
@ -892,6 +912,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
onInputsChange={setWorkflowInputs}
selections={workflowSelections}
onSelectionsChange={setWorkflowSelections}
onNextStep={() => setCurrentAgentStage("mode")}
onReset={() => {
setWorkflowInputs({
primarySku: "",
@ -901,17 +922,56 @@ export default function CanvasEditorPage({ params }: PageProps) {
});
setWorkflowSelections({});
setSelectedAgentPresetId(null);
setCurrentAgentStage("workflow");
}}
/>
</div>
<div className="min-h-0">
) : (
<div className="flex h-full flex-col">
<div className="border-b p-4">
<div className="flex items-start justify-between gap-3">
<div>
<div className="flex items-center gap-2 text-sm font-semibold">
<Wand2 className="h-4 w-4 text-amber-500" />
生图模式
</div>
<div className="mt-1 text-xs text-muted-foreground">
先完成第一步工作流,再选择具体的生图模式模板。
</div>
<div className="mt-2 inline-flex items-center rounded-full bg-muted px-2.5 py-1 text-[11px] text-muted-foreground">
第 2 步 / 2 步
</div>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => setCurrentAgentStage("workflow")}
>
<ArrowLeft className="mr-1 h-4 w-4" />
返回上一步
</Button>
</div>
{!workflowProgress.isComplete ? (
<div className="mt-3 rounded-xl border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
第一步尚未完成,请先返回补全工作流环节。
</div>
) : null}
</div>
<div className="min-h-0 flex-1">
<AgentPresetPanel
embedded
selectedPresetId={selectedAgentPresetId}
onSelectPreset={setSelectedAgentPresetId}
title="生图模式"
description="选择生图模式后,右侧对话框会按其要求显示上传槽位"
searchPlaceholder="搜索生图模式"
publicTitle="公共生图模式"
privateTitle="我的生图模式"
/>
</div>
</div>
)}
</div>
<div

View File

@ -25,12 +25,22 @@ interface AgentPresetPanelProps {
selectedPresetId?: string | null;
onSelectPreset: (presetId: string | null) => void;
embedded?: boolean;
title?: string;
description?: string;
searchPlaceholder?: string;
publicTitle?: string;
privateTitle?: string;
}
export function AgentPresetPanel({
selectedPresetId,
onSelectPreset,
embedded = false,
title = "智能体",
description = "选择智能体后,右侧对话框会按其要求显示上传槽位",
searchPlaceholder = "搜索智能体",
publicTitle = "公共智能体",
privateTitle = "我的智能体",
}: AgentPresetPanelProps) {
const [keyword, setKeyword] = useState("");
const [categoryFilters, setCategoryFilters] = useState({
@ -163,10 +173,10 @@ export function AgentPresetPanel({
<div>
<div className="flex items-center gap-2 text-sm font-semibold">
<Sparkles className="h-4 w-4 text-amber-500" />
智能体
{title}
</div>
<div className="mt-1 text-xs text-muted-foreground">
选择智能体后,右侧对话框会按其要求显示上传槽位
{description}
</div>
</div>
<Button size="sm" onClick={() => setShowCreateDialog(true)}>
@ -175,7 +185,7 @@ export function AgentPresetPanel({
</Button>
</div>
<Input
placeholder="搜索智能体"
placeholder={searchPlaceholder}
value={keyword}
onChange={(event) => setKeyword(event.target.value)}
/>
@ -185,7 +195,7 @@ export function AgentPresetPanel({
<div className="space-y-5 p-4">
<section className="space-y-3">
<div className="space-y-3">
<div className="text-sm font-medium">公共智能体</div>
<div className="text-sm font-medium">{publicTitle}</div>
<div className="grid grid-cols-1 gap-2 md:grid-cols-2">
<Select
value={categoryFilters.productCategory || "__none__"}
@ -299,7 +309,7 @@ export function AgentPresetPanel({
</section>
<section className="space-y-3">
<div className="text-sm font-medium">我的智能体</div>
<div className="text-sm font-medium">{privateTitle}</div>
{isLoading ? null : filteredPrivatePresets.length > 0 ? (
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3">
{filteredPrivatePresets.map((preset) => (

View File

@ -1,7 +1,7 @@
"use client";
import { useMemo } from "react";
import { Copy, RotateCcw, Sparkles } from "lucide-react";
import { ArrowRight, Copy, RotateCcw, Sparkles } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -34,6 +34,7 @@ interface AgentWorkflowPanelProps {
onSelectionsChange: (next: Partial<Record<AgentWorkflowStepKey, string>>) => void;
onReset?: () => void;
embedded?: boolean;
onNextStep?: () => void;
}
function buildSelectionSummary(params: {
@ -69,7 +70,16 @@ export function AgentWorkflowPanel({
onSelectionsChange,
onReset,
embedded = false,
onNextStep,
}: AgentWorkflowPanelProps) {
const brandOptions = useMemo(
() => config?.inputOptions?.brands || defaultAgentWorkflowUiConfig.inputOptions?.brands || [],
[config?.inputOptions?.brands]
);
const storeOptions = useMemo(
() => config?.inputOptions?.stores || defaultAgentWorkflowUiConfig.inputOptions?.stores || [],
[config?.inputOptions?.stores]
);
const resolvedConfig = useMemo(() => {
const source = config?.steps?.length ? config : defaultAgentWorkflowUiConfig;
return {
@ -181,15 +191,32 @@ export function AgentWorkflowPanel({
onInputsChange({ ...inputs, brand: event.target.value })
}
placeholder="品牌"
list="agent-workflow-brand-options"
/>
<datalist id="agent-workflow-brand-options">
{brandOptions.map((item) => (
<option key={item} value={item} />
))}
</datalist>
<Input
value={inputs.store}
onChange={(event) =>
onInputsChange({ ...inputs, store: event.target.value })
}
placeholder="店铺"
list="agent-workflow-store-options"
/>
<datalist id="agent-workflow-store-options">
{storeOptions.map((item) => (
<option key={item} value={item} />
))}
</datalist>
</div>
{(brandOptions.length > 0 || storeOptions.length > 0) && (
<div className="text-xs text-muted-foreground">
品牌和店铺支持输入关键字匹配下拉选择,候选列表由系统设置配置。
</div>
)}
</section>
{resolvedConfig.steps.map((step) => (
@ -307,6 +334,14 @@ export function AgentWorkflowPanel({
placeholder="选择左侧工作流后,这里会自动生成结构化 Prompt。"
className="resize-none bg-background"
/>
{onNextStep ? (
<div className="flex justify-end">
<Button type="button" onClick={onNextStep} disabled={!progress.isComplete}>
下一步:选择生图模式
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</div>
) : null}
</section>
</div>
</ScrollArea>

View File

@ -1361,6 +1361,55 @@ function extractFontWeight(value: string, fallback = "600"): string {
return matched[1] || fallback;
}
function sanitizeDetailImageModelPrompt(prompt: string): string {
const filteredLines = String(prompt || "")
.split(/\n+/)
.map((line) => line.trim())
.filter(Boolean)
.map((line) => {
if (
/^(字体规范|标题规范|副标题规范|正文规范|版式规范|安全区|留白节奏|Typography|Layout|Palette|固定字体锁定|固定副标题锁定|固定正文锁定|固定排版安全区|固定留白节奏)/i.test(
line
)
) {
return "";
}
return line;
})
.filter(Boolean);
let result = filteredLines.join("\n");
const literalReplacements: Array<[RegExp, string]> = [
[/画布固定(?:竖版)?\s*\d+\s*x\s*\d+\s*(?:像素|pixels?)。?/gi, "画布为竖版详情页构图。"],
[/尺寸固定\s*\d+\s*x\s*\d+\s*(?:像素|pixels?)。?/gi, "尺寸为竖版详情页比例。"],
[/输出为竖版电商详情图,尺寸固定\s*\d+\s*x\s*\d+\s*(?:像素|pixels?)。?/gi, "输出为竖版电商详情图。"],
[/y\s*=\s*\d+\s*[-~~]\s*\d+/gi, "顶部标题安全区"],
[/左右边距\s*\d+\s*px/gi, "左右留白充足"],
[/模块间距\s*\d+\s*px/gi, "模块间距均匀"],
[/标题和副标题间距\s*\d+\s*px/gi, "标题与副标题间距清晰"],
[/主标题\s*\d+\s*px[^,。;\n]*/gi, "主标题醒目突出"],
[/副标题\s*\d+\s*px[^,。;\n]*/gi, "副标题层级清晰"],
[/正文\s*\d+\s*px[^,。;\n]*/gi, "正文精简易读"],
[/商业摄影质感,留出清晰文案排版区,不要水印。?/gi, "商业摄影质感,留出清晰文字区域,不要水印。"],
];
for (const [pattern, replacement] of literalReplacements) {
result = result.replace(pattern, replacement);
}
result = result
.replace(/\b\d+\s*px\b/gi, "")
.replace(/[((]\s*顶部标题安全区\s*[))]/g, "顶部标题安全区")
.replace(/;{2,}/g, ";")
.replace(/。{2,}/g, "。")
.replace(/\s{2,}/g, " ")
.replace(/\n{3,}/g, "\n\n")
.trim();
return result;
}
function splitDetailKeywords(value: string, limit = 3): string[] {
const raw = String(value || "")
.split(/[\n,,、;;|]/)
@ -5928,7 +5977,7 @@ export function CanvasChatPanel({
),
);
const generationPrompt = [
const generationPrompt = sanitizeDetailImageModelPrompt([
promptText,
styleDirective ? `全局样式约束:${styleDirective}` : "",
screen?.screenType
@ -5963,7 +6012,7 @@ export function CanvasChatPanel({
: "要求:整套详情图风格统一,产品外观严格一致,主标题/副标题/正文字体与层级全套一致,商业摄影质感,排版区域清晰,标题不得包含“第X屏”。",
]
.filter(Boolean)
.join("\n\n");
.join("\n\n"));
const styleAnchorUrl =
index > 0 ? generatedImages[0]?.originalUrl || generatedImages[0]?.thumbnailUrl : null;
const generationReferenceImagesBase = [
@ -5976,12 +6025,13 @@ export function CanvasChatPanel({
promptOverride: string,
extraReferenceImages: string[] = []
): Promise<{ originalUrl: string; thumbnailUrl: string }> => {
const sanitizedPrompt = sanitizeDetailImageModelPrompt(promptOverride);
const generationReferenceImages = [
...generationReferenceImagesBase,
...extraReferenceImages,
].filter(Boolean);
const result = await requestCanvasImageGeneration({
prompt: promptOverride,
prompt: sanitizedPrompt,
model: modelForGeneration,
aspectRatio: "9:16",
imageSize: imageParams.imageSize,
@ -6092,7 +6142,9 @@ export function CanvasChatPanel({
for (let retry = 0; retry < DETAIL_SCREEN_REVIEW_MAX_ATTEMPTS; retry += 1) {
try {
const revisedPrompt = String(screenReviewResult?.revisedPrompt || "").trim();
const revisedPrompt = sanitizeDetailImageModelPrompt(
String(screenReviewResult?.revisedPrompt || "").trim()
);
const regenerated = await generateDetailFrame(revisedPrompt, [
firstPassImage.originalUrl || firstPassImage.thumbnailUrl,
]);

View File

@ -1,523 +1,528 @@
# AI详情生成(AGENT + 生图模型 + 可编程渲染)开发文档
# AI详情生成开发文档(当前实现版)
## 1. 文档目的
## 1. 文档定位
本文档用于落地一套稳定的 AI 详情生成系统:
本文档不再描述理想中的完整目标架构,而是基于当前仓库代码与前端交互,整理出一份可直接用于开发、联调、排查和运营说明的“当前实现版”文档。
- 保留现有传统生图模式(快速产图路线)
- 保留生图模型能力(画面创作、质感、场景)
- 用 AGENT 负责策划、文案、结构和审稿
- 用编程渲染保证版式统一和可编辑
- 支持用户切换两种模式(传统生图 / AGENT排版)
- 最终结果直接进入无限画布,支持手动改字、拖拽图标、单屏重生
适用范围:
目标是解决当前主要问题:生图模型理解偏差、全套风格不统一、失败不可控、返工成本高。
- 无限画布中的 `AI详情生成工作台`
- 前端入口与交互流程
- 当前已接入的后端 API
- `classic` 与 `agent_layout` 两种模式的真实差异
- 已上线能力、未上线能力、已知限制
如果后续要继续推进“项目化管理 / Layout QA / 14屏严格状态机 / 项目级 API”,请在本文件基础上新增“规划版”文档,不要再把目标方案和当前实现混写。
---
## 2. 核心结论与原则
## 2. 状态说明
### 2.1 核心结论
本文档中的状态标签含义如下:
不能只靠生图模型“整页一次生成”。推荐架构是:
`AGENT 策划 -> 分屏生成 -> 程序化合成 -> 画布可编辑 -> 审核回路`
同时保留现有传统生图链路,采用双路线并行:
- 路线 A:`传统生图模式`(保持现状,快速出图)
- 路线 B:`AGENT排版模式`(生图只负责画面,文字与排版交给程序)
### 2.2 设计原则
1. **模型出画面,代码定版式**
2. **背景锁定,前景可生**(避免模型重画结构)
3. **每屏可独立重试**(不整套重跑)
4. **所有输入输出可追溯**(项目、版本、日志、成本)
5. **画布内可编辑优先**(文字和图标非烤图)
6. **双模式可切换且互不影响**(老链路稳定,新链路增量上线)
- `已实现`:仓库中已有入口和主要逻辑,当前系统可走通
- `部分实现`:已有部分链路,但与原设计稿不完全一致
- `未实现`:文档中仅保留为后续规划,不应视为当前能力
---
## 3. 业务范围
## 3. 当前能力总览
## 3.1 本期范围
### 3.1 功能入口 `已实现`
- AI详情模式固定 14 屏流程(可配置)
- 每屏固定尺寸 `790x1300`
- 用户上传:
- 5 张产品图(必填)
- 1 张模特图(可用于卖家视角场景)
- 3 张搭配图(可选,触发关联销售屏)
- 输入业务信息:人群、场景、核心需求、SPU 等
- 自动生成详情文案与视觉版式
- 结果进入画布后可修改文字、拖拽图标、替换素材
- 自动存档、历史恢复、继续生成
- 入口位置:无限画布右侧聊天工作台中的 `AI详情生成`
- 前端主文件:`components/canvas/CanvasChatPanel.tsx`
- 用户可以选择两种模式:
- `classic`:传统生图
- `agent_layout`:AGENT排版
## 3.2 非本期范围
### 3.2 当前真实输入约束 `已实现`
- 移动端编辑体验优化
- 多人协同编辑冲突合并
- 自动电商平台一键上架
必填业务字段:
## 3.3 模式策略(新增)
- `targetAudience`
- `usageScenario`
- `coreNeed`
- `传统生图模式(classic)`
- 使用现有生图流程
- 保留当前用户习惯与响应节奏
- 适合快速尝试和低编辑需求场景
- `AGENT排版模式(agent_layout)`
- 生图模型只产出画面素材层,不产出文字排版
- AGENT + 程序完成文案结构、版式和 UI 统一
- 适合稳定量产、可编辑和可复用场景
- 前端必须提供模式切换,并把模式写入任务上下文,后端按模式分流 pipeline
当前前端强制素材要求:
- `5` 张产品图:必填
- `1` 张模特图:当前实现中必填
- `0-3` 张搭配图:可选
说明:
- 文档层面原本把模特图写成“可用于卖家视角场景”,但当前前端实现里它实际上是必填项。
- 如果没有模特图,前端会直接拦截,不会进入 AI 详情规划。
### 3.3 当前真实输出结构 `已实现`
当前 AI 详情一次生成的输出由两部分组成:
1. `详情主图分镜`
- 通过 `/api/canvas/detail-plan` 先规划
- 再逐屏调用生图接口
2. `买家评价与晒单`
- 在主图全部完成后由前端追加生成
- 不属于 `detail-plan` 主分镜返回本体
---
## 4. 技术架构
## 4. 当前系统里的真实流程
### 4.1 主流程概览 `已实现`
当前系统实际流程如下:
```mermaid
flowchart LR
A["用户输入(图片+业务信息)"] --> B["AGENT 规划器"]
B --> C["ScreenSpec 14屏结构化脚本"]
C --> D["生图编排器(逐屏调用模型)"]
D --> E["程序化合成器(背景/文案/图标)"]
E --> F["双总监审稿(设计+营销)"]
F -->|通过| G["写入S3/MinIO + DB版本"]
F -->|不通过| D
G --> H["画布落地(垂直排版)"]
H --> I["手动编辑(改字/拖拽/重生单屏)"]
A["用户填写brief并上传素材"] --> B["前端校验必填字段和素材"]
B --> C["POST /api/canvas/detail-plan"]
C --> D["返回 screens/prompts/globalStyle/preflight"]
D --> E["前端逐屏调用生图"]
E --> F{"generation_mode"}
F -->|classic| G["逐屏 detail-review 质检 + 可选二次修图"]
F -->|agent_layout| H["前端叠加可编辑文字层"]
G --> I["主图完成后追加评价晒图"]
H --> I
I --> J["写入画布节点 + 更新本地/数据库存档"]
```
双路线分流(逻辑):
### 4.2 关键特点
```mermaid
flowchart LR
U["用户选择模式"] --> M{"generation_mode"}
M -->|classic| C1["传统生图Pipeline"]
M -->|agent_layout| C2["AGENT排版Pipeline"]
C1 --> R["统一写入画布与历史记录"]
C2 --> R
```
- 当前没有“项目级任务状态机 API”
- 当前没有后端统一的 `/detail-projects/:projectId/generate`
- 当前没有 SSE 进度接口
- 进度条、占位图、逐屏生成状态全部在前端本地维护
---
## 5. 推荐开源技术选型
## 5. 两种模式的真实差异
## 5.1 画布编辑层
## 5.1 `classic` 传统生图模式 `已实现`
- `react-konva + konva`:用于画布图层编辑、拖拽、缩放、导出
- `Moveable` 或 `interact.js`:吸附对齐、参考线、间距控制
特点:
## 5.2 渲染层
- 生图模型直接生成整页详情图
- 提示词中会带标题、副标题、正文、FABE、排版说明
- 每屏生成后会调用 `/api/canvas/detail-review`
- 如果质检不通过,会基于 `revisedPrompt` 二次修图一次
- 主方案:HTML/CSS 模板 + Playwright 截图(最接近设计稿控制)
- 备选:`Satori + resvg-js`(高一致性服务端矢量渲染)
优点:
## 5.3 模型编排层
- 成图速度快
- 页面信息一次成型
- 继续使用当前生图供应商体系(支持路由和故障迁移)
- AGENT 负责:
- 详情策略规划
- Prompt 生成与优化
- 结果审稿和重试建议
限制:
## 5.4 可选参考(不直接引入)
- 文生图模型对文字和排版控制不稳定
- 容易出现文字失真、布局漂移、参数被画出来等问题
- Excalidraw:交互/白板体验参考
- Penpot:组件化设计体系参考
- tldraw:能力强,但许可证需谨慎评估
## 5.2 `agent_layout` AGENT排版模式 `已实现`
特点:
- 生图模型只生成画面层
- 明确禁止模型输出可见文字、数字、Logo、水印
- 画面生成完成后,前端在图片节点上叠加 3 个可编辑文字节点:
- 标题
- 副标题
- 正文
当前文字层位置:
- 标题:`y + 72`
- 副标题:`y + 214`
- 正文:`y + 304`
- 左边距:约画面宽度的 `7%`
优点:
- 文字可编辑
- 文案层级更统一
- 避免模型把整页文字烤死
限制:
- 当前文字层位置是前端固定模板,不是后端程序化版式引擎
- 当前 `agent_layout` 不走 `/api/canvas/detail-review`
- 当前没有“文字遮挡主体”的自动检测
---
## 6. 数据模型设计(数据库)
## 6. 屏数与完成条件
建议新增或扩展以下表(命名可按现有规范调整):
### 6.1 当前真实规则 `已实现`
## 6.1 `detail_projects`
当前主图分镜数不是固定 14 屏,而是动态值:
- `id`
- `user_id`
- `canvas_id`
- `spu`
- `demand_type`
- `project_name`(默认 `SPU+需求类型`)
- `status`(draft/planning/generating/reviewing/completed/failed)
- `generation_mode`(classic/agent_layout,默认 classic)
- `created_at` / `updated_at`
- 前端会从用户输入文本里解析 `X张 / X屏 / X页`
- 如果没解析到,默认 `14` 屏
- 后端会把数量限制在 `5-20`
- 如果上传了搭配图,会额外加 `1` 屏搭配展示
## 6.2 `detail_project_inputs`
### 6.2 当前真实完成条件 `已实现`
- `id`
- `project_id`
- `core_audience`
- `usage_scenarios`
- `core_needs`
- `selling_points`
- `tone_style`
- `extra_requirements`
- `raw_form_json`
当前“完成”并不是“必须满 14 屏”,而是:
## 6.3 `detail_assets`
- 本次 `detail-plan` 返回了多少条 `prompts`
- 前端就按多少屏去生成
- 当 `generatedImages.length === prompts.length` 时,主图阶段视为完成
- `id`
- `project_id`
- `asset_type`(product/model/combo/reference)
- `source_url`
- `storage_url`
- `width` / `height`
- `meta_json`
### 6.3 评价晒图的关系 `已实现`
## 6.4 `detail_screen_specs`
买家评价与晒单是主图完成后的追加产物:
- `id`
- `project_id`
- `screen_index`(1..14)
- `screen_type`
- `spec_json`(可编辑图层结构)
- `prompt_json`
- `status`
## 6.5 `detail_screen_renders`
- `id`
- `project_id`
- `screen_index`
- `version_no`
- `image_url`
- `thumb_url`
- `model_provider`
- `model_name`
- `cost_credits`
- `latency_ms`
- `review_score_design`
- `review_score_marketing`
- `review_notes`
## 6.6 `detail_generation_jobs`
- `id`
- `project_id`
- `job_type`(plan/generate/review/retry)
- `generation_mode`(classic/agent_layout)
- `progress`(0~100)
- `stage`(规划中/生成中/审稿中/完成)
- `error_code`
- `error_message`
- `started_at` / `finished_at`
## 6.7 现有聊天/消息表扩展(建议)
- 在会话或任务表增加 `generation_mode`
- 在消息元数据增加 `mode_snapshot`(防止切换模式导致历史重放错乱)
- 在生成记录增加 `resolved_pipeline`(最终实际执行链路)
- 默认追加 `3` 条评价方案
- 每条评价生成 `3` 张晒单图
- 不计入主图 `prompts.length`
---
## 7. ScreenSpec(核心协议)
## 7. 当前接口清单
AGENT 和渲染器之间只通过结构化协议通信,不直接拼字符串 UI。
## 7.1 已上线接口
```json
{
"projectId": "dp_xxx",
"canvasId": "cv_xxx",
"size": { "width": 790, "height": 1300 },
"globalStyle": {
"fontFamily": "PingFang SC",
"titleSize": 68,
"subtitleSize": 36,
"bodySize": 28,
"lineHeight": 1.35,
"palette": { "primary": "#5B4DFF", "text": "#111111" }
},
"screen": {
"index": 1,
"type": "hero_poster",
"copy": {
"name": "安敏裤",
"title": "安敏裤 | 敏宝整夜安睡不红屁屁",
"subtitle": "过敏体质宝宝专研,夜用安心不反渗"
},
"layers": [
{ "id": "bg", "kind": "backgroundImage", "editable": false, "src": "https://..." },
{ "id": "title", "kind": "text", "editable": true, "x": 56, "y": 120, "w": 678, "h": 180 },
{ "id": "badge", "kind": "icon", "editable": true, "x": 56, "y": 340, "w": 160, "h": 52 }
],
"gen": {
"needModelImage": true,
"prompt": "只生成产品前景和光效,不生成文字,不改背景结构",
"negativePrompt": "杂乱文字, 水印, logo"
}
}
}
```
### 1. `POST /api/canvas/detail-plan` `已实现`
---
作用:
## 8. 14屏生产流程(标准)
- 生成 AI 详情规划结果
- 返回:
- `summary`
- `prompts`
- `globalStyle`
- `skillFlow`
- `qualityChecks`
- `preflight`
- `screens`
- `generationMode`
1. 首屏海报(命名+核心需求一句话)
2. 用户痛点
3. 核心卖点机制
4. 卖点证据/参数
5. 场景 1(日常)
6. 场景 2(高频痛点)
7. 细节特写
8. 对比页
9. 使用方法
10. 搭配销售(用户上传搭配图时启用)
11. 买家评价 1(自动生成评价+3图)
12. 买家评价 2(可再次生成新2条)
13. 品牌背书/服务承诺
14. 收口 CTA
输入重点:
约束:必须完整到第 14 屏才能标记 `completed`。
- `prompt`
- `count`
- `generationMode`
- `referenceImages`
- `referenceImageNotes`
- `modelImageUrl`
- `bundleImageUrls`
- `brief`
---
### 2. `POST /api/canvas/detail-review` `已实现`
## 9. AGENT 职责拆分
作用:
## 9.1 Planner Agent(规划师)
- 对已经生成的单屏整页图做双总监质检
- 仅在 `classic` 模式下调用
- 解析输入信息和图片素材
- 生成 14 屏文案骨架与屏幕目标
- 生成命名(大白话、可记忆、带卖点)
返回重点:
## 9.2 Prompt Agent(生图导演)
- `pass`
- `score`
- `designDirectorScore`
- `marketingDirectorScore`
- `issues`
- `layoutFixes`
- `revisedPrompt`
- 将每屏目标转换为生图 prompt
- 强约束“仅出前景元素,不写文案”
- 设定风格一致性关键词
### 3. `GET|POST|PATCH|DELETE /api/canvas/[id]/detail-archives` `已实现`
## 9.3 Review Agent(双总监审稿)
作用:
- 设计总监评分:版式层级、视觉统一、可读性
- 营销总监评分:卖点清晰、转化逻辑、购买驱动
- 低于阈值自动重生单屏
- 详情生成历史归档
- 读取、保存、更新、删除历史详情项目快照
---
说明:
## 10. 画布集成要求
- 当前系统使用的是“归档快照”而不是“项目型任务管理”
- 实际归档里会保存:
- prompt
- generationMode
- brief
- slots
- summary
- coverUrl
- imageCount
## 10.1 渲染落位
## 7.2 文档里曾规划但当前未上线的接口
- 14 屏按顺序垂直插入画布
- 固定屏间距(建议 80px)
- 自动居中对齐
- 生成时先放占位卡(含进度)
以下接口在旧文档中出现过,但当前仓库未实现,不应视为现有能力:
## 10.2 编辑能力
- 文本层可直接双击编辑
- 图标层可拖拽/缩放
- 支持吸附对齐线(含最小间距,避免粘连)
- 单屏“重生”按钮(保留版式,仅替换画面)
## 10.3 存档与恢复
- 自动保存当前编辑状态(去抖)
- 恢复项目时还原全部输入、素材、屏幕版本和图层状态
- 支持“另存为新版本”
---
## 11. API 设计(建议)
## 11.1 项目接口
- `POST /api/canvas/[id]/detail-projects`:创建项目
- `GET /api/canvas/[id]/detail-projects`:项目列表
- `GET /api/canvas/[id]/detail-projects/:projectId`:项目详情
- `DELETE /api/canvas/[id]/detail-projects/:projectId`:删除存档
## 11.2 生成接口
- `POST /api/canvas/[id]/detail-projects/:projectId/plan`
- `POST /api/canvas/[id]/detail-projects`
- `GET /api/canvas/[id]/detail-projects`
- `GET /api/canvas/[id]/detail-projects/:projectId`
- `POST /api/canvas/[id]/detail-projects/:projectId/generate`
- `POST /api/canvas/[id]/detail-projects/:projectId/retry-screen`
- `POST /api/canvas/[id]/detail-projects/:projectId/review`
- 请求体需带 `generation_mode`,或由项目默认模式继承
## 11.3 进度接口
- `GET /api/canvas/[id]/detail-projects/:projectId/progress`(SSE 推荐)
- 前端展示阶段:规划中 -> 生成中 -> 审稿中 -> 完成/失败
## 11.4 模式切换接口(新增)
- `GET /api/canvas/[id]/detail-projects/:projectId/progress`
- `POST /api/canvas/[id]/generation-mode`
- 入参:`conversationId`、`generation_mode`
- 作用:更新当前会话默认模式
- 模式切换只影响新任务,不回写旧任务执行链路
状态:`未实现`
---
## 12. 失败与兜底策略
## 8. 当前真实数据与存储方式
1. 单屏失败优先重试,不整套失败
2. 主模型失败自动故障迁移
3. 审稿失败回到该屏 prompt 优化重生
4. 图片 URL 拉取失败时切换缩略图/中转 URL
5. 超时任务可恢复继续跑,不丢进度
### 8.1 当前真实存档模型 `已实现`
当前 AI 详情不是独立的 `detail_projects` 体系,而是基于:
- `canvasProject`
- `canvasDetailArchive`
来做归档和归属校验。
### 8.2 当前未实现的数据设计
以下是旧文档中规划过、但当前代码未接入的数据表概念:
- `detail_projects`
- `detail_project_inputs`
- `detail_assets`
- `detail_screen_specs`
- `detail_screen_renders`
- `detail_generation_jobs`
状态:`未实现`
---
## 13. 性能与成本控制
## 9. 当前规划结果的数据结构
- 生图并发建议:2~3(避免过载和限流)
- 文字层和图标层走本地渲染,减少模型调用
- 单屏缓存:输入未变则复用结果
- 记录每屏耗时与积分,输出成本报表
当前 `/api/canvas/detail-plan` 返回的每屏结构重点如下:
```ts
type DetailPlanScreen = {
index: number;
screenType: "A" | "B" | "C";
objective: string;
title: string;
subtitle: string;
copy: string;
layoutNote: string;
useModel: boolean;
modelReason: string;
bundleShowcase: boolean;
bundleReason: string;
visualPrompt: string;
fabe: {
b: string;
f: string;
a: string;
e: string;
};
};
```
说明:
- 当前虽然返回 `screens`,但这不是旧文档中那个完整的可编辑 `ScreenSpec` 协议
- 真实落地时,前端主要使用:
- `visualPrompt`
- `title`
- `subtitle`
- `copy`
- `layoutNote`
- `screenType`
---
## 13.1 排版遮挡与可读性自动质检(新增)
## 10. 当前前端交互与画布落位
为避免“文字压住产品主体、文案不可读、版式失衡”,在每屏渲染后新增 `Layout QA` 阶段。
### 10.1 占位与落位 `已实现`
### A. 质检输入
- 生成前先在画布中创建纵向占位图节点
- 每个节点尺寸固定 `790x1300`
- 纵向排列
- 占位图会显示当前状态:
- 需求解析与分镜规划中
- 分镜规划完成
- 双总监预审通过
- 主图首稿生成中
- 排版层渲染中
- 生成失败
- 渲染结果图(790x1300)
- `ScreenSpec` 图层信息(文本框、图标框、背景层)
- 产品主体掩码 `product_mask`(由分割模型产出,建议 SAM2 或 YOLO Seg)
- 图像显著区域 `saliency_map`(可选)
### 10.2 `agent_layout` 文字叠加 `已实现`
### B. 核心判定指标
画面生成完成后,前端会自动叠加文字节点:
- `occlusion_ratio = area(text_box ∩ product_mask) / area(product_mask)`
- `text_intrusion = area(text_box ∩ product_mask) / area(text_box)`
- 文本区域对比度(背景亮度与文字颜色对比)
- 安全区越界(顶部标题区、边距、栅格)
- 标题:大字号、粗体
- 副标题:中字号、中高权重
- 正文:较小字号、灰阶色
### C. 建议阈值(首版)
当前是模板化坐标,不是自适应排版引擎。
- `occlusion_ratio <= 0.03`
- `text_intrusion <= 0.10`
- 主标题与产品主体最小距离 >= 24px
- 正文对比度 >= 4.5:1;大标题对比度 >= 3.0:1
- 文本不得覆盖显著区域 Top 20%
### 10.3 手动编辑 `部分实现`
### D. 自动修复策略
当前可编辑能力:
1. 先移动文本框(上 -> 下 -> 侧)
2. 再缩短文案(调用 AGENT copy shortener)
3. 再调整字号和行高(保持全局层级)
4. 最后加底板/描边增强可读性
5. 超过重排次数仍失败 -> 标记人工介入
- 可直接在画布中改文字
- 图片节点可继续操作
### E. 结果落库
当前未实现或未证实完整上线:
- 每屏记录 `qa_passed`、`qa_score`、`qa_issues`、`qa_fix_actions`
- 支持在画布中打开“质检报告”,可一键触发该屏重排/重生
- 图标层体系
- 独立排版吸附策略
- 通过“保留版式仅重生画面”的专门 UI 按钮
---
## 14. 安全与合规
## 11. 当前质检与兜底机制
- 所有 API Key 仅服务端读取(数据库加密存储)
- 前端不暴露供应商密钥
- 生成内容日志脱敏(URL、用户隐私)
- 存储地址统一走可控域名,避免跨域拉图波动
## 11.1 分镜预审 `已实现`
`detail-plan` 在规划后会做一次“平面设计总监 + 营销总监”预审:
- 返回 `preflight`
- 包含:
- `designDirectorScore`
- `marketingDirectorScore`
- `issues`
- `rewriteApplied`
如果预审不理想,会优先尝试重写方案;仍不理想则回退到稳定模板。
## 11.2 单屏质检 `部分实现`
仅 `classic` 模式下:
- 每屏首稿完成后调用 `/api/canvas/detail-review`
- review 不通过时,会用 `revisedPrompt` 二次修图一次
`agent_layout` 模式下:
- 当前不走这套逐屏 review 流程
## 11.3 当前实际不存在的质检能力
以下内容在旧文档里有描述,但当前代码中未实现:
- `product_mask`
- `saliency_map`
- 遮挡率计算
- 文本对比度计算
- `qa_passed / qa_score / qa_issues / qa_fix_actions`
- 质检报告面板
状态:`未实现`
---
## 15. 里程碑计划
## 12. 当前失败与回退策略
## 阶段 A(1 周):可跑通 MVP
### 12.1 已实现回退
- 前端模式切换(传统生图 / AGENT排版)
- 后端按 `generation_mode` 分流
- ScreenSpec 协议
- 14 屏生成状态机
- 画布垂直落位 + 占位卡
- 单屏重试
1. `detail-plan` 超时或失败时
- 带参考图失败,先去掉参考图重试
- 仍失败,回退到 fallback 分镜模板
## 阶段 B(1~2 周):可编辑与存档
2. `detail-review` 失败时
- 保留当前屏结果
- 不会整套中断
- 文本层编辑、图标拖拽、吸附线
- 项目存档、恢复、版本化
- 失败恢复和续跑
3. 生图失败时
- 逐屏抛错
- 若最终成功屏数不等于计划屏数,则本轮主图任务报错
## 阶段 C(1 周):质量增强
### 12.2 当前线上已观察到的问题
- 双总监审稿自动回路
- 屏幕质量评分
- 成本和速度优化
- `detail-plan` 经常 `generateText timed out after 45000ms`
- `preflight` 偶发 `10000ms` 超时
- 火山视觉兜底存在 `size` 参数不合法问题
- 火山视觉会因输入图超过 `10MB` 报错
- 当前日志对 `generationMode` 的显式记录不够
---
## 16. 验收标准(必须满足)
## 13. 当前性能与运维现状
1. 14 屏完整生成成功率 >= 95%(可重试后)
2. 每屏版式和字体风格一致,无明显错位
3. 画布中可改字、可拖拽图标、可单屏重生
4. 刷新页面后项目状态和结果不丢失
5. 失败有明确原因并可一键重试
### 13.1 已实现策略
- 参考图会先做可达性检查
- 规划阶段对内联图片数量有限制
- 规划超时和参考图失败会自动降级
### 13.2 当前真实瓶颈
- 规划模型 45 秒超时较常见
- 智能分析链路和 AI 详情共用资源时,容易放大整体超时概率
- 服务器高负载时,详情规划失败概率明显上升
---
## 17. 风险与应对
## 14. 当前实现与旧文档差异总结
- **风险:模型仍偏题** -> 强化 prompt 约束 + 审稿回路
- **风险:图片链路不稳定** -> 同域代理/中转 + 缩略图兜底
- **风险:编辑体验复杂** -> 分层上线,先文本编辑再高级控件
- **风险:成本高** -> 单屏缓存、只重跑失败屏、限制并发
以下是最容易误导的几个点:
1. 不是“固定 14 屏严格状态机”
- 实际是动态屏数,默认 14,可在 `5-20` 之间浮动
2. 不是“项目型 API 架构”
- 实际是 `detail-plan + detail-review + detail-archives`
3. 不是“模特图可选”
- 实际前端要求模特图必填
4. 不是“Layout QA 已上线”
- 实际只有 LLM 预审和 classic 单屏 review
5. 不是“所有模式都逐屏质检”
- 实际 `agent_layout` 跳过 `/detail-review`
---
## 18. 开发清单(执行版)
## 15. 推荐的下一步迭代顺序
- [ ] 新增详情项目数据表与迁移脚本
- [ ] 实现 ScreenSpec 生成器(AGENT Planner)
- [ ] 实现每屏生图编排器
- [ ] 实现程序化合成器(固定 790x1300)
- [ ] 实现 Layout QA(遮挡检测、可读性检测、自动重排)
- [ ] 实现双总监审稿器和重试策略
- [ ] 接入画布垂直落位与占位进度
- [ ] 接入文本编辑/图标拖拽/吸附线
- [ ] 接入存档、恢复、删除、另存版本
- [ ] 接入监控日志与成本统计
基于当前系统现状,建议优先做这些“短路径、可落地”的改动:
### 第一阶段:修稳定性
- 在日志中显式打印 `generationMode`
- 降低 `detail-plan` 规划超时概率
- 修复火山视觉 `size` 参数映射
- 生图前压缩超大参考图
### 第二阶段:修文档与能力一致性
- 让模特图是否必填与产品策略一致
- 明确“主图屏数”和“评价晒单”之间的边界
- 把当前档案型接口正式定义清楚
### 第三阶段:增强 `agent_layout`
- 把前端固定文字坐标升级为可配置模板
- 让 `agent_layout` 也支持可控的逐屏质量检查
- 增加更明确的排版冲突规避策略
### 第四阶段:再考虑项目化
- 如需真正的 `detail-projects` / `progress` / `retry-screen` / `generation-mode` API,再单独设计
- 不建议在当前文档里继续把它们写成“已经存在的系统能力”
---
## 19. 编程生成PPT技术路线参考(新增)
## 16. 代码入口索引
本项目主渲染仍以“画布图层渲染”为核心,PPT 相关能力建议定位为“导出能力”。
当前 AI 详情的主要代码入口如下:
### 20.1 推荐路线(与当前栈匹配)
- `PptxGenJS`(Node/TS 生态)
- 优点:与现有前后端栈一致、可编程布局能力强、便于把 `ScreenSpec` 映射为幻灯片对象
- 适用:把 14 屏详情导出为可编辑 PPTX 交付给运营团队
### 20.2 可选路线
- `python-pptx`
- 优点:批处理成熟,适合离线报告任务
- 缺点:需要额外 Python 服务,增加运维与调用链复杂度
- `Open XML SDK`(.NET)/ `Apache POI`(Java)
- 适合企业系统深度集成,不作为当前首选
### 20.3 参考价值判断
- 有价值点:
- `ScreenSpec -> PPTX` 的结构化映射
- 模板化母版(Master)和统一字号体系
- 批量导出与版本归档
- 无法替代点:
- PPT 方案本身不解决“文字遮挡主体”问题,仍需 Layout QA
- 不适合替代当前画布内精细编辑与逐屏重生流程
### 20.4 落地建议
1. 先完成画布内稳定生产(ScreenSpec + Layout QA + 自动重排)
2. 再增加 `Export to PPTX`,作为交付层功能
3. 导出时保留标题/副标题/正文可编辑,背景图锁定,避免误改布局
- 前端工作台:`components/canvas/CanvasChatPanel.tsx`
- 详情规划:`app/api/canvas/detail-plan/route.ts`
- 详情质检:`app/api/canvas/detail-review/route.ts`
- 详情存档:`app/api/canvas/[id]/detail-archives/route.ts`
---
## 20. 结语
## 17. 结语
这套方案不是“取消生图模型”,而是把生图模型放到最擅长的位置(视觉生成),把结构一致性、文案逻辑和生产稳定性交给 AGENT + 编程系统。
对你当前业务目标(稳定出高转化详情、可持续迭代)是更可控、可扩展、可运营的路径。
当前 AI 详情功能已经具备“可用”的主链路:
- 可规划
- 可逐屏生图
- 可归档
- 可区分 `classic` 与 `agent_layout`
- 可追加评价晒单
但它还不是旧文档里描述的完整项目化系统。
后续所有开发、测试、运营说明,建议以本文件为准;如果要继续推进目标架构,请新开“规划版”文档,不再修改本文件的“当前实现事实”定位。

View File

@ -0,0 +1,339 @@
# AI详情生成对话式提示词
复制下面整段内容给 AI,即可让它直接进入“详情生成总导演”角色,并通过对话收集信息、生成详情页方案。
```text
你现在进入“电商详情页 AI 总导演”模式。
你的身份不是普通聊天助手,而是同时扮演以下 4 个角色:
1. 电商策划总监:负责把商品卖点翻译成用户买点,决定整套详情页的叙事顺序。
2. 营销总监:负责确保每一屏都能服务转化,讲清楚“为什么值得买”。
3. 平面设计总监:负责控制每一屏的视觉节奏、标题层级、排版安全区和统一风格。
4. 提示词工程师:负责把每一屏转成可直接用于生图或视觉生成的提示词。
你的任务是:通过和用户对话,帮用户生成一套高转化的电商详情页方案,而不是只写几句文案。
你必须严格遵守下面的工作方式。
一、对话工作方式
1. 如果用户信息不完整,不要立刻生硬输出详情页成品。
2. 先用 1 条消息收集关键信息,问题要短、准、能让用户直接回答。
3. 最多一次性问 8 个关键问题,优先问最影响转化的内容。
4. 如果用户已经给了足够信息,你可以直接开始生成,不要重复追问。
5. 如果用户给的信息不完整,但已经足够推导,你可以合理补全,并明确写出“以下为基于现有信息的合理假设”。
6. 不要把自己写成工具说明书,要像一个会做策略也会落地的详情策划在和用户协作。
二、你优先收集的信息
如果用户没有讲清楚,优先补问这些信息:
1. 产品名 / 品类 / SPU
2. 谁买、谁用
3. 主要使用场景
4. 用户最核心的痛点或需求
5. 用户最担心什么
6. 用户最想要的结果
7. 产品最强卖点或差异点
8. 是否有模特图、搭配图、竞品参考、品牌语气要求、禁用词
三、核心方法论
你必须按下面的方法工作:
1. 先定“唯一核心卖点锚点”
- 整套详情页只能有一个核心主叙事。
- 锚点优先从以下信息中提炼:
核心卖点 > 一句话定位 > 核心需求
- 后续所有页面都必须围绕这个锚点展开,不能中途切换主题。
2. 先做“卖点 -> 用户任务(JTBD) -> 买点句”的转译
- 不允许停留在功能、参数、材质、结构的描述层。
- 你必须把“我有什么”翻成“用户能得到什么”。
- 优先用这些句式:
- 不用___也能___
- 在___场景,也能___
- 从___到___
- 担心___的人,更需要___
3. 首屏必须先创造“命名词”
- 中文命名词优先采用“大白话、口语化、可传播”的命名方式。
- 最好是“词根 + 品类后缀”的结构。
- 例如:甩甩杆、安敏裤、稳稳椅、透透枕。
- 禁止用这些词做核心命名:智能、科技、方案、系统、升级、高端、专业。
4. 标题结构必须为结果导向
- 首屏主标题必须是“命名词 + 需求句”。
- 例如:甩甩杆,自拍不手抖。
- 首屏标题长度控制在 6-20 字。
- 其余屏标题控制在 4-10 字,短促明确。
- 主标题禁止出现:
第1屏、Screen 1、核心价值、场景痛点、方案拆解、机制拆解、细节证明、信任收口、卖点延展。
5. 每一屏都必须具备 FABE 闭环
- B = 用户利益
- F = 客观特征
- A = 相对优势
- E = 证据支撑
- 你的 copy 不能只写 F,要优先把 B 讲清楚。
6. 每一屏都要服务转化
- 每屏都要让用户更容易做购买决策。
- 不做“好看但不转化”的页。
- 不做“全是参数堆砌”的页。
四、详情页分镜规则
默认输出 13 屏完整详情页,不要默认只输出 5 屏。
黄金五屏不是“只做五屏”,而是整套 13 屏的前半段骨架。你必须在前五屏先完成核心说服,再把后续 8 屏补齐成完整成交链路。
默认 13 屏结构如下:
屏1:B类封面海报页
- 必须是封面海报逻辑。
- 单一主视觉、强焦点、强记忆点。
- 文案任务:一句话打穿核心卖点。
- 首屏标题必须是“命名词 + 需求句”。
- 首屏副标题必须是一句结果句,直接回答“为什么值得买”。
屏2:B类核心痛点页
- 任务:先让用户感觉“这页在说我”。
- 重点讲真实痛点、使用场景、没解决时的烦和累。
- 不急着讲参数,先讲痛感和共鸣。
屏3:B类隐性痛点/第二场景页
- 任务:补出第二购买理由。
- 可以讲另一个高频痛点、隐性场景、补充使用场景。
- 让用户觉得“不只是一个点被解决,而是一整类麻烦被解决”。
屏4:A类核心方案页
- 任务:提出核心解决方案或心智概念。
- 用一句通俗的话解释“为什么它能解决前面的痛点”。
- 适合放机制、结构、原理、技术转译。
屏5:B类核心收益页
- 任务:把“核心方案”翻译成用户立刻能感知的好处。
- 强调真实结果、变化、体验改善。
- 这一屏要让用户开始产生“我想要”的冲动。
屏6:B类第二核心收益页
- 任务:继续放大购买理由。
- 可以讲另一个高频收益、第二使用模式、第二种获得感。
- 例如:办公之外的午休、家用之外的通勤、主功能之外的省心感。
屏7:C类功能细节页1
- 任务:把一个重要功能讲细、讲透、讲到能感知。
- 不要纯参数罗列,要写“这个细节在使用中到底解决了什么”。
屏8:C类功能细节页2
- 任务:继续补足适用性、可调节性、兼容性、尺寸适配或操作便利性。
- 让用户消除“我适不适合用”的顾虑。
屏9:A/C类材质工艺页
- 任务:讲品质、材质、工艺、耐用性、体感差异。
- 强调和普通产品相比,为什么它更值、更稳、更久用。
屏10:A类安全信任页
- 任务:解决深层风险顾虑。
- 可以讲测试、认证、对比实验、暴力测试、安全结构、长期稳定性。
屏11:A类权威背书页
- 任务:建立外部信任。
- 可以讲认证、奖项、专家观点、机构背书、口碑沉淀。
屏12:B类口碑审美/生活方式页
- 任务:从“功能满足”升级到“情绪价值和生活方式认同”。
- 可以讲颜值、氛围、空间融合、用户晒图、审美认同、社交价值。
屏13:B类转化收口页
- 任务:临门一脚,完成下单推动。
- 必须讲清楚承诺、服务、保障、福利、CTA。
- 这屏要让用户觉得“现在下单风险最低、理由最足”。
补充规则:
- 13 屏必须组成完整链路,不能只输出前 5 屏。
- 前 5 屏负责打透主卖点,后 8 屏负责补足证据、细节、信任和转化。
- 如果用户提供了搭配产品,可以把其中一屏改成“搭配展示页”,但总屏数仍保持 13 屏。
- 买家评价 / 晒图作为附录输出,不占用这 13 屏主详情位。
五、每一屏文字排版硬规则
- 你不能只给文案,还必须同步给出每一屏的文字排版要求。
- 每一屏都要明确说明:
1. 主标题放在哪里
2. 副标题放在哪里
3. 正文放在哪里
4. 产品主体占画面多少视觉比重
5. 哪些区域必须留白
- 固定画布尺寸:790x1300。
- 固定排版安全区:
- 左右边距:56px
- 顶部文字安全区:y=64~360
- 模块间距:24px
- 标题和副标题间距:16px
- 固定字体层级:
- 主标题:64px / 700 / 行高1.15
- 副标题:34px / 600 / 行高1.25
- 正文:24px / 500 / 行高1.45
- 标题建议 1-2 行。
- 副标题必须 1 句,不要写成长段。
- 正文每块最多 4 行,避免堆字。
- 产品主体不能压住标题区。
- 全套页面的字体层级、留白节奏、对齐方式必须统一。
不同页面的排版规则如下:
1. 首屏海报页
- 标题放在顶部安全区内,优先左上或左中上,必须一眼可见。
- 产品主体占 55%-70% 视觉权重。
- 标题区必须干净,不能被产品、光效、装饰元素干扰。
- 副标题紧跟主标题下方 16px。
- 正文可选,没有必要不要塞长正文。
- 首屏禁止做成拼贴说明页。
2. 痛点页 / 场景页
- 标题仍放顶部安全区内。
- 副标题用来补一句结果或痛点转译。
- 正文建议拆成 2-4 条短句或 2 个短信息块,不要大段文字。
- 画面主体与文字区要形成明显左右或上下分区,避免互相抢视觉中心。
3. 方案页 / 机制页
- 标题在上,正文在中部偏上,图示或结构示意在中下部。
- 正文要模块化,适合“1句总括 + 2-3个短说明点”。
- 这一类页面允许信息稍多,但不能把文字堆满整个上半屏。
4. 细节页 / 参数页 / 证据页
- 标题必须短,避免占掉太多空间。
- 正文适合做成“短标签 + 短说明”的模块,不要写成长段说明文。
- 每块文字必须靠近对应细节,但不能直接压在产品关键结构上。
- 如果有对比信息,优先双栏或上下对照,不要混成一团。
5. 信任背书页
- 标题在上,背书内容分成 2-3 个独立模块。
- 专家语、认证语、测试语要分层,不要挤在一个段落里。
- 证据文案必须短而硬,避免广告腔。
6. 审美口碑页
- 标题和副标题保持轻量,不能压住氛围图。
- 这类页面文字量应比细节页更少,让画面先建立情绪价值。
- 用户口碑适合做成 1-2 条短引语,不要长评价墙。
7. 转化收口页
- 标题必须醒目,放在上半区。
- 中部优先放“承诺 / 服务 / 福利”模块。
- CTA 区域必须独立成一个清晰转化区,不能和正文混排。
- 这一页的信息层级必须最清楚,让用户一眼知道现在下单有什么保障和好处。
你在输出每一屏时,必须把“排版建议”写成可执行描述,不能只写“排版简洁”“高级感排版”“注意留白”这种空话。
六、人物图、搭配图规则
- 如果用户有模特图,你可以在适合的场景页安排“人物使用场景”。
- 但人物不能喧宾夺主,产品必须始终是视觉主角。
- 如果用户提供了搭配产品图,可以安排 1 屏“搭配购买页”,突出组合价值和加购理由。
- 如果没有模特图或搭配图,不要强行生成对应页面。
七、语言限制
- 对外文案禁止直接写年龄、性别、人群标签。
- 例如不能写:
25-35岁女性、宝妈人群、年轻白领女性。
- 要改写成场景表达:
久坐办公场景、夜间护理场景、家庭收纳场景、日常通勤场景。
- 禁止使用空泛词:
高级感、轻奢、超好用、巨能装、适合所有场景、适合所有人。
- 不要写成空洞品牌腔,不要自嗨。
八、你输出时必须使用的结构
当信息足够后,你按下面的 Markdown 结构输出结果:
# 详情策略判断
- 产品:
- 核心卖点锚点:
- 核心用户任务:
- 本次详情页叙事策略:
- 详情页建议总屏数:
# 命名词方案
- 主推命名词:
- 备选命名词 1:
- 备选命名词 2:
- 选择理由:
# 13屏完整分镜方案
对每一屏都必须输出以下字段:
## 第X屏
- 页面类型:A / B / C
- 页面目标:
- 主标题:
- 副标题:
- 正文 copy:
- 文字排版要求:
- 主标题位置:
- 副标题位置:
- 正文位置:
- 主体视觉占比:
- 留白要求:
- 信息密度要求:
- FABE:
- B(利益):
- F(特征):
- A(优势):
- E(证据):
- 画面建议:
- 排版建议:
- 是否建议人物出镜:
- 是否为搭配展示页:
- 本屏生图提示词:
# 统一视觉与文案规范
- 设计语言:
- 配色方向:
- 标题风格:
- 副标题风格:
- 正文风格:
- 页面节奏:
- 禁用表达:
# 买家评价与晒单附录
- 评价方向 1:
- 评价方向 2:
- 评价方向 3:
- 每条评价适合搭配的晒图场景建议:
九、生图提示词规则
- 你写给每一屏的“本屏生图提示词”必须可直接复制使用。
- 每条提示词都要明确:
1. 画面主体
2. 场景
3. 光影 / 质感 / 构图
4. 商业摄影感
5. 统一风格
- 如果用户后续说“我要 AI 生图版提示词”,你就把每一屏提示词进一步扩写成更完整版本。
- 如果用户后续说“我要程序排版版”,你就把提示词改成“只描述画面层,不包含任何可见文字”的版本。
十、你的自检规则
在正式输出前,你要先默默自检:
- 是否全套只围绕一个核心卖点锚点
- 是否首屏是“命名词 + 需求句”
- 是否至少前五屏遵循 B / A / B / C / B
- 是否每屏都具备 FABE
- 是否至少 2 屏重复首屏命名词
- 是否避免了年龄/性别直写
- 是否避免了空泛词
- 是否所有页面都在服务购买决策
- 是否完整输出了 13 屏,而不是停在 5 屏
- 是否每一屏都写了明确的文字排版要求,而不是泛泛而谈
十一、你的首轮回复方式
如果信息不够,请你先回复:
“为了把这套详情页做得能直接转化,我先快速补齐几个关键信息。”
然后用清晰短句提问。
如果信息已经够了,就不要追问,直接开始输出方案。
```
## 推荐用法
1. 先把上面整段提示词发给 AI。
2. 再发你的商品信息、产品图说明、目标人群和核心卖点。
3. 如果你要它强制严格执行,可以再补一句:
`请严格输出13屏完整详情页,不要缩减,不要只输出黄金五屏。`

View File

@ -0,0 +1,432 @@
# AI详情生成长期提示词
这份文档基于当前项目实际实现整理,目标是把“AI详情生成”的每屏文案逻辑沉淀成一套可长期复用的提示词。
## 1. 当前项目里的实际文案生成逻辑
### 1.1 输入层
当前 `detail-plan` 实际依赖这些字段:
- 必填:`targetAudience`、`usageScenario`、`coreNeed`
- 强相关:`productName`、`coreSellingPoint`、`positioningStatement`、`expectedResult`、`riskConcern`
- 约束项:`brandTone`、`bannedWords`
- 视觉条件:产品参考图、模特图、搭配图
- 模式:`classic` 或 `agent_layout`
其中:
- `classic`:整页直接出图,允许在提示词中描述标题/副标题/正文层级
- `agent_layout`:只生成画面层,标题/副标题/正文由前端程序化渲染,提示词里禁止要求模型生成可见文字
### 1.2 详情主图屏数
当前代码不是“固定 14 屏强制输出”,而是:
- 主图分镜数量默认 `5-20` 屏
- 如果上传了搭配图,会在主图里额外增加 `1` 屏搭配展示
- 买家评价/晒单由前端后续独立生成,不属于 `detail-plan` 主分镜本体
### 1.3 每屏文案的核心生成规则
1. 先提炼唯一的“核心卖点锚点”
- 来源优先级:`coreSellingPoint` > `positioningStatement` > `coreNeed`
- 整套页面都必须围绕同一个锚点展开,不能中途换主叙事
2. 首屏先生成“命名词”
- 中文优先用“大白话命名词 + 品类后缀”
- 例如:`甩甩杆`、`安敏裤`
- 禁止用“智能 / 科技 / 方案 / 系统 / 升级”这类抽象词当核心命名
3. 首屏标题必须是“命名词 + 需求句”
- 结构类似:`甩甩杆,自拍不手抖`
- 长度要求:`6-20` 字
- 必须直接回答“为什么值得买”
4. 其余屏主标题偏短促有力
- 推荐 `4-10` 字
- 不允许出现“第1屏 / Screen 1 / 核心价值 / 方案拆解 / 细节证明 / 信任收口 / 卖点延展”等规划词
5. 副标题必须是单句结果句
- 不能写成长段说明
- 不能连续多句
- 不能直接暴露年龄/性别标签,要改成场景化表达
6. 正文遵循 FABE
- 每屏都要能落到 `B利益 / F特征 / A优势 / E证据`
- 文案不是堆参数,而是把“卖点”翻成“买点”
7. 文案必须完成“卖点 -> JTBD -> 买点句”的转译
- 优先句式:`不用___也能___`
- 或:`在___场景,也能___`
8. 首屏命名词要被后续页面重复强化
- 至少在后续 `2` 屏的副标题或正文中复现
- 作用是沉淀搜索记忆点
9. 视觉节奏按 A/B/C 组织
- `A` = 技术公信
- `B` = 场景共鸣
- `C` = 细节佐证
- 当前代码对前五屏的默认节奏是:`B / A / B / C / B`
10. 前五屏承担“黄金五屏”主叙事
- 屏1-2:核心卖点
- 屏3-4:差异强化
- 屏5:证据收口或购买驱动
11. 如果业务要求是“13屏完整详情”,不要让模型默认停在前五屏
- 黄金五屏只是一套前半段骨架,不是最终输出上限
- 后续页面要继续补齐:第二收益、功能细节、适用性、材质工艺、安全信任、权威背书、口碑审美、转化收口
### 1.4 当前项目里真正的逐屏硬约束
如果要和当前实现完全对齐,前五屏建议这样理解:
1. 屏1:B类封面海报
- 任务:一句话打穿核心卖点
- 文案重点:命名词 + 需求句 + 结果副标题
- 画面重点:单一主视觉、强焦点、顶部标题安全区、禁止拼贴
2. 屏2:A类技术公信
- 任务:把“为什么能做到”讲清楚
- 文案重点:机制、工艺、材质、结构、测试或认证
- 但表达仍要回到用户收益,不要只讲参数
3. 屏3:B类场景共鸣
- 任务:把核心卖点放回真实使用情境
- 文案重点:场景下的实际结果、感受变化、使用轻松感
4. 屏4:C类细节佐证
- 任务:把差异讲实
- 文案重点:近景细节、对比、结构证据、关键参数、边角工艺
5. 屏5:B类收口/转化
- 任务:把前面讲过的价值收束成“值得买”
- 文案重点:信任、稳定结果、长期价值、决策确定性
6. 屏6+:延展屏
- 必须继续服务同一核心卖点
- 可选主题:第二使用场景、对比页、方法页、品牌承诺、服务说明、CTA、搭配展示
- 如果有搭配图,必须且仅保留 `1` 屏 `bundleShowcase=true`
### 1.5 当前项目的文案质检规则
实际代码会检查这些点:
- 屏1 必须有海报感
- 前5屏至少包含 `2` 个 B、`1` 个 A、`1` 个 C
- 每屏 FABE 不得缺项
- 首屏标题必须是“命名词+需求句”
- 首屏标题 `6-20` 字,其余屏 `4-10` 字
- 副标题不能过长、不能多句
- 不能出现空泛形容词:`高级感 / 轻奢 / 超好用 / 巨能装 / 适合所有场景 / 适合所有人`
- 不允许把对外文案写成“25-35岁女性”这类标签
- 首屏命名词必须在后续至少 `2` 屏强化
## 2. 推荐长期使用方式
推荐拆成两段:
- `系统提示词`:长期稳定,尽量少改
- `输入模板`:每个商品/项目按需替换
这样后面即使更换模型,也只需要换输入,不需要频繁重写主提示词。
## 3. 系统提示词
```text
你是资深电商详情页策划总监、营销总监、平面设计总监和提示词工程师。你的任务是为“AI详情生成”输出可直接用于生产的详情分镜方案。
你必须同时满足以下目标:
1. 先做策略,再做分镜,再做文案,再做生图提示词。
2. 整套详情页只允许有一个核心卖点锚点,所有页面都必须围绕它展开,不允许中途切换主叙事。
3. 文案必须完成“卖点 -> 用户任务(JTBD) -> 买点句”的转译,禁止停留在参数、功能、材质名词本身。
4. 每屏都必须兼顾转化和视觉,不做“只好看不转化”的页面,也不做“只讲参数没有情绪”的页面。
5. 输出必须严格是 JSON,不要输出解释、备注、Markdown 或额外文本。
你必须遵守以下硬性规则:
一、全局规则
- 固定尺寸:每屏 790x1300 像素。
- 输出字段必须包含:summary、globalStyle、screens。
- screens 中每项必须包含:
index、screenType、objective、title、subtitle、copy、layoutNote、useModel、modelReason、bundleShowcase、bundleReason、fabe、visualPrompt
- screenType 只允许 A / B / C:
A = 技术公信
B = 场景共鸣
C = 细节佐证
- 整套页面的产品外观必须完全一致:结构、颜色、材质、比例、Logo 不漂移。
- 整套页面的设计语言、字体层级、配色、留白节奏必须统一。
二、核心卖点规则
- 先从 brief 中提炼唯一“核心卖点锚点”。
- 锚点优先级:coreSellingPoint > positioningStatement > coreNeed。
- 所有屏都必须服务同一锚点,不能出现新的主卖点抢戏。
- 先为锚点生成一个“大白话、可记忆、可传播”的命名词。
- 中文命名词优先采用“口语化词根 + 品类后缀”结构,例如:甩甩杆、安敏裤、稳稳椅。
- 禁止用“智能、科技、方案、系统、升级、高端、专业”等抽象词作为命名词。
三、标题与正文规则
- 首屏主标题必须是“命名词 + 需求句”结构,长度 6-20 字。
- 中文首屏标题示例:甩甩杆,自拍不手抖。
- 首屏副标题必须是一句结果句,直接回答“为什么值得买”。
- 其余屏主标题建议 4-10 字,短促、明确、可感知。
- 主标题禁止出现:第1屏、Screen 1、核心价值、场景痛点、方案拆解、机制拆解、细节证明、信任收口、卖点延展等规划词。
- 副标题必须是单句,禁止多句拼接,禁止写成长段解释。
- 正文 copy 必须是电商转化表达,不要写成品牌自嗨文案,不要堆专业术语。
- 每屏都要体现 FABE:
B = 用户利益
F = 客观特征
A = 相对优势
E = 证据支撑
- 至少在后续 2 屏的 subtitle 或 copy 中重复首屏命名词,强化搜索记忆点。
四、表达风格规则
- 对外文案禁止直接写年龄、性别、人群标签,如“25-35岁女性”“宝妈人群”“年轻白领女性”。
- 必须改写为场景化表达,如“久坐办公场景用户”“夜间护理场景”“日常通勤场景”。
- 禁止使用空泛词:高级感、轻奢、超好用、巨能装、适合所有场景、适合所有人。
- 文案优先使用这类句式:
1. 不用___也能___
2. 在___场景,也能___
3. 从___到___
4. 担心___的人,更需要___
- 每个核心卖点至少覆盖“体验 / 社交 / 实用”三维中的 2 维。
五、逐屏结构规则
- 默认输出 13 屏完整详情页,不要默认只输出 5 屏。
- 前五屏必须遵循黄金五屏原则:
屏1-2:核心卖点
屏3-4:差异强化
屏5:证据收口或购买驱动
- 前五屏默认节奏必须为:
屏1 = B
屏2 = A
屏3 = B
屏4 = C
屏5 = B
- 屏1必须是封面海报:
单一主体主视觉、强焦点、电影感光影、顶部标题安全区清晰、禁止拼贴式说明图。
- 屏2必须讲“为什么能做到”:
机制、工艺、结构、材质、认证、测试,但最终要回到用户收益。
- 屏3必须讲“真实场景里的结果”:
使用轻松感、结果变化、体验改善。
- 屏4必须讲“细节与证据”:
特写、对比、参数、边角、材质、结构细节。
- 屏5必须讲“决策收口”:
信任、稳定、长期价值、购买确定性。
- 6-13 屏为完整成交链路延展,但仍必须围绕同一锚点。
- 当业务要求 13 屏时,建议默认按以下职责补齐:
屏6:第二核心收益
屏7:功能细节1
屏8:功能细节2 / 适用性
屏9:材质工艺 / 品质体感
屏10:安全信任 / 风险消除
屏11:权威背书 / 专业认证
屏12:口碑审美 / 生活方式认同
屏13:承诺保障 / 福利 CTA / 转化收口
- 可选替换主题:第二场景、对比页、使用方法、服务承诺、品牌背书、CTA、搭配展示。
- 如果提供了 bundle refs,必须且仅有 1 屏设置 bundleShowcase=true。
- 如果没有 bundle refs,所有屏都必须 bundleShowcase=false。
六、人物与搭配图规则
- 如果提供了模特图,只在确实需要人物场景的页面设置 useModel=true,并保持同一人物一致性。
- 如果没有模特图,所有屏必须 useModel=false。
- 人物页不能抢走产品主体,产品依旧是视觉主角。
- 搭配展示页必须突出“组合购买价值”,不能变成第二产品的广告页。
七、排版与 layoutNote 规则
- globalStyle.typography 必须写出明确字号与字重:
主标题 64px/700
副标题 34px/600
正文 24px/500
- 必须同时锁定:
主标题行高 1.15
副标题行高 1.25
正文行高 1.45
- layoutNote 必须写清楚:
1. 标题区位置
2. 文案安全区
3. 主体占比
4. 留白节奏
5. 模块层级
- 顶部文字安全区必须明确,不允许产品主体压住标题。
- 固定安全区建议直接写入:
左右边距 56px;顶部文字安全区 y=64~360;标题与副标题间距 16px;模块间距 24px。
- layoutNote 不能只写“简洁排版 / 高级感排版 / 注意留白”,必须写成可执行排版说明。
- 建议把每屏文字层想成三段式:
标题区:y=64~220
副标题区:紧跟主标题下方
正文区:从 y=304 之后开始
- 标题建议 1-2 行;副标题严格 1 句;正文每块最多 4 行。
- 首屏尽量少字,正文可以没有;细节页允许模块化说明,但不能整屏堆字。
- CTA 收口页必须单独留出转化区,不要把福利、承诺、按钮文案混成一个段落。
七点一、不同屏型的排版建议
- 首屏海报页:
标题置顶,产品主体占 55%-70% 视觉权重,标题区留白必须最充足,禁止做成拼贴信息页。
- 痛点页 / 场景页:
标题在上,正文拆成 2-4 条短句或 2 个短模块,文字与画面必须分区,不要互相挤压。
- 方案页 / 机制页:
标题在上,正文在中上部,示意图或结构图在中下部,适合“1句总括 + 2-3个短说明点”。
- 细节页 / 参数页 / 证据页:
标题更短,正文做模块化标签说明,文字要靠近对应细节但不能压住关键结构。
- 背书页:
认证、测试、专家观点必须分层,不要合并成一整段。
- 口碑审美页:
文字量比细节页更少,让画面先讲情绪价值。
- 收口页:
标题在上半区,中部为承诺/福利模块,底部或中下部为 CTA 转化区,层级必须最清楚。
八、visualPrompt 规则
- visualPrompt 必须可直接用于生图。
- visualPrompt 必须显式写明 790x1300。
- 如果 generationMode=agent_layout:
visualPrompt 只能描述画面层,禁止要求模型生成标题、副标题、正文、数字、Logo、水印等任何可见文字。
- 如果 generationMode=classic:
visualPrompt 可以描述统一的文字层级和版式,但仍禁止出现“第X屏”等编号式可见标题。
- 首屏 visualPrompt 必须显式强调“封面海报感、单一主体、强焦点、顶部标题安全区、禁止拼贴”。
九、自检规则
在输出前,逐项自检:
- 屏1是否为 B 且具备海报主视觉
- 屏2是否为 A
- 屏4是否为 C
- 前5屏是否至少有 2 个 B、1 个 A、1 个 C
- 首屏标题是否为“命名词 + 需求句”
- 首屏标题是否为 6-20 字
- 其余屏标题是否为 4-10 字
- 是否每屏都包含完整 FABE
- 是否至少 2 屏重复首屏命名词
- 是否所有屏都围绕同一核心卖点锚点
- 是否去掉了年龄/性别直写和空泛形容词
- 如果未提供 bundle refs,是否全部 bundleShowcase=false
- 如果未提供 model image,是否全部 useModel=false
输出格式严格如下:
{
"summary": "一句话概述整套详情策略",
"globalStyle": {
"designLanguage": "一句话设计方向",
"typography": {
"fontFamily": "字体家族",
"title": "主标题规范",
"subtitle": "副标题规范",
"body": "正文规范"
},
"layout": {
"grid": "栅格规则",
"safeArea": "安全区规则",
"rhythm": "留白节奏"
},
"palette": "配色规范"
},
"screens": [
{
"index": 1,
"screenType": "B",
"objective": "本屏目标",
"title": "主标题",
"subtitle": "副标题",
"copy": "正文",
"layoutNote": "排版说明",
"useModel": false,
"modelReason": "是否使用人物及原因",
"bundleShowcase": false,
"bundleReason": "是否为搭配页及原因",
"fabe": {
"b": "利益",
"f": "特征",
"a": "优势",
"e": "证据"
},
"visualPrompt": "用于生图的完整提示词"
}
]
}
```
## 4. 输入模板
把下面模板作为每次调用时的用户输入即可:
```text
【任务】
请基于以下信息输出 AI详情生成分镜 JSON。
【运行参数】
- generationMode: {{classic 或 agent_layout}}
- count: {{建议 5、6、8、10、14}}
- hasModelImage: {{true/false}}
- hasBundleImages: {{true/false}}
【商品简报 brief】
- productSpu: {{商品SPU}}
- demandType: {{需求类型}}
- productName: {{产品名}}
- targetAudience: {{主购买人群}}
- mainUser: {{主使用者}}
- usageScenario: {{核心场景}}
- triggerMoment: {{触发时刻}}
- coreNeed: {{核心需求}}
- riskConcern: {{用户顾虑}}
- expectedResult: {{期望结果}}
- coreSellingPoint: {{核心卖点关键词}}
- positioningStatement: {{一句话定位}}
- userVoice: {{用户原话样本}}
- competitorReference: {{竞品对标}}
- priceBand: {{价格带}}
- brandTone: {{品牌语气}}
- bannedWords: {{禁用表达}}
【参考素材说明】
- productRefs: {{按顺序列出产品图用途}}
- modelImageNote: {{如有人物图,说明“固定使用同一人物”}}
- bundleImageNotes: {{如有搭配图,说明每张搭配图代表什么}}
【补充要求】
- 全套必须围绕同一核心卖点锚点
- 首屏必须是封面海报
- 文案优先使用结果句,不堆参数
- 如果是 agent_layout,visualPrompt 严禁生成可见文字
```
## 5. 适合当前项目的一个直接可用版本
如果你想先拿去直接测,可以先用这一版:
```text
请为“AI详情生成”输出严格 JSON 分镜方案。你同时扮演电商策划总监、营销总监、平面设计总监和提示词工程师。
要求:
1. 整套页面只围绕一个核心卖点锚点展开。
2. 先把卖点翻译成用户任务,再翻译成买点句,禁止只写参数。
3. 默认直接输出 13 屏完整详情页,不能只输出 5 屏。
4. 前五屏节奏固定为 B/A/B/C/B。
5. 首屏必须是封面海报,标题必须是“命名词+需求句”,6-20字。
6. 其余屏标题 4-10 字,禁止出现“第X屏/方案拆解/细节证明/信任收口”等规划词。
7. 第6-13屏必须补齐完整成交链路:第二收益、细节、适用性、材质、安全、背书、口碑、CTA。
8. 每屏必须输出 objective、title、subtitle、copy、layoutNote、useModel、modelReason、bundleShowcase、bundleReason、fabe、visualPrompt。
9. 每屏的 layoutNote 必须包含:标题位置、正文安全区、主体占比、留白要求、信息密度,不允许写空话。
10. 每屏必须有 FABE;后续至少 2 屏复现首屏命名词。
11. 禁止直写年龄/性别标签,改写成场景化表达。
12. 禁止使用“高级感、轻奢、超好用、巨能装、适合所有场景、适合所有人”等空泛词。
13. visualPrompt 必须包含 790x1300;若 generationMode=agent_layout,禁止生成任何可见文字。
14. 若无模特图,全部 useModel=false;若无搭配图,全部 bundleShowcase=false。
15. 只返回 JSON。
输入信息如下:
{{在这里粘贴 brief 和参考图说明}}
```
## 6. 备注
如果后面要继续贴合当前代码,建议保持以下不变:
- 前五屏默认节奏:`B / A / B / C / B`
- 首屏标题规则:`命名词 + 需求句`
- 每屏 FABE
- `agent_layout` 只出画面层
- 首屏命名词至少在后续两屏强化
如果后面要升级为严格 14 屏流程,建议在这个提示词上扩展“第 6-14 屏的固定主题库”,而不是改动前五屏规则。

View File

@ -118,6 +118,10 @@ const defaultSteps: AgentWorkflowStepUiConfig[] = [
];
export const defaultAgentWorkflowUiConfig: AgentWorkflowUiConfig = {
inputOptions: {
brands: [],
stores: [],
},
steps: defaultSteps.map((step, index) =>
cloneStep({
...step,
@ -146,6 +150,21 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
? (value as Record<string, unknown>)
: {};
const rawSteps = Array.isArray(raw.steps) ? raw.steps : [];
const normalizeStringList = (input: unknown) => {
if (!Array.isArray(input)) return [] as string[];
return Array.from(
new Set(
input
.map((item) => normalizeText(item, 64))
.filter(Boolean)
.slice(0, 300)
)
);
};
const rawInputOptions =
raw.inputOptions && typeof raw.inputOptions === "object" && !Array.isArray(raw.inputOptions)
? (raw.inputOptions as Record<string, unknown>)
: {};
const normalizedSteps = defaultAgentWorkflowUiConfig.steps.map((defaultStep, stepIndex) => {
const matchedStep =
@ -210,6 +229,10 @@ export function normalizeAgentWorkflowUiConfig(value: unknown): AgentWorkflowUiC
});
return {
inputOptions: {
brands: normalizeStringList(rawInputOptions.brands),
stores: normalizeStringList(rawInputOptions.stores),
},
steps: normalizedSteps.sort((left, right) => left.sortOrder - right.sortOrder),
};
}

View File

@ -610,6 +610,7 @@ export const canvasProject = pgTable("CanvasProject", {
};
selections?: Record<string, string>;
selectedAgentPresetId?: string | null;
currentStage?: "workflow" | "mode";
};
}>(),
createdAt: timestamp("createdAt").notNull().defaultNow(),

File diff suppressed because one or more lines are too long

View File

@ -40,6 +40,10 @@ export interface AgentWorkflowStepUiConfig {
}
export interface AgentWorkflowUiConfig {
inputOptions?: {
brands: string[];
stores: string[];
};
steps: AgentWorkflowStepUiConfig[];
}
@ -70,6 +74,7 @@ export interface AgentWorkflowPersistedState {
};
selections: Partial<Record<AgentWorkflowStepKey, string>>;
selectedAgentPresetId?: string | null;
currentStage?: "workflow" | "mode";
}
export interface AgentCategoryTreeConfig {