refactor(image): rebuild reference prompt pipeline

- Introduce the new reference prompt composition and migration template pipeline
- Replace the legacy image prompt extraction path and align template loading contracts
- Update text2image workspace integration and add reference pipeline coverage
This commit is contained in:
linshen
2026-03-30 22:08:41 +08:00
parent 6024d003af
commit c33f5973a3
25 changed files with 2196 additions and 402 deletions

View File

@@ -0,0 +1,519 @@
# Reference Image Dialog Redesign Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Rework the text-to-image reference-image dialog into a simpler, clearer flow with thumbnail-first context, user-facing mode names, no undo complexity, and a hard 5-variable cap.
**Architecture:** Keep the existing three-stage reference pipeline intact (`ReferenceSpec -> PromptDraft -> VariableizedPrompt`) and only reshape the dialog state, layout, copy, and variable extraction policy around it. Treat the modal as a confirmation-and-light-edit surface rather than a strongly synchronized editor, so prompt text and variables can diverge temporarily without triggering re-extraction logic.
**Tech Stack:** Vue 3, Naive UI, TypeScript, Vitest, existing core template system
---
## File Map
### Core files to modify
- `packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue`
- Reference-image modal structure, layout, user-facing wording hooks, thumbnail presentation, and removal of undo banner UI.
- `packages/ui/src/composables/image/useReferencePromptDialog.ts`
- Dialog state model, removal of apply snapshot/undo, addition of current-prompt preview state if needed.
- `packages/ui/src/services/ImageStyleExtractor.ts`
- Service-layer variable cap and any helper for trimming extracted variables to 5 high-priority entries.
- `packages/ui/src/i18n/locales/zh-CN.ts`
- Main Chinese copy changes for the dialog.
- `packages/ui/src/i18n/locales/zh-TW.ts`
- Traditional Chinese parity for the same copy.
- `packages/ui/src/i18n/locales/en-US.ts`
- English parity for the same copy.
- `packages/core/src/services/template/default-templates/variable-extraction/extraction.ts`
- Tighten extraction policy and cap guidance to 5 variables in Chinese.
- `packages/core/src/services/template/default-templates/variable-extraction/extraction_en.ts`
- Tighten extraction policy and cap guidance to 5 variables in English.
### Test files to modify
- `packages/ui/tests/unit/composables/useReferencePromptDialog.spec.ts`
- Update expectations away from undo and toward simplified apply behavior.
- `packages/ui/tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts`
- Add assertions for the 5-variable hard cap and final-prompt-only retention.
- `packages/ui/tests/unit/image/reference-image-theme-guards.spec.ts`
- Update source guard assertions to match thumbnail layout, no undo banner, and controlled modal sizing.
### Optional new tests
- `packages/ui/tests/unit/image/reference-image-dialog-layout.spec.ts`
- Add only if the existing theme guard becomes too brittle to express the new structure cleanly.
---
### Task 1: Simplify Dialog State and Remove Undo
**Files:**
- Modify: `packages/ui/src/composables/image/useReferencePromptDialog.ts`
- Test: `packages/ui/tests/unit/composables/useReferencePromptDialog.spec.ts`
- [ ] **Step 1: Write the failing composable test for “apply without undo”**
```ts
it('applies prompt and variables without exposing undo state', () => {
const dialog = useReferencePromptDialog(/* ... */)
dialog.openDialog()
dialog.setGeneratedPreview(createPreview())
dialog.applyToCurrentPrompt()
expect(dialog).not.toHaveProperty('canUndoLastApply')
expect(dialog).not.toHaveProperty('undoLastApply')
})
```
- [ ] **Step 2: Add a failing test for current-prompt preview behavior**
```ts
it('stores detected current prompt for preview while keeping full prompt available for migration decisions', () => {
const dialog = useReferencePromptDialog(/* original prompt is long text */)
dialog.openDialog()
expect(dialog.detectedOriginalPrompt.value).toContain('当前提示词')
})
```
Note:
- If the implementation chooses a computed preview string instead of a second ref, assert the chosen public API instead of inventing a new property.
- [ ] **Step 3: Run the composable test file**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/composables/useReferencePromptDialog.spec.ts
```
Expected:
- FAIL because undo APIs still exist and the new preview expectation is not implemented yet.
- [ ] **Step 4: Remove undo state from the composable**
Implementation direction:
```ts
// Remove:
// - lastApplySnapshot
// - canUndoLastApply
// - undoLastApply()
const applyToCurrentPrompt = () => {
if (!canApply.value) return false
options.applyPrompt(workingPrompt.value)
options.applyVariables(cloneVariables(workingVariables.value))
options.resetPromptArtifacts?.()
closeDialog()
return true
}
```
- [ ] **Step 5: Add or expose a small current-prompt preview value**
Implementation direction:
```ts
const detectedOriginalPromptPreview = computed(() =>
detectedOriginalPrompt.value.trim(),
)
```
Rules:
- Keep the full original prompt for mode-switch logic.
- Let the workspace decide how many lines to show visually.
- [ ] **Step 6: Re-run the composable tests**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/composables/useReferencePromptDialog.spec.ts
```
Expected:
- PASS
- [ ] **Step 7: Commit**
```powershell
git add packages/ui/src/composables/image/useReferencePromptDialog.ts packages/ui/tests/unit/composables/useReferencePromptDialog.spec.ts
git commit -m "refactor(ui): simplify reference dialog state"
```
---
### Task 2: Rebuild the Modal Information Architecture and Layout
**Files:**
- Modify: `packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue`
- Test: `packages/ui/tests/unit/image/reference-image-theme-guards.spec.ts`
- [ ] **Step 1: Write the failing UI source guard updates**
Add expectations for:
- thumbnail-oriented reference image block
- separate detected-current-prompt section
- `风格迁移 / 复刻图片` copy hooks
- no undo banner markup
Example:
```ts
expect(source).toMatch(/reference-dialog-context-grid/)
expect(source).toMatch(/reference-dialog-thumbnail/)
expect(source).toMatch(/detectedCurrentPromptTitle/)
expect(source).not.toMatch(/reference-image-undo-button/)
expect(source).not.toMatch(/undoBanner/)
```
- [ ] **Step 2: Run the UI source guard test**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/image/reference-image-theme-guards.spec.ts
```
Expected:
- FAIL because the current modal still uses the old arrangement and undo markup.
- [ ] **Step 3: Replace the large reference preview with a compact thumbnail layout**
Implementation direction inside `ImageText2ImageWorkspace.vue`:
```vue
<div class="reference-dialog-source-row">
<button class="reference-dialog-thumbnail">
<NImage ... />
</button>
<div class="reference-dialog-source-meta">
<NText strong>{{ referenceDialog.sourceImageName || t(...) }}</NText>
<NText depth="3">{{ t('imageWorkspace.referenceImage.sourceImageHint') }}</NText>
<NButton size="small" secondary>{{ ... }}</NButton>
</div>
</div>
```
Rules:
- Thumbnail should not dominate vertical space.
- Keep Naive UI theming and avoid hardcoded light-only backgrounds.
- [ ] **Step 4: Split “detected current prompt” into its own section**
Implementation direction:
```vue
<NCard v-if="referenceDialog.showModeSwitch" ...>
<NText strong>{{ t('imageWorkspace.referenceImage.detectedCurrentPromptTitle') }}</NText>
<NText depth="3" class="reference-dialog-current-prompt-preview">
{{ referenceDialog.detectedOriginalPromptPreview }}
</NText>
</NCard>
```
Rules:
- Show only preview text visually via CSS line clamp.
- Do not place it under the usage-mode heading.
- [ ] **Step 5: Convert the mode selector into user-facing option cards**
Implementation direction:
```vue
<NRadioGroup ...>
<div class="reference-dialog-mode-grid">
<label class="reference-dialog-mode-card">
<NRadio value="migrate" />
<NText strong>{{ t('imageWorkspace.referenceImage.styleTransfer') }}</NText>
<NText depth="3">{{ t('imageWorkspace.referenceImage.styleTransferDescription') }}</NText>
</label>
</div>
</NRadioGroup>
```
Rules:
- Preserve the underlying radio semantics.
- Increase selection clarity with border/background states derived from theme tokens.
- [ ] **Step 6: Move the result area to a mixed layout**
Implementation direction:
```vue
<div class="reference-dialog-results-grid">
<NCard class="reference-dialog-section reference-dialog-section--prompt">...</NCard>
<NCard class="reference-dialog-section reference-dialog-section--variables">...</NCard>
</div>
```
Rules:
- Desktop: `2fr / 1fr`
- Narrow widths: stack vertically
- Prompt textarea gets a stable minimum height
- Variable list gets a stable min/max height with scrolling
- [ ] **Step 7: Remove the undo banner from the workspace**
Delete:
- success alert block above the template/model controls
- `handleReferenceDialogUndo` wiring
- any `referenceDialog.canUndoLastApply` template branches
- [ ] **Step 8: Re-run the UI source guard test**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/image/reference-image-theme-guards.spec.ts
```
Expected:
- PASS
- [ ] **Step 9: Commit**
```powershell
git add packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue packages/ui/tests/unit/image/reference-image-theme-guards.spec.ts
git commit -m "feat(ui): redesign reference image dialog layout"
```
---
### Task 3: Update Dialog Copy Across Locales
**Files:**
- Modify: `packages/ui/src/i18n/locales/zh-CN.ts`
- Modify: `packages/ui/src/i18n/locales/zh-TW.ts`
- Modify: `packages/ui/src/i18n/locales/en-US.ts`
- [ ] **Step 1: Add a failing check in the UI source guard or locale-aware test**
If no locale test exists, extend the existing source guard to assert the new translation keys are referenced and old ones are gone.
Example:
```ts
expect(source).toMatch(/styleTransfer/)
expect(source).toMatch(/replicateImage/)
expect(source).not.toMatch(/migrateToCurrentPrompt/)
expect(source).not.toMatch(/replicateOnly/)
```
- [ ] **Step 2: Run the relevant test file**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/image/reference-image-theme-guards.spec.ts
```
Expected:
- FAIL until the component and locale keys agree.
- [ ] **Step 3: Update the locale entries**
Chinese target copy:
```ts
styleTransfer: "风格迁移",
styleTransferDescription: "在原提示词的基础上学习图片风格进行改造",
replicateImage: "复刻图片",
replicateImageDescription: "丢弃原始提示词内容,反推图片对应提示词",
detectedCurrentPromptTitle: "检测到当前提示词",
```
Also remove:
- `undoBanner`
- `undo`
- `undoSuccess`
- [ ] **Step 4: Keep cross-locale parity**
Do not leave `zh-TW` and `en-US` behind even if the main product language is Chinese.
- [ ] **Step 5: Re-run the UI test**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/image/reference-image-theme-guards.spec.ts
```
Expected:
- PASS
- [ ] **Step 6: Commit**
```powershell
git add packages/ui/src/i18n/locales/zh-CN.ts packages/ui/src/i18n/locales/zh-TW.ts packages/ui/src/i18n/locales/en-US.ts packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue packages/ui/tests/unit/image/reference-image-theme-guards.spec.ts
git commit -m "refactor(ui): update reference dialog copy"
```
---
### Task 4: Tighten Variable Extraction to 5 High-Value Variables
**Files:**
- Modify: `packages/core/src/services/template/default-templates/variable-extraction/extraction.ts`
- Modify: `packages/core/src/services/template/default-templates/variable-extraction/extraction_en.ts`
- Modify: `packages/ui/src/services/ImageStyleExtractor.ts`
- Test: `packages/ui/tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts`
- [ ] **Step 1: Add a failing service test for the 5-variable cap**
Example:
```ts
it('caps extracted variables at 5 entries', async () => {
const result = await extractPromptVariables({
prompt: SOME_PROMPT,
modelKey: 'text-model',
variableExtractionService: {
extract: vi.fn().mockResolvedValue({
variables: Array.from({ length: 7 }, (_, index) => ({
name: `变量${index + 1}`,
value: `${index + 1}`,
position: { originalText: `${index + 1}`, occurrence: 1 },
reason: 'test',
})),
}),
} as any,
})
expect(Object.keys(result.variableDefaults)).toHaveLength(5)
})
```
- [ ] **Step 2: Run the reference-migration service tests**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts
```
Expected:
- FAIL because no hard cap exists yet.
- [ ] **Step 3: Tighten the variable-extraction prompt templates**
Chinese and English template changes should:
- reduce max variable count from 20 to 5
- instruct the model to prioritize subject, count, color, key action, and key scene/style anchor
- avoid low-value decorative fragments
Example rule block:
```ts
- 5
-
-
```
- [ ] **Step 4: Add a hard-cap safeguard in `ImageStyleExtractor.ts`**
Implementation direction:
```ts
const MAX_REFERENCE_DIALOG_VARIABLES = 5
const limitedVariables = result.variables.slice(0, MAX_REFERENCE_DIALOG_VARIABLES)
const variableizedPrompt = replaceExtractedVariablesInPrompt(prompt, limitedVariables)
const keptVariableNames = scanVariablesFromValue(variableizedPrompt)
return {
prompt: variableizedPrompt,
variableDefaults: buildFilteredDefaultsFromExtractedVariables(keptVariableNames, limitedVariables),
rawText,
}
```
- [ ] **Step 5: Re-run the service tests**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts
```
Expected:
- PASS
- [ ] **Step 6: Commit**
```powershell
git add packages/core/src/services/template/default-templates/variable-extraction/extraction.ts packages/core/src/services/template/default-templates/variable-extraction/extraction_en.ts packages/ui/src/services/ImageStyleExtractor.ts packages/ui/tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts
git commit -m "refactor(image): cap reference dialog variables"
```
---
### Task 5: Final Verification and Manual Smoke Check
**Files:**
- Verify all files from Tasks 1-4
- Optional notes update in: `docs/superpowers/specs/2026-03-31-reference-image-dialog-redesign-design.md`
- [ ] **Step 1: Run the targeted UI and service tests together**
Run:
```powershell
pnpm -F @prompt-optimizer/ui test -- tests/unit/composables/useReferencePromptDialog.spec.ts tests/unit/image/reference-image-theme-guards.spec.ts tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts
```
Expected:
- PASS
- [ ] **Step 2: Run UI typecheck**
Run:
```powershell
pnpm -F @prompt-optimizer/ui typecheck
```
Expected:
- PASS
- [ ] **Step 3: Run a local manual smoke test**
Run:
```powershell
pnpm dev:fresh
```
Manual checklist:
- Open `http://127.0.0.1:18181/#/image/text2image`
- Click `参考图`
- Confirm there is no undo banner in the workspace after apply
- Confirm the reference image is shown as a thumbnail, not a large preview
- Confirm `检测到当前提示词` is separate from the mode area
- Confirm `风格迁移 / 复刻图片` are clearly distinguishable
- Confirm the prompt editor and variables panel both have stable visible height
If model/auth config blocks full end-to-end generation, still verify the static layout and state behavior around modal opening, mode switching, and absence of undo affordances.
- [ ] **Step 4: Commit the verified final state**
```powershell
git add packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue packages/ui/src/composables/image/useReferencePromptDialog.ts packages/ui/src/services/ImageStyleExtractor.ts packages/ui/src/i18n/locales/zh-CN.ts packages/ui/src/i18n/locales/zh-TW.ts packages/ui/src/i18n/locales/en-US.ts packages/core/src/services/template/default-templates/variable-extraction/extraction.ts packages/core/src/services/template/default-templates/variable-extraction/extraction_en.ts packages/ui/tests/unit/composables/useReferencePromptDialog.spec.ts packages/ui/tests/unit/image/reference-image-theme-guards.spec.ts packages/ui/tests/unit/services/ImageStyleExtractor.reference-migration.spec.ts
git commit -m "feat(ui): simplify reference image migration dialog"
```
---
## Notes for the Implementer
- Do not reintroduce “sync variables” or “undo once” under new names.
- Keep the modal built on Naive UI primitives and theme tokens.
- Prefer CSS line-clamp or constrained container height for current-prompt preview rather than trimming the underlying source text aggressively.
- Keep the three-stage service architecture intact; this plan is a UI and policy refinement, not a pipeline rewrite.
- If the workspace file becomes too hard to reason about, it is acceptable to extract a small presentational subcomponent for the mode cards or result grid, but only if it reduces complexity instead of spreading it.

View File

@@ -0,0 +1,434 @@
# 文生图参考图弹窗重构设计
## 背景
当前文生图中的“参考图”弹窗已经接入三段式内部链路:
1. `ReferenceSpec` 提取
2. `PromptDraft` 生成或迁移
3. `VariableizedPrompt` 抽取
但当前交互仍存在几个明显问题:
- 弹窗承担了过多“临时补救”职责,例如应用后撤销,导致状态复杂度偏高。
- “检测到当前提示词”被放在“怎么使用这张参考图”内部,信息层级不清晰。
- 模式命名偏实现视角,用户第一眼难以理解差异。
- 参考图预览区域占用空间过大,挤压了真正重要的结果编辑区。
- 变量区缺少明确产品边界,当前结果更像调试信息而不是可确认的产物。
- 当前变量提取策略过于宽松,不适合参考图迁移场景,容易抽出过多变量。
本次重构目标不是新增更强的自动能力,而是把参考图弹窗整理成一个更清晰、更可理解、更可确认的前置改造流程。
## 目标
### 产品目标
- 让用户能快速理解“这张参考图会怎么影响当前提示词”。
- 保持现有 `文生图 / 图生图` 一级入口和模板下拉不变。
- 让“参考图”成为清晰的前置改造工具,而不是半自动编辑器。
- 保留 prompt 与变量的人工微调能力,但删除不必要的状态补丁和联动复杂度。
### 交互目标
- 让弹窗第一眼就能看懂当前上下文、可选模式和最终结果。
- 把视觉重心从“参考图展示”转移到“生成后的提示词”和“变量预览”。
- 让模式命名直接对应用户心智,而不是内部实现术语。
### 技术目标
- 删除撤销链路及其相关状态。
- 保持三段式架构不变,只收敛 UI 结构、文案与变量策略。
- 把变量数量稳定控制在 5 个以内,并保证优先级一致。
## 非目标
- 不修改图生图工作区。
- 不新增收藏、URL、Garden 导入等参考来源。
- 不引入 prompt 与变量的实时双向同步。
- 不把参考图弹窗演化为 JSON 树编辑器或多步向导。
- 不改变现有优化按钮、模板选择、主工作区链路。
## 设计原则
### 1. 参考图是来源,不是主角
参考图用于确认风格来源是否正确,不应该占据大块主编辑空间。默认展示应为缩略图,而不是大图卡片。
### 2. 先交代上下文,再让用户做选择
“检测到当前提示词”属于系统当前上下文,应先独立告知用户,再让用户选择如何使用参考图。
### 3. 模式命名必须是用户语言
模式名称应直接表达结果差异,而不是实现逻辑。用户要看懂“风格迁移”和“复刻图片”,而不是推断“保留当前内容”和“按参考图生成”的含义。
### 4. 结果区是弹窗的视觉中心
弹窗应把主要空间分配给最终会被应用的两类结果:
- 生成后的提示词
- 提取到的变量
### 5. 简化优先于强一致
本期保留“初次生成时自动抽变量,之后允许手动改 prompt 和变量值”的弱一致策略,不引入自动重算或手动同步动作。
## 方案比较
### 方案 A纯纵向堆叠
按顺序纵向排列所有内容块:
- 参考图
- 检测到当前提示词
- 使用方式
- 生成后的提示词
- 变量预览
优点:
- 实现简单
- 信息顺序线性
缺点:
- 弹窗过长
- 重点区域不够突出
- prompt 与变量缺少工作台感
### 方案 B完全左右双栏
整个弹窗采用左右布局,把上下文和结果一起放入双栏。
优点:
- 可在桌面端压缩高度
- 对比感更强
缺点:
- 信息关系变复杂
- 辅助信息和核心结果抢空间
- 响应式和主题适配更容易出问题
### 方案 C上轻下重的混合布局
顶部为轻量上下文区,中部为模式选择,底部为结果工作区双栏。
结构为:
- 顶部:`参考图` 缩略图卡 + `检测到当前提示词` 摘要卡
- 中部:`风格迁移 / 复刻图片` 两张模式卡
- 底部:左侧 `生成后的提示词`,右侧 `提取到的变量`
优点:
- 信息优先级清晰
- 结果区获得足够空间
- 比纯双栏更稳,比纯纵向更紧凑
缺点:
- 需要对弹窗结构和样式做一次性整理
### 推荐方案
采用方案 C。它最符合当前产品定位也最容易沿用 Naive UI 和现有弹窗结构做稳定落地。
## 信息架构
### 1. 参考图
作为第一块区域展示,采用缩略图样式:
- 左侧固定尺寸缩略图,建议 `96x96``112x112`
- 右侧展示文件名、说明文字和“上传/更换图片”按钮
- 默认不展示大图,不占用额外垂直空间
- 点击缩略图时可沿用现有图片预览能力,但不作为默认状态
说明文案继续保留:
- `仅支持本地 PNG/JPEG最大 10MB`
### 2. 检测到当前提示词
仅在当前原始提示词非空时显示,作为独立信息卡片放在参考图区域之后。
展示规则:
- 标题:`检测到当前提示词`
- 只展示前 2 到 3 行摘要
- 超出内容省略,不展示完整正文
- 目的仅为帮助用户判断是否保留当前内容,避免把遗留文本误当成当前意图
该区域不承担编辑功能。
### 3. 怎么使用这张参考图
作为单独区域展示,不再混入当前提示词信息。
模式命名改为:
- `风格迁移`
- `复刻图片`
模式说明改为:
- `风格迁移`:在原提示词的基础上学习图片风格进行改造
- `复刻图片`:丢弃原始提示词内容,反推图片对应提示词
展示方式:
- 使用可点击卡片承载单选逻辑,而不是仅显示普通文字型 radio
- 卡片需有明显选中态,便于第一眼区分
规则:
- 当前提示词为空时,不显示模式切换,默认只走 `复刻图片`
- 当前提示词非空时,默认推荐 `风格迁移`
## 弹窗布局
### 桌面端
采用混合布局:
- 顶部上下文区:纵向排列两个轻量卡片
- `参考图`
- `检测到当前提示词`
- 中部模式区:两张模式卡横向排布
- 底部结果区:左右布局
- 左:`生成后的提示词`,宽度约 `2fr`
- 右:`提取到的变量`,宽度约 `1fr`
### 窄屏
底部结果区自动回退为纵向堆叠:
- 先显示 `生成后的提示词`
- 再显示 `提取到的变量`
### 弹窗尺寸
- 继续基于 Naive UI `NModal + NCard`
- 控制整体宽度,不允许回退为异常全屏
- 建议桌面宽度保持在 `min(880px, calc(100vw - 32px))` 左右的级别
- 保持主题跟随,避免硬编码浅色背景或阴影逻辑
## 结果编辑区设计
### 生成后的提示词
这是弹窗的主内容区,应具备稳定高度。
规则:
- 使用单个可编辑 textarea
- 不再展示“请先上传参考图生成预览”之类的说明文案
- 未生成前允许为空,但界面仍保留固定编辑区域
- 建议最小高度约 `260px ~ 320px`
- 加载中只显示轻量状态提示,不挤压编辑区高度
### 提取到的变量
作为结果工作区的一部分展示,而不是附属信息。
规则:
- 变量名只读
- 变量值可编辑
- 区域需具备明确最小高度和滚动能力
- 变量行之间保持稳定间距,避免像表单碎片一样堆在底部
## 变量策略
### 产品规则
- 变量只在首次生成预览时自动提取一次
- 用户编辑 prompt 后,不自动重算变量
- 不再提供“同步变量”或“重新提取变量”按钮
- 点击应用时:
- 直接采用当前 prompt 文本
- 直接采用当前变量区值
- 不再做额外重算
这意味着 prompt 与变量允许短暂不完全一致,这是有意的简化,不视为缺陷。
### 数量上限
变量总数必须控制在 5 个以内。
采用三层约束:
1. 参考图生成与迁移模板中,要求输出更适合少量高价值变量抽取的结构
2. 变量提取模板中明确要求最多返回 5 个变量,并按重要性排序
3. UI 服务层增加硬上限兜底,只保留前 5 个变量
### 优先级
优先保留以下变量类型:
- 主体
- 数量
- 颜色
- 关键动作
- 关键场景或核心风格锚点
低优先级项应避免被抽成变量:
- 细碎修饰词
- 重复限定词
- 对最终复用价值不高的局部装饰
## 状态与数据流
### 打开弹窗
1. 读取当前原始提示词
2. 若非空,生成摘要用于“检测到当前提示词”
3. 初始化模式:
- 有当前提示词时默认 `风格迁移`
- 无当前提示词时默认 `复刻图片`
4. 清空本次参考图预览结果
### 上传参考图后生成预览
#### 复刻图片
1. `extractReferenceSpecFromImage`
2. `composePromptFromReferenceSpec`
3. `extractPromptVariables`
4. 将结果填入弹窗中的 prompt 和变量区
#### 风格迁移
1. `extractReferenceSpecFromImage`
2. `migratePromptWithReferenceSpec`
3. `extractPromptVariables`
4. 将结果填入弹窗中的 prompt 和变量区
### 应用到当前提示词
1. 使用当前编辑框中的 prompt 作为最终文本
2. 使用当前变量区中的值覆盖当前临时变量
3. 关闭弹窗
4. 不再保留撤销快照
## 需要删除的复杂度
### 删除撤销链路
移除以下能力:
- 弹窗应用后的撤销提示条
- `lastApplySnapshot`
- `canUndoLastApply`
- `undoLastApply()`
- 相关 UI 按钮与成功提示
原因:
- 弹窗本身已承担最终确认职责
- 应用后撤销会引入额外状态与心智负担
- 不符合本功能“确认后替换”的简单模型
### 删除变量同步链路
移除或保持不存在以下能力:
- 手动同步变量
- 自动重算变量
- prompt 变更后的失焦刷新
- 变量与 prompt 的双向联动逻辑
原因:
- 这会把弹窗变成编辑器,不再是前置参考改造工具
- 当前 MVP 的价值在于快速得到一份可用起点,而不是维护强一致的数据模型
## 文案调整
### 主要文案
- `识图提取` 保持为 `参考图`
- `检测到当前提示词:{prompt}` 改为分离式标题和摘要内容,不再拼成一整句
- `保留当前内容` 改为 `风格迁移`
- `按参考图生成` 改为 `复刻图片`
### 模式说明
- `风格迁移`:在原提示词的基础上学习图片风格进行改造
- `复刻图片`:丢弃原始提示词内容,反推图片对应提示词
## 影响范围
### UI
- `packages/ui/src/components/image-mode/ImageText2ImageWorkspace.vue`
- `packages/ui/src/composables/image/useReferencePromptDialog.ts`
- `packages/ui/src/i18n/locales/zh-CN.ts`
- `packages/ui/src/i18n/locales/zh-TW.ts`
- `packages/ui/src/i18n/locales/en-US.ts`
### 服务与模板
- `packages/ui/src/services/ImageStyleExtractor.ts`
- `packages/core/src/services/template/default-templates/image-prompt-composition/`
- `packages/core/src/services/template/default-templates/image-prompt-migration/`
- `packages/core/src/services/template/default-templates/variable-extraction/`
## 错误处理
- 上传失败时,维持当前 prompt 和变量不变
- 参考图解析失败时,仅提示本次生成失败,不关闭弹窗
- 变量提取失败时,允许 prompt 继续展示,但变量区为空
- 当前提示词为空时,不展示模式选择,也不报错
## 测试要点
### 交互测试
- 弹窗不再显示应用后撤销提示
- 当前提示词非空时,先显示摘要,再显示模式选择
- 模式名称和说明文案已切换为 `风格迁移 / 复刻图片`
- 参考图区域使用缩略图,不再占用大图高度
- prompt 区和变量区有稳定高度
### 逻辑测试
- `风格迁移` 默认选中,仅在当前提示词非空时出现
- `复刻图片` 在当前提示词为空时自动生效
- 应用时不再保存撤销快照
- 编辑 prompt 不触发变量自动刷新
- 变量数量始终不超过 5 个
### 回归测试
- 未使用参考图时,文生图现有流程不变
- 图生图工作区不受影响
- 三段式内部服务链路保持不变
## 验收标准
- 用户能在首次打开弹窗时看懂“当前看到了什么”和“可以怎么用这张图”
- 参考图不再抢占主编辑区空间
- `风格迁移 / 复刻图片` 的语义差异无需额外解释即可理解
- 弹窗应用链路不再包含撤销和同步变量等补救型复杂度
- 变量数量被稳定控制在 5 个以内
## 实施建议
建议按以下顺序实施:
1. 先删状态复杂度
- 移除撤销状态与相关文案
2. 再改 UI 信息架构
- 缩略图参考图
- 当前提示词摘要卡
- 模式卡
- 底部混合布局
3. 最后收变量策略
- 提取模板收紧
- 服务层硬上限兜底
这样可以先把交互心智收干净,再保证变量结果稳定。