fix(agent): enrich generic image-analysis text with visual summary
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-19 03:17:34 +08:00
parent c8f3a04f03
commit 55b2c836b4
2 changed files with 118 additions and 0 deletions

View File

@ -798,6 +798,45 @@ function buildAutoModeFallbackMessage(params: {
].join("\n");
}
function extractMessageImageUrls(parts: any[]): string[] {
return (parts || [])
.map((part: any) => {
if (!part) return null;
if (part.type === "file") return part.url || part.data || null;
if (part.type === "image") return part.url || part.image || null;
if (part.type === "image_url") return part.image_url?.url || null;
return null;
})
.filter((url: any): url is string => typeof url === "string" && /^https?:\/\//i.test(url));
}
function shouldEnrichImageAnalysisText(message?: string): boolean {
if (!message) return false;
if (!/###\s*图片分析/.test(message)) return false;
return /(基于当前上传图片处理|基于你选中的原图处理|基于上一轮图片继续处理)/.test(message);
}
function injectImageAnalysisSummary(message: string, summary: string): string {
const normalizedSummary = summary.replace(/\s+/g, " ").trim();
if (!normalizedSummary) return message;
const lines = message.split("\n");
const analysisHeaderIndex = lines.findIndex((line) => /^###\s*图片分析/.test(line.trim()));
if (analysisHeaderIndex < 0) return message;
for (let i = analysisHeaderIndex + 1; i < lines.length; i += 1) {
const current = lines[i]?.trim() || "";
if (/^###\s*/.test(current)) break;
if (/^- /.test(current)) {
lines[i] = `- ${normalizedSummary}`;
return lines.join("\n");
}
}
const insertIndex = analysisHeaderIndex + 1;
lines.splice(insertIndex, 0, `- ${normalizedSummary}`);
return lines.join("\n");
}
/**
* 自定义消息转换函数
* 注意:gemini-image 和 huanke-gemini 都需要 URL 格式(不是 Base64)
@ -2099,6 +2138,44 @@ export async function POST(request: Request) {
});
}
if (
shouldRunAgentConversation &&
!smartAutoNeedsClarification &&
smartAutoFriendlyMessage &&
shouldEnrichImageAnalysisText(smartAutoFriendlyMessage)
) {
try {
const currentImageUrls = extractMessageImageUrls(message.parts as any[]);
const summaryImageUrls =
currentImageUrls.length > 0 ? currentImageUrls : smartAutoHistoryImages;
if (summaryImageUrls.length > 0) {
const { summarizeImageForExecutionReport } = await import("@/lib/ai/smart-analyzer");
const summary = await withOperationTimeout(
summarizeImageForExecutionReport({
text: message.parts
.filter((part): part is { type: "text"; text: string } => part.type === "text")
.map((part) => part.text)
.join(" "),
imageUrls: summaryImageUrls,
context: typeof autoContext === "string" ? autoContext : undefined,
}),
"enrichImageAnalysisSummary",
8000,
);
if (summary?.trim()) {
smartAutoFriendlyMessage = injectImageAnalysisSummary(
smartAutoFriendlyMessage,
summary.trim(),
);
console.log("[Smart Auto Mode] ✅ Enriched image analysis summary");
}
}
} catch (enrichError) {
console.warn("[Smart Auto Mode] Skip image analysis enrichment:", enrichError);
}
}
const session = await auth();
if (!session?.user) {

View File

@ -636,6 +636,47 @@ export async function summarizeImageForExecutionReport(params: {
if (summary) return summary;
}
try {
const selectedVisionModel =
(agentModel && isLikelyVisionCapableModel(agentModel) ? agentModel : undefined) ||
allModels.find((m) => isLikelyVisionCapableModel(m));
if (!selectedVisionModel) return null;
const { getLanguageModelById } = await import("./dynamic-provider");
const model = await getLanguageModelById(selectedVisionModel.model.id);
if (!model) return null;
const fallbackVisionImages = await buildAnalyzerVisionImagesByMode({
imageUrls,
preferRemoteUrls: shouldPreferRemoteVisionUrls(selectedVisionModel),
});
if (fallbackVisionImages.length === 0) return null;
const { text: summaryText } = await generateText({
model,
messages: [
{
role: "user",
content: [
{
type: "text",
text: `${promptText}\n只输出一行,格式:画面要点:主体+场景+风格+光线(不超过45字)。`,
},
...fallbackVisionImages,
],
},
],
temperature: 0.1,
maxTokens: 120,
abortSignal: AbortSignal.timeout(8000),
} as any);
const normalized = summaryText?.replace(/\s+/g, " ").trim();
return normalized || null;
} catch (error) {
console.warn("[Smart Analyzer] summarizeImageForExecutionReport fallback failed:", error);
}
return null;
}