fix: vision analysis retry + fallback jelas saat gagal

Vision API call sekarang pakai retryWithBackoff (2 retries instant).
Fallback message tegas: 'GAGAL DIANALISIS — JANGAN mengasumsikan aman'.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-02 11:41:18 +07:00
co-authored by Claude Opus 4.8
parent 64643bb066
commit 74400376a0
2 changed files with 59 additions and 37 deletions
@@ -591,26 +591,36 @@ const analyzeSingleMediaImage = async (
: buildGeneralImageVisionPrompt(image.sourceLabel, messageId); : buildGeneralImageVisionPrompt(image.sourceLabel, messageId);
try { try {
const completion = await withLlmConcurrency(async () => const completion = await retryWithBackoff(
openai.chat.completions.create({ async () => {
model: config.AI_LLM_VISION_MODEL ?? config.AI_LLM_MODEL, return withLlmConcurrency(async () =>
messages: [ openai.chat.completions.create({
{ model: config.AI_LLM_VISION_MODEL ?? config.AI_LLM_MODEL,
role: "user", messages: [
content: [
{ {
type: "text", role: "user",
text: promptText, content: [
{
type: "text",
text: promptText,
},
{ type: "image_url", image_url: image.image_url },
],
}, },
{ type: "image_url", image_url: image.image_url },
], ],
}, temperature: 0.1,
], top_p: 0.9,
temperature: 0.1, max_tokens: 500,
top_p: 0.9, stream: false,
max_tokens: 500, } as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming),
stream: false, );
} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming), },
{
retries: 2,
minTimeout: 0,
maxTimeout: 0,
logger: log,
},
); );
const content = completion.choices[0]?.message?.content?.trim(); const content = completion.choices[0]?.message?.content?.trim();
@@ -630,9 +640,11 @@ const analyzeSingleMediaImage = async (
messageId, messageId,
error: error instanceof Error ? error.message : String(error), error: error instanceof Error ? error.message : String(error),
}, },
"Separate media analysis failed", "Vision analysis failed after retries — image not analyzed",
); );
return `[Media analysis for message ${messageId}] ${image.sourceLabel}: gagal dianalisis otomatis; gunakan metadata URL/nama media sebagai evidence.`; // Return a clear signal that vision analysis FAILED — so batch LLM knows
// the image could not be described and must NOT assume it's clean.
return `[Media analysis for message ${messageId}] ${image.sourceLabel}: GAGAL DIANALISIS — gambar tidak dapat diunduh atau vision API gagal setelah 3x percobaan. JANGAN mengasumsikan gambar aman hanya karena gagal dianalisis. Gunakan metadata URL/nama file saja sebagai petunjuk.`;
} }
}; };
+28 -18
View File
@@ -591,26 +591,36 @@ const analyzeSingleMediaImage = async (
: buildGeneralImageVisionPrompt(image.sourceLabel, messageId); : buildGeneralImageVisionPrompt(image.sourceLabel, messageId);
try { try {
const completion = await withLlmConcurrency(async () => const completion = await retryWithBackoff(
openai.chat.completions.create({ async () => {
model: config.AI_LLM_VISION_MODEL ?? config.AI_LLM_MODEL, return withLlmConcurrency(async () =>
messages: [ openai.chat.completions.create({
{ model: config.AI_LLM_VISION_MODEL ?? config.AI_LLM_MODEL,
role: "user", messages: [
content: [
{ {
type: "text", role: "user",
text: promptText, content: [
{
type: "text",
text: promptText,
},
{ type: "image_url", image_url: image.image_url },
],
}, },
{ type: "image_url", image_url: image.image_url },
], ],
}, temperature: 0.1,
], top_p: 0.9,
temperature: 0.1, max_tokens: 500,
top_p: 0.9, stream: false,
max_tokens: 500, } as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming),
stream: false, );
} as OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming), },
{
retries: 2,
minTimeout: 0,
maxTimeout: 0,
logger: log,
},
); );
const content = completion.choices[0]?.message?.content?.trim(); const content = completion.choices[0]?.message?.content?.trim();
@@ -632,7 +642,7 @@ const analyzeSingleMediaImage = async (
}, },
"Separate media analysis failed", "Separate media analysis failed",
); );
return `[Media analysis for message ${messageId}] ${image.sourceLabel}: gagal dianalisis otomatis; gunakan metadata URL/nama media sebagai evidence.`; return `[Media analysis for message ${messageId}] ${image.sourceLabel}: GAGAL DIANALISIS — gambar tidak dapat diunduh atau vision API gagal setelah 3x percobaan. JANGAN mengasumsikan gambar aman hanya karena gagal dianalisis. Gunakan metadata URL/nama file saja sebagai petunjuk.`;
} }
}; };