The staging area is empty — there are no staged changes to summarize. Stage some files first with git add and I can help craft the message.
This commit is contained in:
@@ -1094,7 +1094,14 @@ async function _runSingleMediaAnalysis(
|
||||
|
||||
const maxDimension = config.AI_LLM_IMAGE_MAX_DIMENSION ?? 1024;
|
||||
|
||||
// ── 1. Download attachments for this message (with resize — R5) ──
|
||||
// ── 1-3. Parallel download of ALL media sources ──
|
||||
// Build all download promises upfront and execute them in one Promise.all.
|
||||
// Attachment, URL, sticker/emoji downloads are fully independent of each other.
|
||||
// An 8-image cap is enforced across all sources combined.
|
||||
|
||||
const downloadPromises: Array<Promise<void>> = [];
|
||||
|
||||
// ── Attachment downloads ──
|
||||
const msgAttachments = (allAttachments ?? [])
|
||||
.filter(
|
||||
(att) =>
|
||||
@@ -1104,8 +1111,9 @@ async function _runSingleMediaAnalysis(
|
||||
)
|
||||
.slice(0, 8);
|
||||
|
||||
await Promise.all(
|
||||
msgAttachments.map(async (att) => {
|
||||
for (const att of msgAttachments) {
|
||||
downloadPromises.push(
|
||||
(async () => {
|
||||
const urlToUse = getAttachmentImageUrl(att);
|
||||
if (!urlToUse) return;
|
||||
|
||||
@@ -1159,7 +1167,6 @@ async function _runSingleMediaAnalysis(
|
||||
return;
|
||||
}
|
||||
|
||||
// Resize before base64 encoding (R5)
|
||||
const { data: resizedBuffer, mimeType: resizedMime } =
|
||||
await resizeImageForVision(imageBytes, maxDimension);
|
||||
|
||||
@@ -1170,8 +1177,10 @@ async function _runSingleMediaAnalysis(
|
||||
sourceLabel: `[gambar di atas adalah attachment ${att.filename} dari pesan id=${att.message_id}]`,
|
||||
};
|
||||
const existing = imageMap.get(targetId) ?? [];
|
||||
if (existing.length < 8) {
|
||||
existing.push(part);
|
||||
imageMap.set(targetId, existing);
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn(
|
||||
{
|
||||
@@ -1183,20 +1192,19 @@ async function _runSingleMediaAnalysis(
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}),
|
||||
})(),
|
||||
);
|
||||
}
|
||||
|
||||
// ── 2. Fetch URLs found in message text ──
|
||||
const content = target.edited_content ?? target.content;
|
||||
// ── URL fetch promises ──
|
||||
const urls = extractUrlsFromText(content).slice(0, 3);
|
||||
const urlWebTexts: string[] = [];
|
||||
|
||||
if (urls.length > 0) {
|
||||
const webTexts: string[] = [];
|
||||
await Promise.all(
|
||||
urls.map(async (url) => {
|
||||
for (const url of urls) {
|
||||
downloadPromises.push(
|
||||
(async () => {
|
||||
const result = await fetchUrlSafely(url);
|
||||
if (result.type === "image" && result.data && result.mimeType) {
|
||||
// Resize fetched images too (R5)
|
||||
const { data: resizedBuffer, mimeType: resizedMime } =
|
||||
await resizeImageForVision(result.data, maxDimension);
|
||||
|
||||
@@ -1207,17 +1215,18 @@ async function _runSingleMediaAnalysis(
|
||||
sourceLabel: `[gambar di atas berasal dari link ${url} pada pesan id=${targetId}]`,
|
||||
};
|
||||
const existing = imageMap.get(targetId) ?? [];
|
||||
if (existing.length < 8) {
|
||||
existing.push(part);
|
||||
imageMap.set(targetId, existing);
|
||||
} else if (result.type === "text" && result.textContent) {
|
||||
webTexts.push(`[Isi Web dari ${url}]: ${result.textContent}`);
|
||||
}
|
||||
}),
|
||||
} else if (result.type === "text" && result.textContent) {
|
||||
urlWebTexts.push(`[Isi Web dari ${url}]: ${result.textContent}`);
|
||||
}
|
||||
})(),
|
||||
);
|
||||
if (webTexts.length > 0) webTextMap.set(targetId, webTexts);
|
||||
}
|
||||
|
||||
// ── 3. Sticker / embed / custom emoji images ──
|
||||
// ── Sticker / embed / custom emoji download promises ──
|
||||
const mediaEvidence = extractMessageMediaEvidence(target.metadata);
|
||||
const mediaCandidates: Array<{
|
||||
messageId: string;
|
||||
@@ -1273,10 +1282,12 @@ async function _runSingleMediaAnalysis(
|
||||
})),
|
||||
];
|
||||
|
||||
const remainingSlots = Math.max(0, 8 - (imageMap.get(targetId)?.length ?? 0));
|
||||
for (const candidate of mediaCandidates) {
|
||||
downloadPromises.push(
|
||||
(async () => {
|
||||
// Skip if we already have 8 images
|
||||
if ((imageMap.get(targetId)?.length ?? 0) >= 8) return;
|
||||
|
||||
await Promise.all(
|
||||
mediaCandidates.slice(0, remainingSlots).map(async (candidate) => {
|
||||
// Vision cache check before download
|
||||
const visionCacheKey = candidate.customEmojiId
|
||||
? makeCustomEmojiCacheKey(candidate.customEmojiId)
|
||||
@@ -1310,8 +1321,10 @@ async function _runSingleMediaAnalysis(
|
||||
stickerName: candidate.stickerName,
|
||||
};
|
||||
const existing = imageMap.get(targetId) ?? [];
|
||||
if (existing.length < 8) {
|
||||
existing.push(part);
|
||||
imageMap.set(targetId, existing);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
@@ -1322,7 +1335,6 @@ async function _runSingleMediaAnalysis(
|
||||
const result = await fetchUrlSafely(candidate.url);
|
||||
if (result.type !== "image" || !result.data || !result.mimeType) return;
|
||||
|
||||
// Resize sticker/emoji images too (R5)
|
||||
const { data: resizedBuffer, mimeType: resizedMime } =
|
||||
await resizeImageForVision(result.data, maxDimension);
|
||||
|
||||
@@ -1335,19 +1347,26 @@ async function _runSingleMediaAnalysis(
|
||||
|
||||
const part: MessageImagePart = {
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:${resizedMime};base64,${base64}`,
|
||||
},
|
||||
image_url: { url: `data:${resizedMime};base64,${base64}` },
|
||||
sourceLabel: candidate.label,
|
||||
stickerName: candidate.stickerName,
|
||||
customEmojiId: candidate.customEmojiId,
|
||||
customEmojiName: candidate.customEmojiName,
|
||||
};
|
||||
const existing = imageMap.get(targetId) ?? [];
|
||||
if (existing.length < 8) {
|
||||
existing.push(part);
|
||||
imageMap.set(targetId, existing);
|
||||
}),
|
||||
}
|
||||
})(),
|
||||
);
|
||||
}
|
||||
|
||||
// Execute ALL media downloads in parallel
|
||||
await Promise.all(downloadPromises);
|
||||
|
||||
// Collect web text results from URL fetches
|
||||
if (urlWebTexts.length > 0) webTextMap.set(targetId, urlWebTexts);
|
||||
|
||||
// ── 4. Vision analysis for every image ──
|
||||
await Promise.all(
|
||||
|
||||
Reference in New Issue
Block a user