From 55ee8ade163d39f5156674e95db36c218ce0a1a0 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Tue, 2 Jun 2026 11:08:41 +0700 Subject: [PATCH] fix: vision model hanya deskripsi, tidak memutuskan moderasi Root cause: vision model diminta untuk 'flag' dan 'menilai' gambar, sehingga screenshot terminal/chat biasa diklaim sebagai 'situs perjudian'. Fix: - vision prompt: HANYA deskripsi objektif (objek, teks, layout, jenis gambar) - larang tegas kata 'gambling', 'judi', 'pelanggaran', 'harus dihapus' - tambah buildGeneralImageVisionPrompt di discord-gateway stickerPrompt - MEDIA_INSTRUCTIONS: tegaskan batch LLM adalah hakim, vision hanya saksi mata - deskripsi netral (terminal, chat, editor kode) tidak boleh jadi dasar flag Co-authored-by: Claude Opus 4.8 --- .../ai-moderation/llmModerationClient.ts | 30 +---------- .../modules/ai-moderation/moderationPrompt.ts | 24 ++++----- .../modules/ai-moderation/stickerPrompt.ts | 39 ++++++++++++++ src/moderation/moderationPrompt.ts | 24 ++++----- src/moderation/stickerPrompt.ts | 53 +++++++++---------- 5 files changed, 88 insertions(+), 82 deletions(-) diff --git a/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts b/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts index 5fc84cb..42c4dcd 100644 --- a/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts +++ b/services/discord-gateway/src/modules/ai-moderation/llmModerationClient.ts @@ -22,6 +22,7 @@ import { } from "./stickerCache.js"; import { buildCustomEmojiVisionPrompt, + buildGeneralImageVisionPrompt, buildStickerTextOnlyWarning, buildStickerVisionPrompt, } from "./stickerPrompt.js"; @@ -587,34 +588,7 @@ const analyzeSingleMediaImage = async ( ? buildStickerVisionPrompt(image.stickerName, messageId) : image.customEmojiName ? buildCustomEmojiVisionPrompt(image.customEmojiName, messageId) - : [ - `Analisis media Discord berikut sebagai evidence moderasi. ${image.sourceLabel}`, - ``, - `Jelaskan SECARA SPESIFIK apa yang TERLIHAT di gambar (objek, teks, warna dominan, layout).`, - `Jangan menebak-nebak atau mengasumsikan konten yang tidak terlihat langsung.`, - ``, - `HANYA flag jika gambar secara JELAS dan TIDAK AMBIGU menampilkan:`, - `- Antarmuka situs judi yang JELAS TERLIHAT (ada chip, kartu, meja taruhan, odds, deposit/withdraw)`, - - `- Konten seksual eksplisit/NSFW/pornografi`, - `- Darah/luka/gore nyata (BUKAN kartun/meme/animasi)`, - `- Narkoba atau obat terlarang yang bisa diidentifikasi spesifik`, - `- Simbol kebencian (swastika, simbol teroris) yang JELAS`, - `- Ajakan bunuh diri atau self-harm eksplisit`, - `- Informasi pribadi (alamat, nomor telepon, KTP) yang bocor`, - ``, - `Jika gambar HANYA berisi: chat biasa, meme lucu, foto makanan, selfie,`, - `screenshot discord/wa/media sosial biasa, landscape, hewan, screenshot game,`, - `atau konten sehari-hari lainnya → JELASKAN ISI YANG TERLIHAT dan KONFIRMASI AMAN.`, - ``, - `JANGAN PERNAH mengklaim gambar adalah "antarmuka judi" atau "situs perjudian"`, - `KECUALI ada BUKTI VISUAL SPESIFIK seperti chip, kartu remi, meja taruhan,`, - `odds, deposit/withdraw, atau logo situs judi yang DIKENALI.`, - `Screenshot aplikasi chat atau media sosial BUKAN situs judi.`, - ``, - `Jawab Bahasa Indonesia, maksimal 3 kalimat. Berikan deskripsi objektif,`, - `bukan asumsi. Jika aman, katakan "aman" dengan jelas.`, - ].join("\n"); + : buildGeneralImageVisionPrompt(image.sourceLabel, messageId); try { const completion = await withLlmConcurrency(async () => diff --git a/services/discord-gateway/src/modules/ai-moderation/moderationPrompt.ts b/services/discord-gateway/src/modules/ai-moderation/moderationPrompt.ts index 5b72a0b..fbef0d9 100644 --- a/services/discord-gateway/src/modules/ai-moderation/moderationPrompt.ts +++ b/services/discord-gateway/src/modules/ai-moderation/moderationPrompt.ts @@ -63,26 +63,24 @@ Jangan pernah flag hanya berdasarkan kecurigaan atau ketidakjelasan konteks. // --------------------------------------------------------------------------- const MEDIA_INSTRUCTIONS = `## Instruksi Analisis Media -Gambar, sticker, embed image, preview link, dan attachment sudah dianalisis lewat request media terpisah sebelum batch utama. -Baris "Media analysis" memberikan DESKRIPSI VISUAL tentang apa yang terlihat di gambar, BUKAN keputusan moderasi final. +Gambar, sticker, embed image, preview link, dan attachment sudah DIDESKRIPSIKAN oleh vision model sebelum batch utama. +Baris "Media analysis" berisi DESKRIPSI OBJEKTIF tentang apa yang terlihat di gambar, BUKAN keputusan moderasi. +Vision model TIDAK memutuskan apakah gambar melanggar atau tidak — ia hanya mendeskripsikan isi visual. -## ATURAN KRITIS — Jangan Flag Gambar Biasa sebagai Judi -- **Screenshot Discord/WhatsApp/Telegram/media sosial biasa BUKAN situs judi.** Jangan pernah mengklaim screenshot chat sebagai "antarmuka perjudian". -- **Foto makanan, selfie, pemandangan, hewan, meme, screenshot game BUKAN konten melanggar.** -- **Gambar dengan teks bahasa Indonesia biasa BUKAN promosi judi.** -- HANYA flag "gambling" jika Media analysis secara SPESIFIK menyebutkan melihat elemen judi NYATA: chip, kartu remi, meja taruhan, odds, deposit/withdraw, atau logo situs judi yang DIKENALI. -- Jika Media analysis hanya mendeskripsikan "antarmuka aplikasi" atau "tampilan web" tanpa menyebutkan elemen judi spesifik → jangan flag gambling. -- Jika Media analysis bilang "aman" atau "tidak ada konten melanggar" → percaya itu. -- **Bukti teks LEBIH PENTING dari bukti visual.** Jika teks pesan adalah percakapan biasa ("Aku suka nasgor loh", "Halo guys", "Pagi semua") dan tidak mengandung promosi judi/narkoba/scam, maka gambar tersebut SANGAT TIDAK MUNGKIN adalah pelanggaran. JANGAN kontradiksi antara teks dan gambar — percaya teks terlebih dahulu. -- **Cross-check wajib**: Jika teks pesan clean/aman, maka analisis gambar yang mengklaim ada pelanggaran berat HARUS diabaikan kecuali ada bukti visual yang SANGAT JELAS dan TIDAK TERBANTAHKAN. +## ATURAN KRITIS — Kamu yang Memutuskan, Bukan Vision Model +- **KAMU adalah moderator.** Deskripsi dari vision model adalah SAKSI MATA, bukan hakim. +- Jika deskripsi vision menyebutkan "screenshot terminal", "aplikasi chat", "tampilan website", "foto makanan" → itu BUKAN bukti pelanggaran apapun. +- HANYA flag "gambling" jika KAMU menyimpulkan dari deskripsi bahwa gambar menunjukkan situs judi (chip, kartu remi, meja taruhan, odds, deposit/withdraw). +- **Bukti teks LEBIH PENTING dari deskripsi gambar.** Jika teks pesan adalah percakapan biasa ("Aku suka nasgor loh", "Halo guys") dan tidak mengandung promosi judi, maka gambar tersebut TIDAK MUNGKIN adalah pelanggaran judi. +- **Jika teks clean dan deskripsi gambar biasa → wajib clean.** Tidak peduli seberapa "mencurigakan" gambar terlihat bagi vision model. +- Deskripsi vision yang menyebutkan hal-hal netral (terminal, chat, editor kode, website, grafik, chart) TIDAK BOLEH dijadikan dasar untuk flag gambling. ## Panduan Khusus Sticker - Sticker Discord adalah media kartun/meme/ilustrasi, BUKAN foto atau video nyata. - Sticker sering bersifat humor, satir, atau ekspresi emosi yang dilebih-lebihkan. - Gambar sticker bisa menampilkan adegan kartun yang terlihat "keras" — itu SENI KARTUN, bukan dokumentasi kekerasan nyata. - Nama sticker yang terdengar provokatif (mis. "Singa injek pejabat") adalah konteks satir/humor. JANGAN flag berdasarkan nama sticker saja. -- Terapkan standar yang lebih longgar untuk konten kartun/meme dibanding foto/video nyata. -- Sticker yang berhasil diunduh WAJIB diperlakukan sebagai image evidence, bukan sekadar nama sticker.`; +- Terapkan standar yang lebih longgar untuk konten kartun/meme dibanding foto/video nyata.`; // --------------------------------------------------------------------------- // Section: Few-Shot Examples diff --git a/services/discord-gateway/src/modules/ai-moderation/stickerPrompt.ts b/services/discord-gateway/src/modules/ai-moderation/stickerPrompt.ts index 1c671af..33b859d 100644 --- a/services/discord-gateway/src/modules/ai-moderation/stickerPrompt.ts +++ b/services/discord-gateway/src/modules/ai-moderation/stickerPrompt.ts @@ -94,3 +94,42 @@ export function buildCustomEmojiTextOnlyFallback(emojiName: string): string { `Custom emoji di Discord adalah ekspresi/emosi umum, bukan konten ofensif.]` ); } + +/** + * Prompt for analyzing regular images (attachments, embeds, links). + * + * VISION MODEL ONLY DESCRIBES — it does NOT decide moderation. + * The main text LLM makes all moderation decisions using the description. + */ +export function buildGeneralImageVisionPrompt( + sourceLabel: string, + _messageId: string, +): string { + return [ + `Deskripsikan gambar ini secara objektif dan spesifik.`, + `${sourceLabel}`, + ``, + `Jelaskan HANYA apa yang kamu LIHAT:`, + `- Objek utama apa yang ada di gambar?`, + `- Teks apa yang terlihat? (tulis persis jika bisa dibaca)`, + `- Warna dominan dan layout/tata letak?`, + `- Apakah ini screenshot, foto, meme, kartun, atau dokumen?`, + `- Konteks: apakah terlihat seperti aplikasi chat, terminal/console,`, + ` media sosial, game, website, editor kode, dokumen, atau lainnya?`, + ``, + `PENTING — Deskripsi saja, JANGAN MEMUTUSKAN MODERASI:`, + `- JANGAN sebut "gambling", "judi", "pelanggaran", "melanggar", atau flag apapun.`, + `- JANGAN bilang "harus dihapus", "harus diblokir", atau rekomendasi tindakan.`, + `- Tugasmu HANYA mendeskripsikan isi gambar. BUKAN menilai.`, + `- Screenshot terminal/console/shell/editor kode → deskripsikan sebagai "terminal/console".`, + `- Screenshot aplikasi chat (Discord/WA/Telegram/dll) → deskripsikan sebagai "aplikasi chat".`, + `- Screenshot website dengan grafik/chart → deskripsikan kontennya secara faktual.`, + `- JANGAN PERNAH mengklaim gambar adalah "situs judi" atau "antarmuka perjudian".`, + ` Itu BUKAN tugasmu. Kamu hanya perlu menyebutkan: "tampilan website dengan grafik",`, + ` "screenshot terminal", "aplikasi chat dengan teks percakapan", dll.`, + ``, + `Format jawaban: Deskripsi singkat 2-3 kalimat dalam Bahasa Indonesia.`, + `Mulai dengan menyebutkan JENIS gambar (screenshot/foto/kartun/dokumen).`, + `Akhiri dengan "Deskripsi selesai."`, + ].join("\n"); +} diff --git a/src/moderation/moderationPrompt.ts b/src/moderation/moderationPrompt.ts index 5b72a0b..fbef0d9 100644 --- a/src/moderation/moderationPrompt.ts +++ b/src/moderation/moderationPrompt.ts @@ -63,26 +63,24 @@ Jangan pernah flag hanya berdasarkan kecurigaan atau ketidakjelasan konteks. // --------------------------------------------------------------------------- const MEDIA_INSTRUCTIONS = `## Instruksi Analisis Media -Gambar, sticker, embed image, preview link, dan attachment sudah dianalisis lewat request media terpisah sebelum batch utama. -Baris "Media analysis" memberikan DESKRIPSI VISUAL tentang apa yang terlihat di gambar, BUKAN keputusan moderasi final. +Gambar, sticker, embed image, preview link, dan attachment sudah DIDESKRIPSIKAN oleh vision model sebelum batch utama. +Baris "Media analysis" berisi DESKRIPSI OBJEKTIF tentang apa yang terlihat di gambar, BUKAN keputusan moderasi. +Vision model TIDAK memutuskan apakah gambar melanggar atau tidak — ia hanya mendeskripsikan isi visual. -## ATURAN KRITIS — Jangan Flag Gambar Biasa sebagai Judi -- **Screenshot Discord/WhatsApp/Telegram/media sosial biasa BUKAN situs judi.** Jangan pernah mengklaim screenshot chat sebagai "antarmuka perjudian". -- **Foto makanan, selfie, pemandangan, hewan, meme, screenshot game BUKAN konten melanggar.** -- **Gambar dengan teks bahasa Indonesia biasa BUKAN promosi judi.** -- HANYA flag "gambling" jika Media analysis secara SPESIFIK menyebutkan melihat elemen judi NYATA: chip, kartu remi, meja taruhan, odds, deposit/withdraw, atau logo situs judi yang DIKENALI. -- Jika Media analysis hanya mendeskripsikan "antarmuka aplikasi" atau "tampilan web" tanpa menyebutkan elemen judi spesifik → jangan flag gambling. -- Jika Media analysis bilang "aman" atau "tidak ada konten melanggar" → percaya itu. -- **Bukti teks LEBIH PENTING dari bukti visual.** Jika teks pesan adalah percakapan biasa ("Aku suka nasgor loh", "Halo guys", "Pagi semua") dan tidak mengandung promosi judi/narkoba/scam, maka gambar tersebut SANGAT TIDAK MUNGKIN adalah pelanggaran. JANGAN kontradiksi antara teks dan gambar — percaya teks terlebih dahulu. -- **Cross-check wajib**: Jika teks pesan clean/aman, maka analisis gambar yang mengklaim ada pelanggaran berat HARUS diabaikan kecuali ada bukti visual yang SANGAT JELAS dan TIDAK TERBANTAHKAN. +## ATURAN KRITIS — Kamu yang Memutuskan, Bukan Vision Model +- **KAMU adalah moderator.** Deskripsi dari vision model adalah SAKSI MATA, bukan hakim. +- Jika deskripsi vision menyebutkan "screenshot terminal", "aplikasi chat", "tampilan website", "foto makanan" → itu BUKAN bukti pelanggaran apapun. +- HANYA flag "gambling" jika KAMU menyimpulkan dari deskripsi bahwa gambar menunjukkan situs judi (chip, kartu remi, meja taruhan, odds, deposit/withdraw). +- **Bukti teks LEBIH PENTING dari deskripsi gambar.** Jika teks pesan adalah percakapan biasa ("Aku suka nasgor loh", "Halo guys") dan tidak mengandung promosi judi, maka gambar tersebut TIDAK MUNGKIN adalah pelanggaran judi. +- **Jika teks clean dan deskripsi gambar biasa → wajib clean.** Tidak peduli seberapa "mencurigakan" gambar terlihat bagi vision model. +- Deskripsi vision yang menyebutkan hal-hal netral (terminal, chat, editor kode, website, grafik, chart) TIDAK BOLEH dijadikan dasar untuk flag gambling. ## Panduan Khusus Sticker - Sticker Discord adalah media kartun/meme/ilustrasi, BUKAN foto atau video nyata. - Sticker sering bersifat humor, satir, atau ekspresi emosi yang dilebih-lebihkan. - Gambar sticker bisa menampilkan adegan kartun yang terlihat "keras" — itu SENI KARTUN, bukan dokumentasi kekerasan nyata. - Nama sticker yang terdengar provokatif (mis. "Singa injek pejabat") adalah konteks satir/humor. JANGAN flag berdasarkan nama sticker saja. -- Terapkan standar yang lebih longgar untuk konten kartun/meme dibanding foto/video nyata. -- Sticker yang berhasil diunduh WAJIB diperlakukan sebagai image evidence, bukan sekadar nama sticker.`; +- Terapkan standar yang lebih longgar untuk konten kartun/meme dibanding foto/video nyata.`; // --------------------------------------------------------------------------- // Section: Few-Shot Examples diff --git a/src/moderation/stickerPrompt.ts b/src/moderation/stickerPrompt.ts index 289f2bb..33b859d 100644 --- a/src/moderation/stickerPrompt.ts +++ b/src/moderation/stickerPrompt.ts @@ -96,43 +96,40 @@ export function buildCustomEmojiTextOnlyFallback(emojiName: string): string { } /** - * Prompt used for general attachment/web images (not stickers or emojis). + * Prompt for analyzing regular images (attachments, embeds, links). * - * This is the default prompt for analyzing regular images. It includes - * explicit guidance on gambling detection to prevent false positives - * (e.g., flagging screenshots of food, finance, or casual content as gambling). + * VISION MODEL ONLY DESCRIBES — it does NOT decide moderation. + * The main text LLM makes all moderation decisions using the description. */ export function buildGeneralImageVisionPrompt( sourceLabel: string, - messageId: string, + _messageId: string, ): string { return [ - `Analisis media Discord berikut sebagai evidence moderasi.`, + `Deskripsikan gambar ini secara objektif dan spesifik.`, `${sourceLabel}`, ``, - `PENTING — Panduan Deteksi Pelanggaran:`, + `Jelaskan HANYA apa yang kamu LIHAT:`, + `- Objek utama apa yang ada di gambar?`, + `- Teks apa yang terlihat? (tulis persis jika bisa dibaca)`, + `- Warna dominan dan layout/tata letak?`, + `- Apakah ini screenshot, foto, meme, kartun, atau dokumen?`, + `- Konteks: apakah terlihat seperti aplikasi chat, terminal/console,`, + ` media sosial, game, website, editor kode, dokumen, atau lainnya?`, ``, - `**Gambling/Judi:**`, - `- HANYA flag jika gambar JELAS menampilkan promosi atau antarmuka situs judi/taruhan nyata (poker, slots, sports betting).`, - `- Screenshot Discord/WhatsApp/Telegram/media sosial/chat biasa BUKAN situs judi — jangan flag.`, - `- Cryptocurrency UI atau finance apps (Coinbase, Binance, exchange) BUKAN judi — jangan flag sebagai gambling.`, - `- Screenshot ekonomi game, NFT marketplace, atau trading UI BUKAN judi — jangan flag.`, - `- Gambar makanan, meme, selfie, pemandangan atau konten casual TIDAK PERNAH gambling, bahkan jika ada teks finansial.`, - `- Hanya flag gambling jika ada BUKTI VISUAL JELAS: tombol taruhan, odds, chips, roulette wheel, atau branding situs judi terkenal.`, - `- Jika tidak yakin apakah sebuah gambar menampilkan situs judi atau sekadar aplikasi biasa → pilih "Tidak ada indikasi pelanggaran."`, + `PENTING — Deskripsi saja, JANGAN MEMUTUSKAN MODERASI:`, + `- JANGAN sebut "gambling", "judi", "pelanggaran", "melanggar", atau flag apapun.`, + `- JANGAN bilang "harus dihapus", "harus diblokir", atau rekomendasi tindakan.`, + `- Tugasmu HANYA mendeskripsikan isi gambar. BUKAN menilai.`, + `- Screenshot terminal/console/shell/editor kode → deskripsikan sebagai "terminal/console".`, + `- Screenshot aplikasi chat (Discord/WA/Telegram/dll) → deskripsikan sebagai "aplikasi chat".`, + `- Screenshot website dengan grafik/chart → deskripsikan kontennya secara faktual.`, + `- JANGAN PERNAH mengklaim gambar adalah "situs judi" atau "antarmuka perjudian".`, + ` Itu BUKAN tugasmu. Kamu hanya perlu menyebutkan: "tampilan website dengan grafik",`, + ` "screenshot terminal", "aplikasi chat dengan teks percakapan", dll.`, ``, - `**Illegal Content:**`, - `- Jangan flag berdasarkan kecurigaan. HANYA flag jika ada BUKTI VISUAL JELAS dari konten ilegal (narkoba, senjata, dokumen palsu).`, - ``, - `**Sexual Content & NSFW:**`, - `- Jangan flag foto casual/fashion hanya karena ada bagian tubuh. Flag HANYA jika gambar eksplisit atau pornografi.`, - ``, - `**Violence:**`, - `- Screenshot game/anime action BUKAN kekerasan nyata — jangan flag.`, - `- Jangan flag meme atau karya seni yang menampilkan adegan dramatik.`, - ``, - `Jelaskan isi visual, teks yang terlihat, dan konteks risiko.`, - `Jawab Bahasa Indonesia, maksimal 3 kalimat. Jangan bilang kurang konteks atau perlu admin cek; berikan observasi langsung dari media.`, - `Jika gambar tampak aman/tidak ada risiko, tulis: "Tidak ada indikasi pelanggaran terdeteksi."`, + `Format jawaban: Deskripsi singkat 2-3 kalimat dalam Bahasa Indonesia.`, + `Mulai dengan menyebutkan JENIS gambar (screenshot/foto/kartun/dokumen).`, + `Akhiri dengan "Deskripsi selesai."`, ].join("\n"); }