From aad62bc66befb5eb7a334c54b8651d8af4e7ac55 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Wed, 3 Jun 2026 20:59:10 +0700 Subject: [PATCH] fix(ai-moderation): strip fallback text from LLM analysis content --- .../ai-moderation/llmModerationClient.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts b/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts index 795233f..54fc7e5 100644 --- a/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts +++ b/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts @@ -476,6 +476,25 @@ type MessageImagePart = { customEmojiName?: string; }; +// --------------------------------------------------------------------------- +// Content helpers +// --------------------------------------------------------------------------- + +/** + * Returns the real text content for AI analysis, stripping fallback text + * that getDisplayContent() synthesized ("[Attachment: ...]", "[Sticker: ...]", + * "[Embed]"). These filenames alone are meaningless to the LLM and can + * falsely inflate a "clean" verdict when the actual image failed to download. + */ +function getAnalysisContent(message: MessageRecord): string { + const raw = message.edited_content ?? message.content; + const stripped = raw.replace( + /\[(?:Attachment|Sticker):[^\]]*\]|\[Embed\]/g, + "", + ); + return stripped.trim(); +} + // --------------------------------------------------------------------------- // Media detection helper // --------------------------------------------------------------------------- @@ -976,7 +995,7 @@ async function runTextOnlyBatch( const messagesBlock = batch .map((msg) => { - const content = msg.edited_content ?? msg.content; + const content = getAnalysisContent(msg); const textEvidence = textEvidenceMap.get(msg.id) ?? ""; const textContext = textEvidence ? `\n${textEvidence}` : ""; // XML delimiters wrap each message for prompt safety (R1) @@ -1129,7 +1148,7 @@ async function _runSingleMediaAnalysis( att.uploaded_url ?? null; const maxDimension = config.AI_LLM_IMAGE_MAX_DIMENSION ?? 1024; - const content = target.edited_content ?? target.content; + const content = getAnalysisContent(target); // ── 1-3. Parallel download of ALL media sources ── // Build all download promises upfront and execute them in one Promise.all.