feat: 自动使用历史图片进行连续对话编辑
- 用户没有发送新图片时,自动使用历史中最近的图片 - 支持连续对话场景:换颜色、调整、重做等 - 优先使用AI生成的图片,其次是用户上传的图片 - 让对话更自然,不需要每次都重新上传图片 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
760509100c
commit
691e9862e7
@ -334,6 +334,7 @@ export async function POST(request: Request) {
|
||||
// 🆕 存储智能模式的相关信息
|
||||
let smartAutoFriendlyMessage: string | undefined; // AI的自然对话回复
|
||||
let smartAutoOptimizedPrompt: string | undefined; // 优化后的提示词(不修改用户消息,只用于API调用)
|
||||
let smartAutoHistoryImage: string | undefined; // 从历史对话中提取的图片URL
|
||||
|
||||
// ========== Smart Auto Mode Logic ==========
|
||||
if (finalModelId === "auto") {
|
||||
@ -348,16 +349,68 @@ export async function POST(request: Request) {
|
||||
.join(" ");
|
||||
|
||||
// @ts-ignore - 检查各种可能的图片类型
|
||||
const hasImage = lastUserMessage.parts.some(
|
||||
let hasImage = lastUserMessage.parts.some(
|
||||
(p: any) => p.type === "file" || p.type === "image" || p.type === "image_url"
|
||||
);
|
||||
|
||||
// @ts-ignore - 提取图片URL
|
||||
const imageUrls = lastUserMessage.parts
|
||||
let imageUrls = lastUserMessage.parts
|
||||
.filter((p: any) => p.type === "file" && p.url)
|
||||
.map((p: any) => p.url as string);
|
||||
|
||||
console.log("[Smart Auto Mode] Input:", { textContent: textContent.substring(0, 100), hasImage, imageCount: imageUrls.length });
|
||||
// 🆕 历史图片上下文感知:如果用户没有发送新图片,自动使用历史中最近的图片
|
||||
// 逻辑:只要用户在对话中没有附上新图片,就默认继续处理之前的图片
|
||||
if (!hasImage && messagesFromDb.length > 0) {
|
||||
console.log("[Smart Auto Mode] 🔍 No image in current message, auto-searching history...");
|
||||
|
||||
// 从历史消息中倒序查找最近的图片
|
||||
// 优先找AI生成的图片(用户可能想修改生成结果),其次是用户上传的图片
|
||||
for (let i = messagesFromDb.length - 1; i >= 0; i--) {
|
||||
const msg = messagesFromDb[i];
|
||||
const parts = msg.parts as any[];
|
||||
|
||||
if (!parts) continue;
|
||||
|
||||
// 查找文本中的Markdown图片(AI生成的)
|
||||
if (msg.role === "assistant") {
|
||||
for (const part of parts) {
|
||||
if (part.type === "text" && part.text) {
|
||||
// 匹配Markdown图片格式: 
|
||||
const imgMatch = part.text.match(/!\[.*?\]\((https?:\/\/[^\s)]+)\)/);
|
||||
if (imgMatch && imgMatch[1]) {
|
||||
smartAutoHistoryImage = imgMatch[1];
|
||||
console.log("[Smart Auto Mode] 🖼️ Found AI-generated image:", smartAutoHistoryImage.substring(0, 80));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找用户上传的图片
|
||||
if (msg.role === "user" && !smartAutoHistoryImage) {
|
||||
for (const part of parts) {
|
||||
if ((part.type === "file" || part.type === "image") && part.url) {
|
||||
smartAutoHistoryImage = part.url;
|
||||
console.log("[Smart Auto Mode] 🖼️ Found user-uploaded image:", smartAutoHistoryImage.substring(0, 80));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (smartAutoHistoryImage) break;
|
||||
}
|
||||
|
||||
// 如果找到了历史图片,标记为有图片
|
||||
if (smartAutoHistoryImage) {
|
||||
hasImage = true;
|
||||
imageUrls = [smartAutoHistoryImage];
|
||||
console.log("[Smart Auto Mode] ✅ Auto-using history image for context continuity");
|
||||
} else {
|
||||
console.log("[Smart Auto Mode] ℹ️ No image found in history, proceeding as pure text");
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[Smart Auto Mode] Input:", { textContent: textContent.substring(0, 100), hasImage, imageCount: imageUrls.length, fromHistory: !!smartAutoHistoryImage });
|
||||
|
||||
// 2. 调用智能分析器
|
||||
const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
|
||||
@ -365,6 +418,7 @@ export async function POST(request: Request) {
|
||||
text: textContent,
|
||||
hasImage,
|
||||
imageUrls,
|
||||
imageFromHistory: !!smartAutoHistoryImage, // 🆕 标识图片是否来自历史
|
||||
});
|
||||
|
||||
console.log("[Smart Auto Mode] Analysis result:", {
|
||||
@ -943,6 +997,29 @@ export async function POST(request: Request) {
|
||||
}));
|
||||
}
|
||||
|
||||
// 🆕 如果使用了历史图片,将其注入到消息中
|
||||
if (smartAutoHistoryImage && messagesForAlibaba.length > 0) {
|
||||
console.log("[Chat API] 🖼️ Injecting history image into message");
|
||||
messagesForAlibaba = messagesForAlibaba.map((msg) => {
|
||||
// 检查消息中是否已有图片
|
||||
const hasExistingImage = msg.parts.some(
|
||||
(p: any) => p.type === "file" || p.type === "image"
|
||||
);
|
||||
|
||||
if (!hasExistingImage) {
|
||||
// 注入历史图片
|
||||
return {
|
||||
...msg,
|
||||
parts: [
|
||||
...msg.parts,
|
||||
{ type: "file", url: smartAutoHistoryImage, mimeType: "image/png" },
|
||||
],
|
||||
};
|
||||
}
|
||||
return msg;
|
||||
});
|
||||
}
|
||||
|
||||
// 转换消息(阿里生图支持 URL,会自动上传 base64)
|
||||
const modelMessages = await convertMessagesWithImages(messagesForAlibaba, "alibaba-image");
|
||||
|
||||
|
||||
@ -39,12 +39,25 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
|
||||
- inpaint: 去除某物、消除、擦掉、P掉、局部修改
|
||||
- style_transfer: 风格化、卡通化、动漫风、改风格
|
||||
- color_adjust: 调色、调整颜色、亮度、对比度
|
||||
- redo: 用户不满意之前的结果,想重新处理
|
||||
|
||||
### vision - 图片理解(用户想让你看图说话)
|
||||
### image_gen - 图片生成(用户想生成新图片)
|
||||
### video_gen - 视频生成
|
||||
### chat - 普通对话
|
||||
|
||||
## 特殊场景:连续对话(用户没有发送新图片,系统自动使用历史图片)
|
||||
|
||||
当用户继续对话但没有发送新图片时,系统会自动找到之前的图片。这时候:
|
||||
- 用户可能在继续描述想要的效果(如:"换成蓝色"、"再清晰一点"、"把背景去掉")
|
||||
- 用户可能在修改之前的结果(如:"不满意"、"再调整"、"换个风格")
|
||||
- 用户可能在追问(如:"还可以再亮一点吗"、"能不能换个颜色")
|
||||
|
||||
处理方式:
|
||||
- intent 通常是 image_edit
|
||||
- subIntent 根据用户的具体要求判断
|
||||
- conversationalReply 要自然地回应用户,不需要特别强调"找到了之前的图片"
|
||||
|
||||
## 输出格式(严格JSON)
|
||||
{
|
||||
"intent": "image_edit",
|
||||
@ -86,6 +99,34 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
|
||||
"confidence": 0.5,
|
||||
"conversationalReply": "我看到你发了一张图片,你想对它做什么处理呢?比如抠图、换背景、变清晰?",
|
||||
"needsClarification": true
|
||||
}
|
||||
|
||||
连续对话场景 - 用户说"换成蓝色"(系统自动使用历史图片):
|
||||
{
|
||||
"intent": "image_edit",
|
||||
"subIntent": "color_adjust",
|
||||
"confidence": 0.9,
|
||||
"conversationalReply": "好的,我来帮你调整成蓝色~",
|
||||
"needsClarification": false
|
||||
}
|
||||
|
||||
连续对话场景 - 用户说"不满意,再调整一下":
|
||||
{
|
||||
"intent": "image_edit",
|
||||
"subIntent": "redo",
|
||||
"confidence": 0.8,
|
||||
"conversationalReply": "没问题,你想怎么调整呢?比如换个颜色、调整风格?",
|
||||
"needsClarification": true,
|
||||
"clarifyingQuestions": ["你具体想调整哪方面呢?"]
|
||||
}
|
||||
|
||||
连续对话场景 - 用户说"再清晰一点":
|
||||
{
|
||||
"intent": "image_edit",
|
||||
"subIntent": "enhance",
|
||||
"confidence": 0.9,
|
||||
"conversationalReply": "好的,我再帮你提升一下清晰度~",
|
||||
"needsClarification": false
|
||||
}`;
|
||||
|
||||
/**
|
||||
@ -95,10 +136,11 @@ export async function analyzeIntent(params: {
|
||||
text: string;
|
||||
hasImage: boolean;
|
||||
imageUrls?: string[];
|
||||
imageFromHistory?: boolean; // 🆕 图片是否来自历史记录
|
||||
}): Promise<AnalysisResult> {
|
||||
const { text, hasImage, imageUrls } = params;
|
||||
const { text, hasImage, imageUrls, imageFromHistory } = params;
|
||||
|
||||
console.log("[Smart Analyzer] Analyzing intent:", { text, hasImage, imageCount: imageUrls?.length });
|
||||
console.log("[Smart Analyzer] Analyzing intent:", { text, hasImage, imageCount: imageUrls?.length, imageFromHistory });
|
||||
|
||||
// 先尝试关键词快速匹配(高置信度场景直接返回,节省LLM调用)
|
||||
const quickResult = quickKeywordMatch(text, hasImage);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user