fix(ai-moderation): remove indonesianTextNormalizer to stop hallucinated slang flags
The rule-based badword detector was injecting [normalized_text] and
[normalization_notes] tags into the LLM prompt that caused false
positive hallucinations - the LLM started associating innocent words
('sapik', 'furina') with furry/sexual_deviation due to misleading
context injected by the normalizer.
Removed:
- indonesianTextNormalizer.ts (full file deletion)
- formatModerationTextEvidenceForPrompt import/usage in llmModerationClient
- formatModerationTextEvidenceForPrompt import/usage in conversationContext
- stale re-exports in index.ts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cfe7230a55
commit
e6e44b30c7
@@ -11,7 +11,7 @@ import type {
|
||||
AttachmentRecord,
|
||||
MessageRecord,
|
||||
} from "../message-capture/types.js";
|
||||
import { formatModerationTextEvidenceForPrompt } from "./indonesianTextNormalizer.js";
|
||||
|
||||
import { llmChat, llmVision } from "./llmClient.js";
|
||||
import { buildSystemPrompt as buildSystemPromptModular } from "./moderationPrompt.js";
|
||||
import {
|
||||
@@ -999,16 +999,6 @@ async function runTextOnlyBatch(
|
||||
const maxBatchSize = config.AI_LLM_TEXT_BATCH_SIZE ?? 20;
|
||||
const timeoutMs = config.AI_LLM_MEDIA_ANALYSIS_TIMEOUT_MS ?? 60000;
|
||||
|
||||
// Pre-compute text evidence (normalization + badword detection)
|
||||
const textEvidenceMap = new Map<string, string>();
|
||||
await Promise.all(
|
||||
targets.map(async (msg) => {
|
||||
const content = msg.edited_content ?? msg.content;
|
||||
const evidence = formatModerationTextEvidenceForPrompt(content);
|
||||
textEvidenceMap.set(msg.id, evidence);
|
||||
}),
|
||||
);
|
||||
|
||||
// ── Fetch web content from URLs in text-only messages ──
|
||||
// Prevents LLM from guessing based on domain name alone (e.g., false "scam" flags).
|
||||
// The fetched text content is injected into the message XML so the LLM can
|
||||
@@ -1156,8 +1146,6 @@ async function runTextOnlyBatch(
|
||||
const messagesBlock = batch
|
||||
.map((msg) => {
|
||||
const content = getAnalysisContent(msg);
|
||||
const textEvidence = textEvidenceMap.get(msg.id) ?? "";
|
||||
const textContext = textEvidence ? `\n${textEvidence}` : "";
|
||||
|
||||
// Inject fetched web content for URLs found in this message
|
||||
const msgUrls = extractUrlsFromText(content);
|
||||
@@ -1173,7 +1161,7 @@ async function runTextOnlyBatch(
|
||||
const userCtx = userContexts.get(msg.user_id) ?? "";
|
||||
|
||||
// XML delimiters wrap each message for prompt safety (R1)
|
||||
return `<message id="${msg.id}" user="${msg.username}">\n ${userCtx}\n <content>${content}</content>${textContext}${webContext}\n</message>`;
|
||||
return `<message id="${msg.id}" user="${msg.username}">\n ${userCtx}\n <content>${content}</content>${webContext}\n</message>`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
@@ -1652,12 +1640,9 @@ async function _runSingleMediaAnalysis(
|
||||
);
|
||||
|
||||
// ── 5. Build single-message prompt with XML delimiters (R1) ──
|
||||
const textEvidence = formatModerationTextEvidenceForPrompt(content);
|
||||
|
||||
const webTexts = webTextMap.get(targetId) ?? [];
|
||||
const mediaAnalyses = mediaAnalysisMap.get(targetId) ?? [];
|
||||
const webContext = webTexts.length > 0 ? `\n${webTexts.join("\n")}` : "";
|
||||
const textContext = textEvidence ? `\n${textEvidence}` : "";
|
||||
const mediaAnalysisContext =
|
||||
mediaAnalyses.length > 0 ? `\n${mediaAnalyses.join("\n")}` : "";
|
||||
|
||||
@@ -1693,7 +1678,7 @@ async function _runSingleMediaAnalysis(
|
||||
const userCtx = `<user_reputation trust_score="${rep.trust_score}" clean_streak="${rep.clean_message_streak}" total_infractions="${rep.total_infractions}" />${historyStr}`;
|
||||
|
||||
// XML delimiters wrap the message content (R1)
|
||||
const messageBlock = `<message id="${target.id}" user="${target.username}">\n ${userCtx}\n <content>${content}</content>${mediaContext ? ` ${mediaContext}` : ""}${textContext}${webContext}${mediaAnalysisContext}\n</message>`;
|
||||
const messageBlock = `<message id="${target.id}" user="${target.username}">\n ${userCtx}\n <content>${content}</content>${mediaContext ? ` ${mediaContext}` : ""}${webContext}${mediaAnalysisContext}\n</message>`;
|
||||
|
||||
// Modular system prompt with XML delimiters (R1, R7, R8)
|
||||
const correctedExamples = await buildCorrectedFewShotExamples();
|
||||
|
||||
Reference in New Issue
Block a user