lovart3/lib/ai/smart-analyzer.ts
Your Name 04bd6dda32 fix: 修复智能分析器循环依赖导致的初始化错误
- 改用动态导入 getEnabledAiModelsWithProvider 和 getLanguageModelById
- 避免 Cannot access 'T' before initialization 错误

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

396 lines
13 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: 调色、调整颜色、亮度、对比度
- redo: 用户不满意之前的结果,想重新处理
### vision - 图片理解(用户想让你看图说话)
### image_gen - 图片生成(用户想生成新图片)
### video_gen - 视频生成
### chat - 普通对话
## 特殊场景:连续对话(用户没有发送新图片,系统自动使用历史图片)
当用户继续对话但没有发送新图片时,系统会自动找到之前的图片。这时候:
- 用户可能在继续描述想要的效果(如:"换成蓝色"、"再清晰一点"、"把背景去掉")
- 用户可能在修改之前的结果(如:"不满意"、"再调整"、"换个风格")
- 用户可能在追问(如:"还可以再亮一点吗"、"能不能换个颜色")
处理方式:
- intent 通常是 image_edit
- subIntent 根据用户的具体要求判断
- conversationalReply 要自然地回应用户,不需要特别强调"找到了之前的图片"
## 输出格式(严格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
}
连续对话场景 - 用户说"换成蓝色"(系统自动使用历史图片):
{
"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
}`;
/**
* 分析用户意图
*/
export async function analyzeIntent(params: {
text: string;
hasImage: boolean;
imageUrls?: string[];
imageFromHistory?: boolean; // 🆕 图片是否来自历史记录
}): Promise<AnalysisResult> {
const { text, hasImage, imageUrls, imageFromHistory } = params;
console.log("[Smart Analyzer] Analyzing intent:", { text, hasImage, imageCount: imageUrls?.length, imageFromHistory });
// 先尝试关键词快速匹配(高置信度场景直接返回,节省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> {
// 使用动态导入避免循环依赖问题
const { getEnabledAiModelsWithProvider } = await import("@/lib/db/queries");
const { getLanguageModelById } = await import("./dynamic-provider");
// 获取千问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 };
}