feat: 智能图片编辑系统 - 意图分析、提示词优化、模型路由

新增智能自动模式功能:
- smart-analyzer.ts: 智能意图分析器,识别抠图/换背景/增强等8种子意图
- prompt-optimizer.ts: 提示词优化器,将简单输入转为专业提示词
- model-router.ts: 智能模型路由器,根据意图选择最佳模型
- 修改route.ts集成新模块,替换原有关键词匹配逻辑

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name 2026-01-31 23:15:11 +08:00
parent 8d580ad3ab
commit 8763e8d53f
6 changed files with 3620 additions and 79 deletions

View File

@ -331,96 +331,113 @@ export async function POST(request: Request) {
let finalModelId = selectedChatModel; let finalModelId = selectedChatModel;
// ========== Auto Mode Logic ========== // ========== Smart Auto Mode Logic ==========
if (finalModelId === "auto") { if (finalModelId === "auto") {
console.log("[Auto Mode] Detecting intent..."); console.log("[Smart Auto Mode] 🚀 Starting intelligent analysis...");
const lastUserMessage = message;
const textContent = lastUserMessage.parts try {
.filter((p) => p.type === 'text') // 1. 提取用户消息内容
.map((p) => p.text) const lastUserMessage = message;
.join(' '); const textContent = lastUserMessage.parts
// @ts-ignore .filter((p): p is { type: "text"; text: string } => p.type === "text")
const hasImage = lastUserMessage.parts.some((p) => p.type === 'file' || p.type === 'image' || p.type === 'image_url'); .map((p) => p.text)
.join(" ");
// 获取所有可用模型 // @ts-ignore - 检查各种可能的图片类型
const allModels = await getEnabledAiModelsWithProvider(); const hasImage = lastUserMessage.parts.some(
console.log("[Auto Mode] Available models:", allModels.map(m => `${m.model.displayName} (视频:${m.model.displayName.includes('视频')}, 图片:${m.model.supportsImageGen}, 视觉:${m.model.supportsVision})`)); (p: any) => p.type === "file" || p.type === "image" || p.type === "image_url"
);
let bestModel = null;
// 智能意图识别 - 基于关键词匹配 // @ts-ignore - 提取图片URL
// 定义各类意图的关键词库 const imageUrls = lastUserMessage.parts
const videoKeywords = /(视频|video|movie|film|motion|mp4|avi|mov|wmv|flv|mkv|webm|m4v|生成视频|制作视频|创建视频|做视频|拍视频|录视频|录制|视频剪辑|剪辑视频|剪辑|编辑视频|sora|动起来|动画|animation|animate|animated|动态|动效|gif|clip|clips|短视频|长视频|影片|电影|微电影|宣传片|广告片|产品视频|演示视频|教程视频|mv|music video|片段|镜头|shot|场景|scene|特效|vfx|effects|转场|transition|字幕|subtitle|配音|dubbing|慢动作|快进|timelapse|延时)/i; .filter((p: any) => p.type === "file" && p.url)
.map((p: any) => p.url as string);
const imageEditKeywords = /(修图|P图|改图|调图|优化图片|美化图片|处理图片|编辑图片|编辑照片|编辑这张|编辑|edit photo|edit image|修改图片|调整图片|图片处理|照片处理|处理这张|处理照片|背景|background|去背景|换背景|改背景|背景色|去背|抠图|扣图|抠出|扣出|去除|移除|删除|擦除|消除|抹掉|清除|拿掉|弄掉|去掉|干掉|隐藏|遮挡|remove|delete|erase|wipe|clear|eliminate|change|modify|修改|变清晰|清晰化|锐化|sharpen|sharpening|模糊|blur|blurry|虚化|bokeh|散景|修复|repair|restoration|fix|还原|恢复|recover|处理|process|processing|换|改|替换|更换|转换|transform|replace|swap|exchange|调色|调整颜色|color grade|grading|配色|滤镜|filter|filters|effect|特效|effects|裁剪|剪裁|crop|cropping|cut|cutting|旋转|rotate|rotation|翻转|flip|flipping|mirror|镜像|mirroring|缩放|resize|resizing|scale|scaling|放大|enlarge|enlargement|zoom|zoom in|缩小|shrink|zoom out|增强|enhance|enhancement|improve|improvement|提升|升级|质量|quality|降噪|去噪|denoise|denoising|美颜|beauty|磨皮|smooth|smoothing|瘦脸|face slim|美白|whitening|lighten|lighting|亮度|brightness|对比度|contrast|饱和度|saturation|曝光|exposure|高光|highlight|阴影|shadow|锐度|sharpness|加水印|去水印|watermark|unwatermark|合成|composite|compositing|拼接|拼图|merge|merging|叠加|overlay|blend|blending|透明|transparency|alpha|蒙版|mask|masking)/i;
console.log("[Smart Auto Mode] Input:", { textContent: textContent.substring(0, 100), hasImage, imageCount: imageUrls.length });
const imageGenKeywords = /(画|绘制|绘|绘画|画出|画个|画一个|画一张|画面|帮我画|给我画|画张|绘图|生成图片|生成图像|生成照片|生成一个|生成张|创建图片|创建图像|做图|制图|作图|画图|画画|想要.*图|需要.*图|来张|来个|draw|paint|sketch|素描|速写|render|rendering|渲染|picture|photo|image|图像|图片|照片|生图|出图|生成一张|生成|create image|generate image|make image|produce|design|designing|设计|设计一个|插画|illustration|illustrate|漫画|comic|卡通|cartoon|anime|动漫|二次元|海报|poster|logo|标志|商标|图标|icon|banner|横幅|背景图|背景|壁纸|wallpaper|桌面|配图|封面|cover|缩略图|thumbnail|头像|profile|avatar|artwork|艺术作品|art|artistic|美术|fine art|素材|material|asset|概念图|concept art|平面|graphic|graphics|视觉|visual|可视化|visualization|infographic|信息图)/i;
// 2. 调用智能分析器
const visionKeywords = /(看|看看|看一下|看下|识别|认出|辨认|recognize|identify|这是什么|是什么|what is|what\'s|分析|analyze|analysis|描述|describe|description|解释|explain|讲解|tell me|说说|介绍|理解|understand|检测|detect|detection|找|找出|find|发现|observe|观察|examine|检查|读取|read|阅读|翻译图片|ocr|文字识别|提取文字|图片.*内容|照片.*内容|image.*content)/i; const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
const analysisResult = await analyzeIntent({
if (videoKeywords.test(textContent)) { text: textContent,
console.log("[Auto Mode] Intent: VIDEO - 视频生成"); hasImage,
bestModel = allModels.find(m => m.model.displayName.includes("视频")); imageUrls,
} });
// 2. 图片编辑:用户上传了图片并要求编辑
else if (hasImage && imageEditKeywords.test(textContent)) { console.log("[Smart Auto Mode] Analysis result:", {
console.log("[Auto Mode] Intent: IMAGE_EDIT - 图片编辑"); intent: analysisResult.intent,
bestModel = allModels.find(m => m.model.displayName.includes("图片编辑") || m.model.displayName.includes("编辑")); subIntent: analysisResult.subIntent,
if (!bestModel) { confidence: analysisResult.confidence,
bestModel = allModels.find(m => m.model.supportsVision && !m.model.displayName.includes("视频")); needsClarification: analysisResult.needsClarification,
});
// 3. 如果是图片编辑类意图,优化提示词
if (analysisResult.intent === "image_edit" && analysisResult.subIntent) {
const { optimizePrompt } = await import("@/lib/ai/prompt-optimizer");
const optimizedResult = optimizePrompt({
originalPrompt: textContent,
intent: analysisResult.intent,
subIntent: analysisResult.subIntent,
});
console.log("[Smart Auto Mode] ✨ Prompt optimized:", {
original: textContent.substring(0, 50),
optimized: optimizedResult.optimizedPrompt.substring(0, 100),
});
// 替换消息中的文本为优化后的提示词
message.parts = message.parts.map((part) => {
if (part.type === "text") {
return {
...part,
text: optimizedResult.optimizedPrompt,
};
}
return part;
});
} }
}
// 3. 图片生成:用户要求画图/生成图片(不需要上传图片) // 4. 路由到最佳模型
else if (imageGenKeywords.test(textContent)) { const { routeToModel } = await import("@/lib/ai/model-router");
console.log("[Auto Mode] Intent: IMAGE_GEN - 图片生成"); const routeResult = await routeToModel({
bestModel = allModels.find(m => m.model.displayName.includes("图片编辑") || m.model.supportsImageGen); intent: analysisResult.intent,
// 排除视频模型 subIntent: analysisResult.subIntent,
if (bestModel && bestModel.model.displayName.includes("视频")) { hasImage,
bestModel = allModels.find(m => (m.model.displayName.includes("图片编辑") || m.model.supportsImageGen) && !m.model.displayName.includes("视频")); });
finalModelId = routeResult.id;
console.log(`[Smart Auto Mode] ✅ Routed to: ${routeResult.displayName} (${routeResult.reason})`);
} catch (autoError) {
// 智能分析失败时,回退到简单逻辑
console.error("[Smart Auto Mode] ❌ Error, falling back:", autoError);
const allModels = await getEnabledAiModelsWithProvider();
// @ts-ignore - 检查各种可能的图片类型
const hasImage = message.parts.some(
(p: any) => p.type === "file" || p.type === "image" || p.type === "image_url"
);
// 简单回退:有图选图片模型,无图选默认模型
let bestModel = null;
if (hasImage) {
bestModel = allModels.find(m => m.model.supportsImageGen && !m.model.isSubModel);
} }
}
// 4. 多模态理解:用户上传了图片,想让AI看图理解内容
else if (hasImage && visionKeywords.test(textContent)) {
console.log("[Auto Mode] Intent: VISION - 多模态理解");
bestModel = allModels.find(m => m.model.displayName.includes("多模态") || m.model.supportsVision);
if (!bestModel) { if (!bestModel) {
bestModel = allModels.find(m => m.model.supportsVision && !m.model.displayName.includes("视频")); bestModel = allModels.find(m => m.model.isDefault && !m.model.isSubModel);
}
}
// 5. 多模态理解:用户上传了图片但没有明确意图(默认理解图片)
else if (hasImage) {
console.log("[Auto Mode] Intent: VISION - 多模态理解(图片已上传)");
bestModel = allModels.find(m => m.model.displayName.includes("多模态") || m.model.supportsVision);
if (!bestModel) {
bestModel = allModels.find(m => m.model.supportsVision);
}
}
// 6. 默认:普通文本对话
else {
console.log("[Auto Mode] Intent: CHAT - 普通对话");
// 优先使用多模态模型或默认模型
bestModel = allModels.find(m => m.model.displayName.includes("多模态"));
if (!bestModel) {
bestModel = allModels.find(m => m.model.isDefault);
} }
if (!bestModel && allModels.length > 0) { if (!bestModel && allModels.length > 0) {
bestModel = allModels[0]; bestModel = allModels.find(m => !m.model.isSubModel) || allModels[0];
}
if (bestModel) {
finalModelId = bestModel.model.id;
console.log(`[Smart Auto Mode] Fallback selected: ${bestModel.model.displayName}`);
} else {
return new ChatSDKError("bad_request:api", "No available models for auto mode").toResponse();
} }
} }
// 最终兜底
if (!bestModel && allModels.length > 0) {
bestModel = allModels.find(m => m.model.isDefault) || allModels[0];
}
if (bestModel) {
console.log(`[Auto Mode] ✅ Selected: ${bestModel.model.displayName} (${bestModel.model.id})`);
finalModelId = bestModel.model.id;
} else {
return new ChatSDKError("bad_request:api", "No available models for auto mode").toResponse();
}
} }
// ========== End Auto Mode Logic ========== // ========== End Smart Auto Mode Logic ==========
const session = await auth(); const session = await auth();

View File

@ -0,0 +1,755 @@
# 智能图片编辑 - 实施开发指南
> 版本: v1.0
> 日期: 2025-01-31
> 目标: 在聊天对话框中实现智能图片编辑功能
---
## 一、核心流程
```
用户在对话框中发送 [图片 + 文字]
│
▼
┌──────────────────────────────────────────────────────────────┐
│ POST /api/chat │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. 提取用户消息 │ │
│ │ - 图片 URL (from message.parts where type='file') │ │
│ │ - 文字内容 (from message.parts where type='text') │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2. 智能意图分析 (如果 modelId === 'auto') │ │
│ │ - 调用 Qwen3 VL 分析用户意图 │ │
│ │ - 返回: intent, subIntent, confidence │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3. 提示词优化 (仅图片编辑类意图) │ │
│ │ - 根据子意图选择模板 │ │
│ │ - 填充用户参数,生成专业提示词 │ │
│ │ - 添加负面提示词 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 4. 模型路由 │ │
│ │ - 根据意图选择最佳模型 │ │
│ │ - 图片编辑 → alibaba-image │ │
│ │ - 视觉理解 → alibaba (Qwen3 VL) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 5. 调用对应模型生成 │ │
│ │ - 使用优化后的提示词 │ │
│ │ - 传入用户图片 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 6. 返回结果到对话框 │ │
│ │ - 编辑后的图片 (Markdown格式) │ │
│ │ - 保存到数据库 │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
```
---
## 二、需要修改/创建的文件
### 2.1 新建文件
| 文件路径 | 作用 |
|---------|------|
| `lib/ai/smart-analyzer.ts` | 智能意图分析器 |
| `lib/ai/prompt-optimizer.ts` | 提示词优化器 |
| `lib/ai/model-router.ts` | 智能模型路由器 |
### 2.2 修改文件
| 文件路径 | 修改内容 |
|---------|---------|
| `app/(chat)/api/chat/route.ts` | Auto Mode 逻辑替换 |
---
## 三、详细代码实现
### 3.1 创建 `lib/ai/smart-analyzer.ts`
```typescript
/**
* 智能意图分析器
* 使用 Qwen3 VL 分析用户输入,识别图片编辑意图
*/
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[];
}
// 系统提示词 - 针对图片编辑场景优化
const ANALYZER_SYSTEM_PROMPT = `你是一个专业的图片编辑意图分析专家。请分析用户的请求,判断其意图类型。
## 意图分类(按优先级)
### 1. image_edit - 图片编辑(最高优先级,需要用户上传了图片)
子意图:
- remove_background: 抠图、去背景、透明背景、去除背景
- replace_background: 换背景、改背景、白底、场景替换、背景换成
- enhance: 变清晰、高清、锐化、降噪、提升质量、修复
- extend: 扩展、拓展、延伸、outpainting、扩图
- inpaint: 去除XX、消除、擦掉、修改XX部分、局部修改、P掉
- style_transfer: 风格化、卡通化、动漫风、油画风、改风格
- resize: 缩放、放大、缩小、调整尺寸、裁剪
- color_adjust: 调色、调整颜色、亮度、对比度、饱和度
### 2. vision - 图片理解(需要用户上传了图片)
触发词:看、识别、分析、描述、这是什么、有什么
### 3. image_gen - 图片生成(不需要上传图片)
触发词:画、绘制、生成图片、创建、设计
### 4. video_gen - 视频生成
触发词:视频、动画、动起来
### 5. chat - 普通对话(默认)
## 输出格式(严格JSON)
{
"intent": "image_edit",
"subIntent": "replace_background",
"confidence": 0.95,
"optimizedPrompt": "优化后的提示词",
"negativePrompt": "需要避免的内容",
"needsClarification": false,
"clarifyingQuestions": []
}
## 特殊规则
1. 如果用户上传了图片且有编辑类关键词 → image_edit
2. 如果用户上传了图片但意图不明确 → needsClarification: true,并提供澄清问题
3. 如果用户要求编辑但没上传图片 → needsClarification: true,提示"请上传图片"`;
/**
* 分析用户意图
*/
export async function analyzeIntent(params: {
text: string;
hasImage: boolean;
imageUrls?: string[];
}): Promise<AnalysisResult> {
const { text, hasImage, imageUrls } = params;
// 获取千问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, using fallback");
return fallbackKeywordAnalysis(text, hasImage);
}
try {
const model = await getLanguageModelById(qwenModel.model.id);
if (!model) {
return fallbackKeywordAnalysis(text, hasImage);
}
// 构建用户消息
const userMessage = hasImage
? `用户上传了图片,请求内容:"${text}"`
: `用户请求(无图片):"${text}"`;
console.log("[Smart Analyzer] Analyzing with Qwen3 VL:", userMessage);
// 调用模型分析
const { text: responseText } = await generateText({
model,
system: ANALYZER_SYSTEM_PROMPT,
prompt: userMessage,
temperature: 0.1, // 低温度保证稳定输出
maxTokens: 500,
});
// 解析JSON响应
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const result = JSON.parse(jsonMatch[0]) as AnalysisResult;
console.log("[Smart Analyzer] Analysis result:", result);
return result;
}
} catch (error) {
console.error("[Smart Analyzer] Error:", error);
}
// 出错时使用回退逻辑
return fallbackKeywordAnalysis(text, hasImage);
}
/**
* 回退方案:关键词匹配
*/
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,
};
}
// 换背景
if (/换背景|白底|改背景|背景换成|纯色背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "replace_background",
confidence: 0.9,
};
}
// 图片增强
if (/变清晰|高清|锐化|降噪|提升质量|修复/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "enhance",
confidence: 0.9,
};
}
// 图像拓展
if (/扩展|拓展|延伸|扩图/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "extend",
confidence: 0.9,
};
}
// 局部修改
if (/去除|消除|擦掉|P掉|修改.*部分/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "inpaint",
confidence: 0.9,
};
}
// 风格迁移
if (/风格|卡通化|动漫风|油画风/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "style_transfer",
confidence: 0.9,
};
}
// 视觉理解
if (/看|识别|分析|描述|这是什么|有什么/.test(lowerText)) {
return { intent: "vision", confidence: 0.8 };
}
// 有图但意图不明确
return {
intent: "image_edit",
confidence: 0.5,
needsClarification: true,
clarifyingQuestions: [
"您想对这张图片做什么处理?(抠图/换背景/变清晰/其他)",
],
};
}
// 无图情况
if (/画|绘制|生成图|创建.*图/.test(lowerText)) {
return { intent: "image_gen", confidence: 0.8 };
}
if (/视频|动画|动起来/.test(lowerText)) {
return { intent: "video_gen", confidence: 0.8 };
}
// 默认对话
return { intent: "chat", confidence: 0.7 };
}
export { fallbackKeywordAnalysis };
```
### 3.2 创建 `lib/ai/prompt-optimizer.ts`
```typescript
/**
* 提示词优化器
* 将用户简单输入转换为专业的图片编辑提示词
*/
// 优化结果类型
export interface OptimizeResult {
originalPrompt: string;
optimizedPrompt: string;
negativePrompt: string;
}
// 图片编辑子意图的提示词模板
const EDIT_TEMPLATES: Record<
string,
{
template: string;
negative: string;
extractors: Record<string, RegExp>;
}
> = {
remove_background: {
template:
"去除图片背景,保留主体完整,输出透明背景PNG格式,边缘处理平滑自然,保留细节(如发丝、毛发)",
negative: "残留背景,毛边,边缘模糊,主体不完整,锯齿",
extractors: {},
},
replace_background: {
template:
"将图片背景替换为{background},保持主体完整清晰,光影自然协调,边缘过渡平滑,保留主体阴影",
negative: "残留原背景,边缘不自然,光影不协调,透视错误,主体变形",
extractors: {
background: /(?:换成|改成|替换为|变成|换为)(.+?)(?:背景|底|$)/,
},
},
enhance: {
template:
"提升图片整体清晰度和质量,保持自然色彩不失真,去除噪点,增强细节,适度锐化",
negative: "过度锐化,色彩失真,噪点增加,伪影,画质下降",
extractors: {},
},
extend: {
template:
"向{direction}方向扩展图片{amount},保持原有风格和色调一致,光影过渡自然,无明显接缝",
negative: "风格不一致,明显接缝,透视错误,内容突变",
extractors: {
direction: /向?(上|下|左|右|四周)/,
amount: /(\d+%?)/,
},
},
inpaint: {
template:
"去除/修改图片中的{target},用周围环境自然填充,保持整体风格一致,无修复痕迹",
negative: "明显修复痕迹,风格不一致,内容错误,边缘不自然",
extractors: {
target: /(?:去除|消除|擦掉|删除|P掉)(.+?)(?:,|。|$)/,
},
},
style_transfer: {
template:
"将图片转换为{style}风格,保持主体可识别性,色彩风格协调,整体效果自然",
negative: "主体变形,特征丢失,风格不统一,色彩异常",
extractors: {
style: /(?:转换为|变成|改成)(.+?)(?:风格|$)/,
},
},
resize: {
template: "调整图片尺寸为{size},保持画质清晰,比例协调",
negative: "画质损失,比例失调,模糊",
extractors: {
size: /(\d+[x×]\d+|\d+%)/,
},
},
color_adjust: {
template: "调整图片{adjustment},保持自然效果,色彩协调",
negative: "色彩失真,过度调整,不自然",
extractors: {
adjustment: /(?:调整|增加|减少|提高|降低)(.+?)(?:,|。|$)/,
},
},
};
/**
* 优化提示词
*/
export function optimizePrompt(params: {
originalPrompt: string;
intent: string;
subIntent?: string;
}): OptimizeResult {
const { originalPrompt, intent, subIntent } = params;
// 只对图片编辑类意图进行优化
if (intent !== "image_edit" || !subIntent) {
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印",
};
}
const template = EDIT_TEMPLATES[subIntent];
if (!template) {
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印",
};
}
// 使用模板生成优化后的提示词
let optimizedPrompt = template.template;
// 从用户输入中提取参数并填充模板
for (const [key, regex] of Object.entries(template.extractors)) {
const match = originalPrompt.match(regex);
const value = match ? match[1].trim() : getDefaultValue(key);
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, value);
}
// 附加用户原始意图
optimizedPrompt = `${optimizedPrompt}。\n\n用户原始要求:${originalPrompt}`;
console.log("[Prompt Optimizer] Optimized:", {
original: originalPrompt,
optimized: optimizedPrompt,
negative: template.negative,
});
return {
originalPrompt,
optimizedPrompt,
negativePrompt: template.negative,
};
}
/**
* 获取参数默认值
*/
function getDefaultValue(key: string): string {
const defaults: Record<string, string> = {
background: "纯白色",
direction: "四周",
amount: "50%",
target: "指定区域",
style: "卡通",
size: "原尺寸",
adjustment: "颜色",
};
return defaults[key] || "默认";
}
```
### 3.3 创建 `lib/ai/model-router.ts`
```typescript
/**
* 智能模型路由器
* 根据用户意图选择最佳模型
*/
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
// 路由结果类型
export interface RouteResult {
id: string;
displayName: string;
providerType: string;
reason: string;
}
// 意图到模型的映射配置
const INTENT_MODEL_MAP: Record<
string,
{
providerTypes: string[];
requireVision?: boolean;
requireImageGen?: boolean;
}
> = {
// 图片编辑:优先 alibaba-image(灵魂4.5)
image_edit: {
providerTypes: ["alibaba-image", "gemini"],
requireVision: true,
requireImageGen: true,
},
// 视觉理解:优先千问3 VL(成本低效果好)
vision: {
providerTypes: ["alibaba", "gemini"],
requireVision: true,
},
// 图片生成
image_gen: {
providerTypes: ["alibaba-image", "gemini", "volcano-vision"],
requireImageGen: true,
},
// 视频生成
video_gen: {
providerTypes: ["volcano-video", "qianwen-video"],
},
// 普通对话
chat: {
providerTypes: ["alibaba", "openai"],
},
};
/**
* 路由到最佳模型
*/
export async function routeToModel(params: {
intent: string;
subIntent?: string;
hasImage: boolean;
}): Promise<RouteResult> {
const { intent, subIntent, hasImage } = params;
console.log("[Model Router] Routing for intent:", intent, subIntent);
// 获取所有可用模型
const allModels = await getEnabledAiModelsWithProvider();
// 获取意图对应的配置
const config = INTENT_MODEL_MAP[intent] || INTENT_MODEL_MAP["chat"];
// 按优先级查找匹配的模型
for (const providerType of config.providerTypes) {
const candidates = allModels.filter((m) => {
// 匹配 provider 类型
if (m.provider.type !== providerType) return false;
// 检查能力要求
if (config.requireVision && !m.model.supportsVision) return false;
if (config.requireImageGen && !m.model.supportsImageGen) return false;
// 排除子模型
if (m.model.isSubModel) return false;
// 必须启用
if (!m.model.isEnabled) return false;
return true;
});
if (candidates.length > 0) {
// 优先选择默认模型
const defaultModel = candidates.find((c) => c.model.isDefault);
const selected = defaultModel || candidates[0];
const result: RouteResult = {
id: selected.model.id,
displayName: selected.model.displayName,
providerType: selected.provider.type,
reason: `${intent}${subIntent ? `/${subIntent}` : ""} → ${selected.model.displayName}`,
};
console.log("[Model Router] Selected:", result);
return result;
}
}
// 兜底:返回任意可用模型
const fallback =
allModels.find((m) => !m.model.isSubModel && m.model.isEnabled) ||
allModels[0];
console.log("[Model Router] Using fallback model:", fallback.model.displayName);
return {
id: fallback.model.id,
displayName: fallback.model.displayName,
providerType: fallback.provider.type,
reason: "fallback",
};
}
```
### 3.4 修改 `app/(chat)/api/chat/route.ts`
在现有的 Auto Mode 逻辑位置(约第 334-422 行),替换为以下代码:
```typescript
// ========== Smart Auto Mode Logic ==========
if (finalModelId === "auto") {
console.log("[Smart Auto Mode] Starting intelligent analysis...");
// 1. 提取用户消息内容
const lastUserMessage = message;
const textContent = lastUserMessage.parts
.filter((p) => p.type === "text")
.map((p) => (p as { type: "text"; text: string }).text)
.join(" ");
const hasImage = lastUserMessage.parts.some(
(p) => p.type === "file" || p.type === "image" || p.type === "image_url"
);
const imageUrls = lastUserMessage.parts
.filter((p): p is { type: "file"; url: string } => p.type === "file")
.map((p) => p.url);
// 2. 调用智能分析器
const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
const analysisResult = await analyzeIntent({
text: textContent,
hasImage,
imageUrls,
});
console.log("[Smart Auto Mode] Analysis result:", analysisResult);
// 3. 如果需要澄清,返回澄清问题(可选功能)
if (analysisResult.needsClarification && analysisResult.clarifyingQuestions) {
console.log("[Smart Auto Mode] Needs clarification, but proceeding with best guess...");
// 暂时不中断流程,继续使用最佳猜测
}
// 4. 如果是图片编辑类意图,优化提示词
if (analysisResult.intent === "image_edit" && analysisResult.subIntent) {
const { optimizePrompt } = await import("@/lib/ai/prompt-optimizer");
const optimizedResult = optimizePrompt({
originalPrompt: textContent,
intent: analysisResult.intent,
subIntent: analysisResult.subIntent,
});
console.log("[Smart Auto Mode] Prompt optimized");
// 替换消息中的文本为优化后的提示词
message.parts = message.parts.map((part) => {
if (part.type === "text") {
return {
...part,
text: optimizedResult.optimizedPrompt,
};
}
return part;
});
// 如果模型支持负面提示词,可以在 imageParams 中传递
// requestBody.imageParams = {
// ...requestBody.imageParams,
// negativePrompt: optimizedResult.negativePrompt,
// };
}
// 5. 路由到最佳模型
const { routeToModel } = await import("@/lib/ai/model-router");
const routeResult = await routeToModel({
intent: analysisResult.intent,
subIntent: analysisResult.subIntent,
hasImage,
});
finalModelId = routeResult.id;
console.log(`[Smart Auto Mode] ✅ Routed to: ${routeResult.displayName} (${routeResult.reason})`);
}
// ========== End Smart Auto Mode Logic ==========
```
---
## 四、测试场景
### 4.1 图片编辑场景测试
| 用户输入 | 预期意图 | 预期模型 |
|---------|---------|---------|
| [图片] + "帮我把背景换成白色" | replace_background | alibaba-image |
| [图片] + "抠图" | remove_background | alibaba-image |
| [图片] + "变清晰一点" | enhance | alibaba-image |
| [图片] + "把右边的人P掉" | inpaint | alibaba-image |
| [图片] + "转成卡通风格" | style_transfer | alibaba-image |
### 4.2 非编辑场景测试
| 用户输入 | 预期意图 | 预期模型 |
|---------|---------|---------|
| [图片] + "这是什么?" | vision | alibaba (Qwen3 VL) |
| "画一个可爱的猫" | image_gen | alibaba-image |
| "你好" | chat | alibaba (Qwen3 VL) |
---
## 五、开发步骤
### Phase 1: 基础实现 (1-2天)
1. 创建 `lib/ai/smart-analyzer.ts` - 使用关键词匹配作为主逻辑
2. 创建 `lib/ai/prompt-optimizer.ts` - 实现模板化提示词优化
3. 创建 `lib/ai/model-router.ts` - 实现基于意图的模型路由
4. 修改 `app/(chat)/api/chat/route.ts` - 集成新模块
### Phase 2: 智能升级 (2-3天)
1. 在 `smart-analyzer.ts` 中集成 Qwen3 VL 进行意图分析
2. 测试各种边界情况
3. 优化提示词模板
### Phase 3: 反馈优化 (可选)
1. 添加用户反馈机制
2. 记录用户偏好
3. 持续优化模型路由策略
---
## 六、注意事项
1. **保持向后兼容**:如果智能分析失败,自动回退到关键词匹配
2. **性能考虑**:Qwen3 分析会增加约 1-2 秒延迟,考虑是否需要
3. **错误处理**:所有新模块都需要完善的 try-catch
4. **日志记录**:添加详细日志便于调试
---
## 七、文件结构
```
lib/
└── ai/
├── smart-analyzer.ts # 智能意图分析器
├── prompt-optimizer.ts # 提示词优化器
├── model-router.ts # 智能模型路由器
├── dynamic-provider.ts # 现有模型提供器
└── providers/ # 现有模型提供商
├── alibaba-image.ts
├── gemini-image.ts
└── ...
app/
└── (chat)/
└── api/
└── chat/
└── route.ts # 修改 Auto Mode 逻辑
```

File diff suppressed because it is too large Load Diff

231
lib/ai/model-router.ts Normal file
View File

@ -0,0 +1,231 @@
/**
* 智能模型路由器
* 根据用户意图选择最佳AI模型
*
* 核心逻辑:图片编辑场景优先使用 alibaba-image (灵魂4.5)
*/
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";
// 路由结果类型
export interface RouteResult {
id: string;
displayName: string;
providerType: string;
modelId: string;
reason: string;
}
// 意图到模型的映射配置
// providerTypes 按优先级排序,第一个是首选
const INTENT_MODEL_MAP: Record<
string,
{
providerTypes: string[];
requireVision?: boolean;
requireImageGen?: boolean;
description: string;
}
> = {
// 图片编辑:优先 alibaba-image(灵魂4.5,支持提示词扩展)
image_edit: {
providerTypes: ["alibaba-image", "gemini"],
requireVision: true,
requireImageGen: true,
description: "图片编辑",
},
// 视觉理解:优先千问3 VL(成本低效果好)
vision: {
providerTypes: ["alibaba", "gemini"],
requireVision: true,
description: "图片理解",
},
// 图片生成:优先灵魂4.5
image_gen: {
providerTypes: ["alibaba-image", "gemini", "volcano-vision"],
requireImageGen: true,
description: "图片生成",
},
// 视频生成
video_gen: {
providerTypes: ["volcano-video", "qianwen-video"],
description: "视频生成",
},
// 普通对话:优先千问3
chat: {
providerTypes: ["alibaba", "openai", "local"],
description: "对话",
},
};
// 子意图的特殊路由配置(覆盖默认配置)
const SUB_INTENT_OVERRIDES: Record<
string,
{
providerTypes?: string[];
reason?: string;
}
> = {
// 抠图:alibaba-image 效果最好
remove_background: {
providerTypes: ["alibaba-image", "gemini"],
reason: "抠图首选灵魂4.5",
},
// 换背景:alibaba-image 支持场景生成
replace_background: {
providerTypes: ["alibaba-image", "gemini"],
reason: "换背景首选灵魂4.5",
},
// 图片增强
enhance: {
providerTypes: ["alibaba-image", "gemini", "volcano-vision"],
reason: "增强首选灵魂4.5",
},
// 风格迁移:gemini 可能更有创意
style_transfer: {
providerTypes: ["gemini", "alibaba-image"],
reason: "风格迁移优选Gemini",
},
};
/**
* 路由到最佳模型
*/
export async function routeToModel(params: {
intent: string;
subIntent?: string;
hasImage: boolean;
}): Promise<RouteResult> {
const { intent, subIntent, hasImage } = params;
console.log("[Model Router] Routing:", { intent, subIntent, hasImage });
// 获取所有可用模型
const allModels = await getEnabledAiModelsWithProvider();
console.log("[Model Router] Available models:", allModels.length);
// 获取意图对应的配置
let config = INTENT_MODEL_MAP[intent] || INTENT_MODEL_MAP["chat"];
// 检查是否有子意图的特殊配置
if (subIntent && SUB_INTENT_OVERRIDES[subIntent]) {
const override = SUB_INTENT_OVERRIDES[subIntent];
if (override.providerTypes) {
config = { ...config, providerTypes: override.providerTypes };
}
}
// 按优先级查找匹配的模型
for (const providerType of config.providerTypes) {
const candidates = allModels.filter((m) => {
// 匹配 provider 类型
if (m.provider.type !== providerType) return false;
// 检查能力要求
if (config.requireVision && !m.model.supportsVision) return false;
if (config.requireImageGen && !m.model.supportsImageGen) return false;
// 排除子模型(只选主模型)
if (m.model.isSubModel) return false;
// 必须启用
if (!m.model.isEnabled) return false;
return true;
});
if (candidates.length > 0) {
// 优先选择默认模型
const defaultModel = candidates.find((c) => c.model.isDefault);
const selected = defaultModel || candidates[0];
const result: RouteResult = {
id: selected.model.id,
displayName: selected.model.displayName,
providerType: selected.provider.type,
modelId: selected.model.modelId,
reason: subIntent
? `${config.description}/${subIntent} → ${selected.model.displayName}`
: `${config.description} → ${selected.model.displayName}`,
};
console.log("[Model Router] ✅ Selected:", result);
return result;
}
}
// 兜底逻辑:返回任意可用的图片编辑模型
const fallbackCandidates = allModels.filter(
(m) =>
!m.model.isSubModel &&
m.model.isEnabled &&
(m.model.supportsImageGen || m.model.supportsVision)
);
if (fallbackCandidates.length > 0) {
const fallback = fallbackCandidates[0];
console.log("[Model Router] Using fallback (with image capability):", fallback.model.displayName);
return {
id: fallback.model.id,
displayName: fallback.model.displayName,
providerType: fallback.provider.type,
modelId: fallback.model.modelId,
reason: `fallback (${config.description})`,
};
}
// 最终兜底:返回任意可用模型
const anyModel = allModels.find((m) => !m.model.isSubModel && m.model.isEnabled);
if (anyModel) {
console.log("[Model Router] Using any available model:", anyModel.model.displayName);
return {
id: anyModel.model.id,
displayName: anyModel.model.displayName,
providerType: anyModel.provider.type,
modelId: anyModel.model.modelId,
reason: "fallback (any)",
};
}
// 如果没有任何模型,抛出错误
throw new Error("No available models for routing");
}
/**
* 获取意图的推荐模型列表(用于 UI 展示)
*/
export function getRecommendedModelsForIntent(intent: string): string[] {
const config = INTENT_MODEL_MAP[intent];
return config ? config.providerTypes : INTENT_MODEL_MAP["chat"].providerTypes;
}
/**
* 检查模型是否适合指定意图
*/
export function isModelSuitableForIntent(
providerType: string,
intent: string,
supportsVision: boolean,
supportsImageGen: boolean
): boolean {
const config = INTENT_MODEL_MAP[intent];
if (!config) return true; // 未知意图,允许任何模型
// 检查 provider 类型是否匹配
if (!config.providerTypes.includes(providerType)) {
return false;
}
// 检查能力要求
if (config.requireVision && !supportsVision) return false;
if (config.requireImageGen && !supportsImageGen) return false;
return true;
}

231
lib/ai/prompt-optimizer.ts Normal file
View File

@ -0,0 +1,231 @@
/**
* 提示词优化器
* 将用户简单输入转换为专业的图片编辑提示词
*
* 主要应用场景:图片编辑(抠图、换背景、增强等)
*/
// 优化结果类型
export interface OptimizeResult {
originalPrompt: string;
optimizedPrompt: string;
negativePrompt: string;
}
// 图片编辑子意图的提示词模板
const EDIT_TEMPLATES: Record<
string,
{
template: string;
negative: string;
extractors: Record<string, RegExp>;
defaults: Record<string, string>;
}
> = {
remove_background: {
template:
"精准抠图:去除图片背景,保留主体完整清晰,输出透明背景PNG格式。边缘处理要求:平滑自然无锯齿,保留精细细节(如发丝、毛发、边缘纹理)。主体保持原有清晰度和色彩。",
negative: "残留背景色块,边缘毛糙,锯齿明显,主体不完整,边缘模糊,细节丢失,颜色溢出",
extractors: {},
defaults: {},
},
replace_background: {
template:
"背景替换:将图片背景替换为{background}。要求:保持主体完整清晰不变形,边缘过渡自然平滑,光影效果与新背景协调一致。{extra}",
negative: "残留原背景,边缘不自然,透视错误,主体变形,光影不协调,明显P图痕迹,边缘光晕",
extractors: {
background: /(?:换成|改成|替换为|变成|换为|改为)(.+?)(?:背景|底|$)/,
},
defaults: {
background: "纯白色(#FFFFFF)",
extra: "保留主体自然阴影效果",
},
},
enhance: {
template:
"图片增强:提升图片整体清晰度和画质。要求:保持自然色彩不失真,智能去除噪点,增强细节层次,适度锐化边缘。{extra}",
negative: "过度锐化,色彩失真,噪点增加,伪影,画质下降,不自然的对比度,颜色过饱和",
extractors: {},
defaults: {
extra: "整体效果自然真实",
},
},
extend: {
template:
"图像拓展(Outpainting):向{direction}方向扩展图片约{amount}。要求:扩展区域的内容、风格、色调与原图保持高度一致,光影过渡自然流畅,无明显接缝痕迹,透视关系正确。",
negative: "风格不一致,明显接缝,透视错误,内容突变,色调不匹配,光影断裂",
extractors: {
direction: /向?(上|下|左|右|四周|周围)/,
amount: /(\d+%?|一倍|两倍|50%|100%)/,
},
defaults: {
direction: "四周",
amount: "50%",
},
},
inpaint: {
template:
"局部修改(Inpainting):{action}图片中的{target}。要求:使用周围环境自然填充修改区域,保持整体风格、色调、光影一致,无任何修复痕迹,过渡自然。",
negative: "明显修复痕迹,风格不一致,内容错误,边缘不自然,色差明显,纹理断裂",
extractors: {
target: /(?:去除|消除|擦掉|删除|移除|P掉|p掉)(.+?)(?:,|。|$| )/,
action: /(去除|消除|擦掉|删除|移除|修改)/,
},
defaults: {
target: "指定区域内的元素",
action: "去除",
},
},
style_transfer: {
template:
"风格迁移:将图片转换为{style}风格。要求:保持主体可识别性和基本特征,色彩风格协调统一,整体效果自然美观。",
negative: "主体变形严重,特征丢失,风格不统一,色彩异常,人物不可识别",
extractors: {
style: /(?:转换为|变成|改成|转成)(.+?)(?:风格|$)/,
},
defaults: {
style: "卡通动漫",
},
},
resize: {
template:
"尺寸调整:将图片{action}至{size}。要求:保持画质清晰,比例协调,细节不丢失。",
negative: "画质损失严重,比例失调,模糊,变形",
extractors: {
size: /(\d+[x×]\d+|\d+%)/,
action: /(放大|缩小|调整|裁剪)/,
},
defaults: {
size: "目标尺寸",
action: "调整",
},
},
color_adjust: {
template:
"颜色调整:对图片进行{adjustment}处理。要求:保持自然效果,色彩协调,不过度调整。",
negative: "色彩失真,过度调整,不自然,偏色严重",
extractors: {
adjustment: /(?:调整|增加|减少|提高|降低)(.+?)(?:,|。|$| )/,
},
defaults: {
adjustment: "色彩优化",
},
},
};
/**
* 优化提示词
*/
export function optimizePrompt(params: {
originalPrompt: string;
intent: string;
subIntent?: string;
}): OptimizeResult {
const { originalPrompt, intent, subIntent } = params;
console.log("[Prompt Optimizer] Input:", { originalPrompt, intent, subIntent });
// 只对图片编辑类意图进行优化
if (intent !== "image_edit") {
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印,失真",
};
}
// 如果没有子意图,返回通用优化
if (!subIntent) {
return {
originalPrompt,
optimizedPrompt: `图片编辑:${originalPrompt}。要求:效果自然,画质清晰,细节完整。`,
negativePrompt: "模糊,低质量,变形,水印,失真,不自然",
};
}
const template = EDIT_TEMPLATES[subIntent];
if (!template) {
console.log("[Prompt Optimizer] No template for subIntent:", subIntent);
return {
originalPrompt,
optimizedPrompt: originalPrompt,
negativePrompt: "模糊,低质量,变形,水印,失真",
};
}
// 使用模板生成优化后的提示词
let optimizedPrompt = template.template;
// 从用户输入中提取参数并填充模板
for (const [key, regex] of Object.entries(template.extractors)) {
const match = originalPrompt.match(regex);
let value = match ? match[1].trim() : template.defaults[key] || "";
// 清理提取的值
value = value.replace(/[,。!?,.!?]/g, "").trim();
if (!value) {
value = template.defaults[key] || "";
}
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, value);
}
// 填充剩余的默认值
for (const [key, defaultValue] of Object.entries(template.defaults)) {
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, defaultValue);
}
// 附加用户原始意图(如果优化后的提示词没有完全覆盖用户需求)
if (originalPrompt.length > 10 && !optimizedPrompt.includes(originalPrompt)) {
optimizedPrompt = `${optimizedPrompt}\n\n用户补充要求:${originalPrompt}`;
}
const result: OptimizeResult = {
originalPrompt,
optimizedPrompt,
negativePrompt: template.negative,
};
console.log("[Prompt Optimizer] Output:", result);
return result;
}
/**
* 提取背景描述(辅助函数)
*/
export function extractBackgroundDescription(text: string): string {
// 尝试提取用户描述的背景
const patterns = [
/(?:换成|改成|替换为|变成|换为|改为)(.+?)(?:背景|底)/,
/(.+?)(?:背景|底)$/,
/背景(?:换成|改成|替换为|变成)(.+)/,
];
for (const pattern of patterns) {
const match = text.match(pattern);
if (match && match[1]) {
return match[1].trim();
}
}
return "纯白色";
}
/**
* 检测是否需要保留阴影
*/
export function shouldPreserveShadow(text: string): boolean {
// 产品图、商品图通常需要保留阴影
if (/产品|商品|电商|白底|纯白/.test(text)) {
return true;
}
return false;
}

347
lib/ai/smart-analyzer.ts Normal file
View File

@ -0,0 +1,347 @@
/**
* 智能意图分析器
* 分析用户输入,识别图片编辑意图
*
* 主要应用场景:图片编辑(抠图、换背景、增强等)
*/
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[];
}
// 系统提示词 - 针对图片编辑场景优化
const ANALYZER_SYSTEM_PROMPT = `你是一个专业的图片编辑意图分析专家。请分析用户的请求,判断其意图类型。
## 意图分类(按优先级)
### 1. image_edit - 图片编辑(最高优先级,需要用户上传了图片)
子意图:
- remove_background: 抠图、去背景、透明背景、去除背景、扣图
- replace_background: 换背景、改背景、白底、场景替换、背景换成、纯色背景
- enhance: 变清晰、高清、锐化、降噪、提升质量、修复、清晰化
- extend: 扩展、拓展、延伸、outpainting、扩图、拓图
- inpaint: 去除XX、消除、擦掉、修改XX部分、局部修改、P掉、删除某物
- style_transfer: 风格化、卡通化、动漫风、油画风、改风格、转风格
- resize: 缩放、放大、缩小、调整尺寸、裁剪
- color_adjust: 调色、调整颜色、亮度、对比度、饱和度、色调
### 2. vision - 图片理解(需要用户上传了图片)
触发词:看、识别、分析、描述、这是什么、有什么、tell me、what is
### 3. image_gen - 图片生成(不需要上传图片)
触发词:画、绘制、生成图片、创建、设计、画一个、生成一张
### 4. video_gen - 视频生成
触发词:视频、动画、动起来、让它动
### 5. chat - 普通对话(默认)
## 输出格式(严格JSON,不要有其他内容)
{
"intent": "image_edit",
"subIntent": "replace_background",
"confidence": 0.95,
"needsClarification": false,
"clarifyingQuestions": []
}
## 特殊规则
1. 如果用户上传了图片且有编辑类关键词 → image_edit
2. 如果用户上传了图片但意图不明确 → needsClarification: true,并提供澄清问题
3. 如果用户要求编辑但没上传图片 → needsClarification: true,提示"请上传图片"
4. 只输出JSON,不要有任何解释文字`;
/**
* 分析用户意图
*/
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;
}
/**
* 快速关键词匹配(高置信度场景)
*/
function quickKeywordMatch(text: string, hasImage: boolean): AnalysisResult {
const lowerText = text.toLowerCase();
if (hasImage) {
// 抠图/去背景 - 高频场景
if (/抠图|去背景|透明背景|去背|扣图|移除背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "remove_background",
confidence: 0.95,
};
}
// 换背景 - 高频场景
if (/换背景|白底|改背景|背景换成|纯色背景|白色背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "replace_background",
confidence: 0.95,
};
}
// 图片增强 - 高频场景
if (/变清晰|高清|锐化|降噪|清晰一点|更清晰|提升质量/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "enhance",
confidence: 0.95,
};
}
// P图/去除某物
if (/P掉|p掉|去除|消除|擦掉|删除.*(?:人|物|水印|logo)/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "inpaint",
confidence: 0.95,
};
}
}
// 视频生成
if (/生成视频|做视频|视频生成|动起来|让.{0,3}动/.test(lowerText)) {
return {
intent: "video_gen",
confidence: 0.95,
};
}
// 返回低置信度结果,触发LLM分析
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;
}
/**
* 回退方案:完整关键词匹配
*/
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,
};
}
// 换背景
if (/换背景|白底|改背景|背景换成|纯色背景|换成.*背景|替换.*背景/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "replace_background",
confidence: 0.9,
};
}
// 图片增强
if (/变清晰|高清|锐化|降噪|提升质量|修复|清晰化|变清楚|画质/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "enhance",
confidence: 0.9,
};
}
// 图像拓展
if (/扩展|拓展|延伸|扩图|outpainting|拓宽|扩大/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "extend",
confidence: 0.9,
};
}
// 局部修改/去除
if (/去除|消除|擦掉|P掉|p掉|删除|修改.*部分|移除.*(?:人|物|水印|logo|文字)/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "inpaint",
confidence: 0.9,
};
}
// 风格迁移
if (/风格|卡通化|动漫风|油画风|转.*风格|变.*风格|改.*风格/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "style_transfer",
confidence: 0.9,
};
}
// 调色
if (/调色|调整颜色|亮度|对比度|饱和度|色调|曝光|滤镜/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "color_adjust",
confidence: 0.9,
};
}
// 尺寸调整
if (/缩放|放大|缩小|调整尺寸|裁剪|resize|crop/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: "resize",
confidence: 0.9,
};
}
// 通用编辑关键词
if (/修图|P图|改图|调图|处理.*图|编辑.*图|优化.*图/.test(lowerText)) {
return {
intent: "image_edit",
confidence: 0.8,
needsClarification: true,
clarifyingQuestions: [
"您想对这张图片做什么处理?(抠图/换背景/变清晰/其他)",
],
};
}
// 视觉理解
if (/看|识别|分析|描述|这是什么|有什么|tell me|what is|看看|帮我看/.test(lowerText)) {
return { intent: "vision", confidence: 0.85 };
}
// 有图但意图不明确
return {
intent: "image_edit",
confidence: 0.5,
needsClarification: true,
clarifyingQuestions: [
"您想对这张图片做什么处理?(抠图/换背景/变清晰/局部修改/其他)",
],
};
}
// === 无图片场景 ===
// 图片生成
if (/画|绘制|生成图|创建.*图|设计.*图|画一个|生成一张|做一张/.test(lowerText)) {
return { intent: "image_gen", confidence: 0.85 };
}
// 视频生成
if (/视频|动画|动起来|生成视频|做视频|视频生成/.test(lowerText)) {
return { intent: "video_gen", confidence: 0.85 };
}
// 需要图片但没有上传
if (/抠图|去背景|换背景|修图|P图|编辑图/.test(lowerText)) {
return {
intent: "image_edit",
confidence: 0.7,
needsClarification: true,
clarifyingQuestions: ["请先上传您要编辑的图片"],
};
}
// 默认对话
return { intent: "chat", confidence: 0.7 };
}