diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index 51f59db34..fa276d9e6 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -192,13 +192,8 @@ function applyOptimizedPromptToLatestUserMessage( (part): part is { type: "text"; text: string } => part.type === "text", ); const originalText = textPart?.text?.trim() || ""; - const normalizedOriginal = hiddenPromptPrefix && originalText.startsWith(hiddenPromptPrefix) - ? originalText.slice(hiddenPromptPrefix.length).trim() - : originalText; - const hasOriginalDemand = normalizedOriginal.length > 0; - const hasOriginalInOptimized = - hasOriginalDemand && - (prompt.includes(normalizedOriginal) || normalizedOriginal.includes(prompt)); + const { normalizedOriginal, hasOriginalDemand, hasOriginalInOptimized } = + analyzeOptimizedPromptMerge(originalText, prompt, hiddenPromptPrefix); const finalPrompt = hasOriginalDemand && !hasOriginalInOptimized ? [ hiddenPromptPrefix.trim(), @@ -227,6 +222,97 @@ function applyOptimizedPromptToLatestUserMessage( return cloned; } +function analyzeOptimizedPromptMerge( + originalText: string, + optimizedPrompt?: string, + hiddenPromptPrefix = "", +) { + const prompt = optimizedPrompt?.trim() || ""; + const trimmedOriginal = String(originalText || "").trim(); + const normalizedOriginal = + hiddenPromptPrefix && trimmedOriginal.startsWith(hiddenPromptPrefix) + ? trimmedOriginal.slice(hiddenPromptPrefix.length).trim() + : trimmedOriginal; + const hasOriginalDemand = normalizedOriginal.length > 0; + const hasOriginalInOptimized = + hasOriginalDemand && + (prompt.includes(normalizedOriginal) || normalizedOriginal.includes(prompt)); + + return { + prompt, + normalizedOriginal, + hasOriginalDemand, + hasOriginalInOptimized, + }; +} + +function buildOptimizedPromptPreview(params: { + originalText: string; + optimizedPrompt?: string; + hiddenPromptPrefix?: string; +}): string | undefined { + const { prompt, normalizedOriginal, hasOriginalDemand, hasOriginalInOptimized } = + analyzeOptimizedPromptMerge( + params.originalText, + params.optimizedPrompt, + params.hiddenPromptPrefix || "", + ); + + if (!prompt) return undefined; + + const normalizedPrompt = prompt.replace(/\s+/g, " ").trim(); + if (!normalizedPrompt) return undefined; + + if (hasOriginalDemand && !hasOriginalInOptimized) { + return [ + `- 核心目标:${normalizedOriginal.replace(/\s+/g, " ").trim()}`, + `- 优化提示词:${normalizedPrompt}`, + ].join("\n"); + } + + return `- ${normalizedPrompt}`; +} + +function injectOptimizedPromptSection(params: { + message?: string; + originalText: string; + optimizedPrompt?: string; + hiddenPromptPrefix?: string; +}): string | undefined { + const { message, originalText, optimizedPrompt, hiddenPromptPrefix } = params; + if (!message?.trim()) return message; + + const preview = buildOptimizedPromptPreview({ + originalText, + optimizedPrompt, + hiddenPromptPrefix, + }); + if (!preview) return message; + + const optimizedPromptSection = `【优化后提示词】\n${preview}`; + const optimizedSectionRegex = + /(?:###\s*优化后提示词|【\s*优化后提示词\s*】)[\s\S]*?(?=\n(?:###\s*|【\s*[^】]+\s*】)|$)/; + if (optimizedSectionRegex.test(message)) { + return message.replace(optimizedSectionRegex, optimizedPromptSection); + } + + const outputSectionRegex = /(?:###\s*输出设置|【\s*输出设置\s*】)/; + if (outputSectionRegex.test(message)) { + return message.replace(outputSectionRegex, `${optimizedPromptSection}\n$&`); + } + + const executionSectionRegex = + /(?:###\s*执行计划|【\s*执行计划\s*】)[\s\S]*?(?=\n(?:###\s*|【\s*[^】]+\s*】)|$)/; + if (executionSectionRegex.test(message)) { + return message.replace(executionSectionRegex, (matchedSection) => { + const trimmedSection = matchedSection.replace(/\s+$/, ""); + return `${trimmedSection}\n${optimizedPromptSection}`; + }); + } + + return `${message.trim()}\n\n${optimizedPromptSection}`; +} + type StreamWriter = { write: (chunk: any) => void; }; @@ -1435,6 +1521,7 @@ function normalizeAgentReportHeadingLine(line: string): string { "需求理解", "图片分析", "执行计划", + "优化后提示词", "输出设置", "脚本规划", "分镜规划", @@ -1580,7 +1667,7 @@ function buildAutoModeFallbackMessage(params: { function hasStructuredAgentSections(message?: string): boolean { if (!message) return false; - return /(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】)/.test( + return /(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】|###\s*优化后提示词|【\s*优化后提示词\s*】)/.test( message, ); } @@ -3578,6 +3665,11 @@ export async function POST(request: Request) { userImageParams: requestBody.imageParams, hasUserCustomImageParams, }); + smartAutoFriendlyMessage = injectOptimizedPromptSection({ + message: smartAutoFriendlyMessage, + originalText: requestTextContent, + optimizedPrompt: smartAutoOptimizedPrompt, + }); } if (shouldRunAgentConversation) { diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 914f767cb..553a6b752 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -585,6 +585,7 @@ const CANVAS_AGENT_SECTION_TITLES = new Set([ "需求理解", CANVAS_IMAGE_ANALYSIS_TITLE, "执行计划", + "优化后提示词", "输出设置", ]); const CANVAS_IMAGE_TASK_POLL_INTERVAL_MS = 1600; diff --git a/components/elements/response.tsx b/components/elements/response.tsx index 851e8f9dc..e67c83c7d 100644 --- a/components/elements/response.tsx +++ b/components/elements/response.tsx @@ -34,6 +34,7 @@ const AGENT_SECTION_TITLES = new Set([ "需求理解", IMAGE_ANALYSIS_TITLE, "执行计划", + "优化后提示词", "输出设置", ]); diff --git a/components/message.tsx b/components/message.tsx index b840bba61..7a4f948d5 100644 --- a/components/message.tsx +++ b/components/message.tsx @@ -174,7 +174,7 @@ function filterAgentRoutingNoise(text: string): string { const IMAGE_DONE_SUMMARY = "已完成本次生成,如需微调可继续告诉我。"; const ASSISTANT_TYPEWRITER_SECTION_REGEX = - /(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】|###\s*输出设置|【\s*输出设置\s*】)/; + /(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】|###\s*优化后提示词|【\s*优化后提示词\s*】|###\s*输出设置|【\s*输出设置\s*】)/; const ASSISTANT_TYPEWRITER_STORAGE_KEY = "assistant-typewriter-completed-keys-v1"; const MODEL_BADGE_LINE_REGEX = /^\s*[◈◇◆🔹⬡✦•·]\s*([^\n]+?)\s*$/im;