perf: 视觉拦截器仅处理最后一条 user 消息的图片

历史消息中的图片已在前几轮被转换为文本描述,无需重复送入
OCR/Vision API 处理。此优化避免多轮对话中重复消耗 API 配额
并减少每次请求的延迟。
This commit is contained in:
chinadoiphin
2026-03-18 21:17:50 +08:00
parent c2dae870ca
commit 23c9f16dff

View File

@@ -7,47 +7,55 @@ export async function applyVisionInterceptor(messages: AnthropicMessage[]): Prom
const config = getConfig();
if (!config.vision?.enabled) return;
for (const msg of messages) {
if (msg.role !== 'user') continue;
if (!Array.isArray(msg.content)) continue;
let hasImages = false;
const newContent: AnthropicContentBlock[] = [];
const imagesToAnalyze: AnthropicContentBlock[] = [];
for (const block of msg.content) {
if (block.type === 'image') {
hasImages = true;
imagesToAnalyze.push(block);
} else {
newContent.push(block);
}
// ★ 仅处理最后一条 user 消息中的图片
// 历史消息的图片已在前几轮被转换为文本描述,无需重复处理
// 这避免了多轮对话中重复消耗 Vision API 配额和增加延迟
let lastUserMsg: AnthropicMessage | null = null;
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].role === 'user') {
lastUserMsg = messages[i];
break;
}
}
if (hasImages && imagesToAnalyze.length > 0) {
try {
let descriptions = '';
if (config.vision.mode === 'ocr') {
descriptions = await processWithLocalOCR(imagesToAnalyze);
} else {
descriptions = await callVisionAPI(imagesToAnalyze);
}
if (!lastUserMsg || !Array.isArray(lastUserMsg.content)) return;
// Add descriptions as a simulated system text block
newContent.push({
type: 'text',
text: `\n\n[System: The user attached ${imagesToAnalyze.length} image(s). Visual analysis/OCR extracted the following context:\n${descriptions}]\n\n`
});
let hasImages = false;
const newContent: AnthropicContentBlock[] = [];
const imagesToAnalyze: AnthropicContentBlock[] = [];
msg.content = newContent;
} catch (e) {
console.error("[Vision API Error]", e);
newContent.push({
type: 'text',
text: `\n\n[System: The user attached image(s), but the Vision interceptor failed to process them. Error: ${(e as Error).message}]\n\n`
});
msg.content = newContent;
for (const block of lastUserMsg.content) {
if (block.type === 'image') {
hasImages = true;
imagesToAnalyze.push(block);
} else {
newContent.push(block);
}
}
if (hasImages && imagesToAnalyze.length > 0) {
try {
let descriptions = '';
if (config.vision.mode === 'ocr') {
descriptions = await processWithLocalOCR(imagesToAnalyze);
} else {
descriptions = await callVisionAPI(imagesToAnalyze);
}
// Add descriptions as a simulated system text block
newContent.push({
type: 'text',
text: `\n\n[System: The user attached ${imagesToAnalyze.length} image(s). Visual analysis/OCR extracted the following context:\n${descriptions}]\n\n`
});
lastUserMsg.content = newContent;
} catch (e) {
console.error("[Vision API Error]", e);
newContent.push({
type: 'text',
text: `\n\n[System: The user attached image(s), but the Vision interceptor failed to process them. Error: ${(e as Error).message}]\n\n`
});
lastUserMsg.content = newContent;
}
}
}