lovart3/lib/ai/smart-analyzer.ts
Your Name 760509100c fix: 保持用户消息原样显示,AI自然对话后再执行编辑
- 用户发送的消息不再被修改,保持原样显示
- 优化后的提示词只用于API调用,不影响用户消息
- AI会先用自然语言回复用户,再显示编辑结果

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-01-31 23:29:30 +08:00

349 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 智能意图分析器
* 分析用户输入,识别图片编辑意图
*
* 主要应用场景:图片编辑(抠图、换背景、增强等)
*/
import { generateText } from "ai";
import { getLanguageModelById } from "./dynamic-provider";
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
// 分析结果类型
export interface AnalysisResult {
intent: "image_edit" | "vision" | "image_gen" | "video_gen" | "chat";
subIntent?: string;
confidence: number;
optimizedPrompt?: string;
negativePrompt?: string;
suggestedModel?: string;
needsClarification?: boolean;
clarifyingQuestions?: string[];
conversationalReply?: string; // 🆕 自然对话回复
}
// 系统提示词 - 针对图片编辑场景优化,生成自然对话
const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用户会给你发送图片和编辑请求,你需要:
1. 理解用户想要对图片做什么
2. 用自然、友好的语气回复用户,告诉他你理解了他的需求并会帮他处理
3. 同时输出结构化的意图分析结果
## 意图分类
### image_edit - 图片编辑(用户上传了图片并想编辑)
子意图:
- remove_background: 抠图、去背景、透明背景
- replace_background: 换背景、改背景、白底
- enhance: 变清晰、高清、锐化、降噪
- extend: 扩展、拓展、延伸画布
- inpaint: 去除某物、消除、擦掉、P掉、局部修改
- style_transfer: 风格化、卡通化、动漫风、改风格
- color_adjust: 调色、调整颜色、亮度、对比度
### vision - 图片理解(用户想让你看图说话)
### image_gen - 图片生成(用户想生成新图片)
### video_gen - 视频生成
### chat - 普通对话
## 输出格式(严格JSON)
{
"intent": "image_edit",
"subIntent": "replace_background",
"confidence": 0.95,
"conversationalReply": "好的,我来帮你把背景换成白色!这样产品会更突出~",
"needsClarification": false,
"clarifyingQuestions": []
}
## 回复风格要求
- conversationalReply 要自然、友好、简洁
- 可以加一些语气词让对话更亲切,如"好的"、"没问题"、"~"等
- 说明你理解了什么需求,让用户知道你在做什么
- 如果意图不明确,礼貌地询问用户想要什么效果
## 示例
用户:"帮我把背景换成白色"
{
"intent": "image_edit",
"subIntent": "replace_background",
"confidence": 0.95,
"conversationalReply": "好的,我来帮你把背景换成纯白色,这样图片会更干净专业~",
"needsClarification": false
}
用户:"把这张图变清晰一点"
{
"intent": "image_edit",
"subIntent": "enhance",
"confidence": 0.9,
"conversationalReply": "收到!我来帮你提升图片清晰度,稍等一下~",
"needsClarification": false
}
用户发了图片但没说要做什么:
{
"intent": "image_edit",
"confidence": 0.5,
"conversationalReply": "我看到你发了一张图片,你想对它做什么处理呢?比如抠图、换背景、变清晰?",
"needsClarification": true
}`;
/**
* 分析用户意图
*/
export async function analyzeIntent(params: {
text: string;
hasImage: boolean;
imageUrls?: string[];
}): Promise<AnalysisResult> {
const { text, hasImage, imageUrls } = params;
console.log("[Smart Analyzer] Analyzing intent:", { text, hasImage, imageCount: imageUrls?.length });
// 先尝试关键词快速匹配(高置信度场景直接返回,节省LLM调用)
const quickResult = quickKeywordMatch(text, hasImage);
if (quickResult.confidence >= 0.9) {
console.log("[Smart Analyzer] Quick match result:", quickResult);
return quickResult;
}
// 尝试使用 Qwen3 VL 进行深度分析
try {
const llmResult = await analyzWithLLM(text, hasImage);
if (llmResult) {
console.log("[Smart Analyzer] LLM analysis result:", llmResult);
return llmResult;
}
} catch (error) {
console.error("[Smart Analyzer] LLM analysis failed:", error);
}
// 回退到完整关键词分析
const fallbackResult = fallbackKeywordAnalysis(text, hasImage);
console.log("[Smart Analyzer] Fallback result:", fallbackResult);
return fallbackResult;
}
/**
* 快速关键词匹配(高置信度场景)
* 🆕 现在返回低置信度,强制走LLM分析以获取自然对话回复
*/
function quickKeywordMatch(text: string, hasImage: boolean): AnalysisResult {
// 返回低置信度,强制走LLM分析以获取自然对话回复
// 只有LLM不可用时才会使用fallback
return {
intent: "chat",
confidence: 0.3,
};
}
/**
* 使用 LLM 进行深度分析
*/
async function analyzWithLLM(text: string, hasImage: boolean): Promise<AnalysisResult | null> {
// 获取千问3 VL 模型
const allModels = await getEnabledAiModelsWithProvider();
const qwenModel = allModels.find(
(m) => m.provider.type === "alibaba" && m.model.supportsVision
);
if (!qwenModel) {
console.log("[Smart Analyzer] No Qwen3 VL model found");
return null;
}
const model = await getLanguageModelById(qwenModel.model.id);
if (!model) {
console.log("[Smart Analyzer] Failed to get language model");
return null;
}
// 构建用户消息
const userMessage = hasImage
? `用户上传了图片,请求内容:"${text}"`
: `用户请求(无图片):"${text}"`;
console.log("[Smart Analyzer] Calling Qwen3 VL for analysis");
// 调用模型分析
const { text: responseText } = await generateText({
model,
system: ANALYZER_SYSTEM_PROMPT,
prompt: userMessage,
temperature: 0.1,
maxTokens: 300,
} as any);
// 解析JSON响应
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (jsonMatch) {
try {
const result = JSON.parse(jsonMatch[0]) as AnalysisResult;
return result;
} catch (e) {
console.error("[Smart Analyzer] Failed to parse LLM response:", e);
}
}
return null;
}
/**
* 回退方案:完整关键词匹配(当LLM不可用时使用)
* 🆕 添加了自然对话回复
*/
export function fallbackKeywordAnalysis(
text: string,
hasImage: boolean
): AnalysisResult {
const lowerText = text.toLowerCase();
// === 图片编辑场景(需要有图片) ===
if (hasImage) {
// 抠图/去背景
if (/抠图|去背景|透明背景|去背|扣图|移除背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "remove_background",
confidence: 0.9,
conversationalReply: "好的,我来帮你抠图,去除背景保留主体~",
};
}
// 换背景
if (/换背景|白底|改背景|背景换成|纯色背景|换成.*背景|替换.*背景/.test(lowerText)) {
// 提取背景颜色
const bgMatch = text.match(/(?:换成|改成|替换为|变成)(.+?)(?:背景|底|$)/);
const bg = bgMatch ? bgMatch[1].trim() : "白色";
return {
intent: "image_edit",
subIntent: "replace_background",
confidence: 0.9,
conversationalReply: `好的,我来帮你把背景换成${bg}~`,
};
}
// 图片增强
if (/变清晰|高清|锐化|降噪|提升质量|修复|清晰化|变清楚|画质/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "enhance",
confidence: 0.9,
conversationalReply: "收到,我来帮你提升图片清晰度~",
};
}
// 图像拓展
if (/扩展|拓展|延伸|扩图|outpainting|拓宽|扩大/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "extend",
confidence: 0.9,
conversationalReply: "好的,我来帮你扩展图片边界~",
};
}
// 局部修改/去除
if (/去除|消除|擦掉|P掉|p掉|删除|修改.*部分|移除.*(?:人|物|水印|logo|文字)/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "inpaint",
confidence: 0.9,
conversationalReply: "明白,我来帮你处理这个区域~",
};
}
// 风格迁移
if (/风格|卡通化|动漫风|油画风|转.*风格|变.*风格|改.*风格/.test(lowerText)) {
const styleMatch = text.match(/(?:转换为|变成|改成|转成)(.+?)(?:风格|$)/);
const style = styleMatch ? styleMatch[1].trim() : "新";
return {
intent: "image_edit",
subIntent: "style_transfer",
confidence: 0.9,
conversationalReply: `好的,我来帮你转换成${style}风格~`,
};
}
// 调色
if (/调色|调整颜色|亮度|对比度|饱和度|色调|曝光|滤镜/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "color_adjust",
confidence: 0.9,
conversationalReply: "收到,我来帮你调整图片色彩~",
};
}
// 尺寸调整
if (/缩放|放大|缩小|调整尺寸|裁剪|resize|crop/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "resize",
confidence: 0.9,
conversationalReply: "好的,我来帮你调整图片尺寸~",
};
}
// 通用编辑关键词
if (/修图|P图|改图|调图|处理.*图|编辑.*图|优化.*图/.test(lowerText)) {
return {
intent: "image_edit",
confidence: 0.8,
needsClarification: true,
conversationalReply: "我看到你想编辑这张图片,你具体想要做什么处理呢?比如抠图、换背景、变清晰?",
};
}
// 视觉理解
if (/看|识别|分析|描述|这是什么|有什么|tell me|what is|看看|帮我看/.test(lowerText)) {
return {
intent: "vision",
confidence: 0.85,
conversationalReply: "让我来看看这张图片~",
};
}
// 有图但意图不明确
return {
intent: "image_edit",
confidence: 0.5,
needsClarification: true,
conversationalReply: "我看到你发了一张图片,你想对它做什么处理呢?比如抠图、换背景、变清晰?",
};
}
// === 无图片场景 ===
// 图片生成
if (/画|绘制|生成图|创建.*图|设计.*图|画一个|生成一张|做一张/.test(lowerText)) {
return {
intent: "image_gen",
confidence: 0.85,
conversationalReply: "好的,我来帮你生成这张图片~",
};
}
// 视频生成
if (/视频|动画|动起来|生成视频|做视频|视频生成/.test(lowerText)) {
return {
intent: "video_gen",
confidence: 0.85,
conversationalReply: "好的,我来帮你生成视频~",
};
}
// 需要图片但没有上传
if (/抠图|去背景|换背景|修图|P图|编辑图/.test(lowerText)) {
return {
intent: "image_edit",
confidence: 0.7,
needsClarification: true,
conversationalReply: "你想编辑图片的话,需要先上传一张图片哦~",
};
}
// 默认对话
return { intent: "chat", confidence: 0.7 };
}