fix: display top10 images

This commit is contained in:
Sha Zhou 2025-06-19 12:55:46 +08:00
parent d835ccfd7c
commit 401eb9a23f
3 changed files with 34 additions and 8 deletions

View File

@ -48,7 +48,7 @@ import { logInfo, logError, logDebug, logWarning } from './logging';
import { researchPlan } from './tools/research-planner'; import { researchPlan } from './tools/research-planner';
import { reduceAnswers } from './tools/reducer'; import { reduceAnswers } from './tools/reducer';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { dedupImagesWithEmbeddings } from './utils/image-tools'; import { dedupImagesWithEmbeddings, filterImages } from './utils/image-tools';
import { serpCluster } from './tools/serp-cluster'; import { serpCluster } from './tools/serp-cluster';
async function wait(seconds: number) { async function wait(seconds: number) {
@ -845,7 +845,7 @@ But then you realized you have asked them before. You decided to to think out of
answer: subproblemResponses.map(r => (r.result as AnswerAction).answer).join('\n\n'), answer: subproblemResponses.map(r => (r.result as AnswerAction).answer).join('\n\n'),
mdAnswer: subproblemResponses.map(r => (r.result as AnswerAction).mdAnswer).join('\n\n'), mdAnswer: subproblemResponses.map(r => (r.result as AnswerAction).mdAnswer).join('\n\n'),
references: subproblemResponses.map(r => (r.result as AnswerAction).references).flat(), references: subproblemResponses.map(r => (r.result as AnswerAction).references).flat(),
imageReferences: subproblemResponses.map(r => (r.result as AnswerAction).imageReferences).flat(), imageReferences: subproblemResponses.map(r => (r.result as AnswerAction).imageReferences).filter(Boolean).flat(),
isFinal: true, isFinal: true,
isAggregated: true isAggregated: true
} as AnswerAction; } as AnswerAction;
@ -1124,10 +1124,12 @@ But unfortunately, you failed to solve the issue. You need to think out of the b
answerStep.answer = candidateAnswers.join('\n\n'); // await reduceAnswers(candidateAnswers, context, SchemaGen); answerStep.answer = candidateAnswers.join('\n\n'); // await reduceAnswers(candidateAnswers, context, SchemaGen);
answerStep.mdAnswer = repairMarkdownFootnotesOuter(buildMdFromAnswer(answerStep)); answerStep.mdAnswer = repairMarkdownFootnotesOuter(buildMdFromAnswer(answerStep));
if (withImages && answerStep.imageReferences?.length) { if (withImages && answerStep.imageReferences?.length) {
logDebug('[agent] all image references:', { count: answerStep.imageReferences?.length }); const sortedImages = answerStep.imageReferences.sort((a, b) => (b.relevanceScore ?? 0) - (a.relevanceScore ?? 0));
const dedupImages = dedupImagesWithEmbeddings(answerStep.imageReferences as ImageObject[], []); logDebug('[agent] all sorted image references:', { count: sortedImages?.length });
logDebug('[agent] deduped images:', { count: dedupImages.length }); const dedupImages = dedupImagesWithEmbeddings(sortedImages as ImageObject[], []);
answerStep.imageReferences = answerStep.imageReferences?.filter(i => i?.url && dedupImages.some(d => d?.url === i.url)) || []; const filteredImages = filterImages(sortedImages, dedupImages);
logDebug('[agent] filtered images:', { count: filteredImages.length });
answerStep.imageReferences = filteredImages.slice(0, 10); // limit to 10 images
} }
} }

View File

@ -522,7 +522,7 @@ export async function buildImageReferences(
const filteredMatches = []; const filteredMatches = [];
for (const match of allMatches) { for (const match of allMatches) {
if (match.relevanceScore < minRelScore) continue; // if (match.relevanceScore < minRelScore) continue;
if (!usedImages.has(match.imageIndex) && !usedAnswerChunks.has(match.answerChunkIndex)) { if (!usedImages.has(match.imageIndex) && !usedAnswerChunks.has(match.answerChunkIndex)) {
filteredMatches.push(match); filteredMatches.push(match);

View File

@ -1,6 +1,6 @@
import { getEmbeddings } from '../tools/embeddings'; import { getEmbeddings } from '../tools/embeddings';
import { TokenTracker } from './token-tracker'; import { TokenTracker } from './token-tracker';
import { ImageObject } from '../types'; import { ImageObject, ImageReference } from '../types';
import { cosineSimilarity } from '../tools/cosine'; import { cosineSimilarity } from '../tools/cosine';
import { logInfo, logError, logDebug, logWarning } from '../logging'; import { logInfo, logError, logDebug, logWarning } from '../logging';
import sharp from 'sharp'; import sharp from 'sharp';
@ -190,4 +190,28 @@ export const dedupImagesWithEmbeddings = (
// Return all new images if there is an error // Return all new images if there is an error
return newImages; return newImages;
} }
}
export const filterImages = (imageReferences: ImageReference[], dedupedImages: ImageObject[]): ImageReference[] => {
if (!imageReferences || imageReferences.length === 0) {
logInfo('No image references provided for filtering');
return [];
}
if (!dedupedImages || dedupedImages.length === 0) {
logInfo('No deduplicated images provided for filtering');
return imageReferences;
}
const urlMap = new Map();
for (const img of imageReferences) {
if (img?.url && !urlMap.has(img.url)) {
urlMap.set(img.url, img);
}
}
const filteredReferences = dedupedImages.map(img => urlMap.get(img.url))
.filter(Boolean);
return filteredReferences;
} }