From c177cbaf82660e42c1371589290e0faebe1393a6 Mon Sep 17 00:00:00 2001 From: wonder Date: Sun, 24 May 2026 21:16:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(prompt):=20AI=20=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=8D=E4=BC=98=E5=8C=96=E5=8F=8C=E6=A0=8F=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 prompt API 模块调用后端 /api/v1/prompt/optimize,PromptEditor 重构为左右双栏布局支持原始/优化提示词对比编辑,默认开启 AI 优化, 用户可关闭开关或手动编辑优化结果后再提交生成。 --- frontend/src/api/prompt.ts | 35 +++++++ .../src/components/GenerateForm.module.css | 98 +++++++++++++++++++ frontend/src/components/GenerateForm.tsx | 58 +++++++++-- frontend/src/components/PromptEditor.tsx | 79 +++++++++++++-- frontend/src/pages/GeneratePage.tsx | 6 +- frontend/src/stores/task.ts | 50 +++++++++- 6 files changed, 304 insertions(+), 22 deletions(-) create mode 100644 frontend/src/api/prompt.ts create mode 100644 frontend/src/components/GenerateForm.module.css diff --git a/frontend/src/api/prompt.ts b/frontend/src/api/prompt.ts new file mode 100644 index 0000000..0d41baf --- /dev/null +++ b/frontend/src/api/prompt.ts @@ -0,0 +1,35 @@ +import { post } from './client' +import { STYLE_CATEGORIES } from '../utils/style' + +interface OptimizePromptParams { + tags: string[] + assetType: string + prompt: string + userNote?: string +} + +interface OptimizePromptResponse { + prompt: string + rawText: string +} + +/** + * 从风格键值对中提取标签的中文名称作为 tags + */ +export function extractTags(style: Record): string[] { + return STYLE_CATEGORIES.flatMap(cat => { + const value = style[cat.key] + if (!value) return [] + const option = cat.options.find(o => o.value === value) + return option ? [option.label] : [] + }) +} + +/** + * 调用后端提示词优化接口 + */ +export async function optimizePrompt( + params: OptimizePromptParams, +): Promise { + return post('/api/v1/prompt/optimize', params) +} diff --git a/frontend/src/components/GenerateForm.module.css b/frontend/src/components/GenerateForm.module.css new file mode 100644 index 0000000..11efb51 --- /dev/null +++ b/frontend/src/components/GenerateForm.module.css @@ -0,0 +1,98 @@ +.promptPanels { + display: flex; + gap: 16px; +} + +.panel { + flex: 1; + display: flex; + flex-direction: column; + gap: 8px; +} + +.panelSingle { + composes: panel; + flex: 1; +} + +.panelLabel { + font-size: 13px; + font-weight: 600; + color: var(--text-secondary); +} + +.optimizedBadge { + font-size: 11px; + padding: 2px 8px; + border-radius: 10px; + background: var(--accent-dim); + color: var(--accent); + font-weight: 600; +} + +.textarea { + resize: vertical; + width: 100%; + min-height: 120px; +} + +.toggleRow { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 4px; +} + +.toggle { + position: relative; + width: 40px; + height: 22px; + border-radius: 11px; + border: none; + cursor: pointer; + transition: background-color 0.2s; + padding: 0; + flex-shrink: 0; +} + +.toggleOn { + background: var(--accent); +} + +.toggleOff { + background: var(--border); +} + +.toggleKnob { + position: absolute; + top: 2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: #fff; + transition: left 0.2s; +} + +.toggleKnobOn { + left: 20px; +} + +.toggleKnobOff { + left: 2px; +} + +.toggleLabel { + font-size: 13px; + color: var(--text-secondary); +} + +.optimizeBtn { + padding: 6px 16px; + font-size: 13px; +} + +@media (max-width: 640px) { + .promptPanels { + flex-direction: column; + } +} diff --git a/frontend/src/components/GenerateForm.tsx b/frontend/src/components/GenerateForm.tsx index e3c2ec0..40a05ec 100644 --- a/frontend/src/components/GenerateForm.tsx +++ b/frontend/src/components/GenerateForm.tsx @@ -13,7 +13,7 @@ const ASSET_TYPES: { value: AssetType; label: string }[] = [ ] interface GenerateFormProps { - onSubmit: () => void + onSubmit: (prompt: string) => void submitting: boolean } @@ -24,13 +24,32 @@ export default function GenerateForm({ onSubmit, submitting }: GenerateFormProps assetType, taskStyle, params, + enableAI, + optimizedPrompt, + isOptimizing, setPrompt, setAssetType, toggleTaskStyle, setParams, + setEnableAI, + setOptimizedPrompt, + runOptimize, } = useTaskStore() const mergedStyle = mergeStyles(projectStyle, taskStyle) + const finalPrompt = enableAI && optimizedPrompt ? optimizedPrompt : prompt + + const handleOptimize = async () => { + try { + await runOptimize(projectStyle) + } catch { + // error handled in store + } + } + + const handleSubmit = () => { + onSubmit(finalPrompt) + } return (
@@ -62,16 +81,41 @@ export default function GenerateForm({ onSubmit, submitting }: GenerateFormProps
- {/* 提示词 */} + {/* 提示词(含 AI 优化) */}
-

- 提示词 -

+
+

+ 提示词 +

+ {enableAI && ( + + )} +
@@ -113,8 +157,8 @@ export default function GenerateForm({ onSubmit, submitting }: GenerateFormProps