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:
parent
8d580ad3ab
commit
8763e8d53f
@ -331,96 +331,113 @@ export async function POST(request: Request) {
|
||||
|
||||
let finalModelId = selectedChatModel;
|
||||
|
||||
// ========== Auto Mode Logic ==========
|
||||
// ========== Smart Auto Mode Logic ==========
|
||||
if (finalModelId === "auto") {
|
||||
console.log("[Auto Mode] Detecting intent...");
|
||||
const lastUserMessage = message;
|
||||
const textContent = lastUserMessage.parts
|
||||
.filter((p) => p.type === 'text')
|
||||
.map((p) => p.text)
|
||||
.join(' ');
|
||||
// @ts-ignore
|
||||
const hasImage = lastUserMessage.parts.some((p) => p.type === 'file' || p.type === 'image' || p.type === 'image_url');
|
||||
console.log("[Smart Auto Mode] 🚀 Starting intelligent analysis...");
|
||||
|
||||
try {
|
||||
// 1. 提取用户消息内容
|
||||
const lastUserMessage = message;
|
||||
const textContent = lastUserMessage.parts
|
||||
.filter((p): p is { type: "text"; text: string } => p.type === "text")
|
||||
.map((p) => p.text)
|
||||
.join(" ");
|
||||
|
||||
// 获取所有可用模型
|
||||
const allModels = await getEnabledAiModelsWithProvider();
|
||||
console.log("[Auto Mode] Available models:", allModels.map(m => `${m.model.displayName} (视频:${m.model.displayName.includes('视频')}, 图片:${m.model.supportsImageGen}, 视觉:${m.model.supportsVision})`));
|
||||
|
||||
let bestModel = null;
|
||||
// @ts-ignore - 检查各种可能的图片类型
|
||||
const hasImage = lastUserMessage.parts.some(
|
||||
(p: any) => p.type === "file" || p.type === "image" || p.type === "image_url"
|
||||
);
|
||||
|
||||
// 智能意图识别 - 基于关键词匹配
|
||||
// 定义各类意图的关键词库
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (videoKeywords.test(textContent)) {
|
||||
console.log("[Auto Mode] Intent: VIDEO - 视频生成");
|
||||
bestModel = allModels.find(m => m.model.displayName.includes("视频"));
|
||||
}
|
||||
// 2. 图片编辑:用户上传了图片并要求编辑
|
||||
else if (hasImage && imageEditKeywords.test(textContent)) {
|
||||
console.log("[Auto Mode] Intent: IMAGE_EDIT - 图片编辑");
|
||||
bestModel = allModels.find(m => m.model.displayName.includes("图片编辑") || m.model.displayName.includes("编辑"));
|
||||
if (!bestModel) {
|
||||
bestModel = allModels.find(m => m.model.supportsVision && !m.model.displayName.includes("视频"));
|
||||
// @ts-ignore - 提取图片URL
|
||||
const 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 });
|
||||
|
||||
// 2. 调用智能分析器
|
||||
const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
|
||||
const analysisResult = await analyzeIntent({
|
||||
text: textContent,
|
||||
hasImage,
|
||||
imageUrls,
|
||||
});
|
||||
|
||||
console.log("[Smart Auto Mode] Analysis result:", {
|
||||
intent: analysisResult.intent,
|
||||
subIntent: analysisResult.subIntent,
|
||||
confidence: analysisResult.confidence,
|
||||
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. 图片生成:用户要求画图/生成图片(不需要上传图片)
|
||||
else if (imageGenKeywords.test(textContent)) {
|
||||
console.log("[Auto Mode] Intent: IMAGE_GEN - 图片生成");
|
||||
bestModel = allModels.find(m => m.model.displayName.includes("图片编辑") || m.model.supportsImageGen);
|
||||
// 排除视频模型
|
||||
if (bestModel && bestModel.model.displayName.includes("视频")) {
|
||||
bestModel = allModels.find(m => (m.model.displayName.includes("图片编辑") || m.model.supportsImageGen) && !m.model.displayName.includes("视频"));
|
||||
|
||||
// 4. 路由到最佳模型
|
||||
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})`);
|
||||
|
||||
} 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) {
|
||||
bestModel = allModels.find(m => m.model.supportsVision && !m.model.displayName.includes("视频"));
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
bestModel = allModels.find(m => m.model.isDefault && !m.model.isSubModel);
|
||||
}
|
||||
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();
|
||||
|
||||
|
||||
755
docs/smart-auto-implementation-guide.md
Normal file
755
docs/smart-auto-implementation-guide.md
Normal 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 逻辑
|
||||
```
|
||||
1960
docs/smart-auto-model-upgrade.md
Normal file
1960
docs/smart-auto-model-upgrade.md
Normal file
File diff suppressed because it is too large
Load Diff
231
lib/ai/model-router.ts
Normal file
231
lib/ai/model-router.ts
Normal 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
231
lib/ai/prompt-optimizer.ts
Normal 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
347
lib/ai/smart-analyzer.ts
Normal 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 };
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user