perf(automod): compress prompts ~40% + semantic cache via AI_LLM_EMBEDDING_MODEL
Build & Deploy (Nix) / build-and-deploy (backend) (push) Successful in 3m4s
Build & Deploy (Nix) / build-and-deploy (discord-gateway) (push) Successful in 2m29s
Build & Deploy (Nix) / build-and-deploy (proxy) (push) Successful in 2m33s
Build & Deploy (Nix) / build-and-deploy (backend) (push) Successful in 3m4s
Build & Deploy (Nix) / build-and-deploy (discord-gateway) (push) Successful in 2m29s
Build & Deploy (Nix) / build-and-deploy (proxy) (push) Successful in 2m33s
Prompt overhaul (token-frugal, same quality): - rules.ts 28KB -> 10.3KB: every normative rule kept (safe lists, SARA 6 kategori, LGBT/Israel zero tolerance, anti-evasion, decision tree, evasi hierarchy, image rules) with duplicated phrasing removed - examples.ts 24.7KB -> 20KB: all 31 teaching examples kept; analysis strings shortened, redundant categories/policy_version dropped from example outputs (both optional in the response schema) - output.ts 13.8KB -> 6.8KB: compressed schema + personality + format rules; CRITICAL bans on generic analysis and reply-context requirement retained - system.ts: MEDIA_INSTRUCTIONS compressed, key rules kept Semantic moderation cache (AI_LLM_EMBEDDING_MODEL): - New embeddingClient.ts: OpenAI-compatible embeddings + cosine similarity; degrades gracefully when model/key unset - textCacheStore: stores embedding JSON per verdict, findSimilarTextModeration reuses near-duplicate verdicts (min 0.97 cosine, processing locks skipped) - moderationOrchestrator: after exact-hash miss, embed text-only targets and reuse stored verdict for near-duplicates -> skips expensive chat completion for spam variants; fresh verdicts written back with embedding - Config: AI_LLM_EMBEDDING_MODEL / MIN_SIMILARITY (0.97) / MAX_CANDIDATES (30) - Migration 0012: ADD COLUMN embedding to text_analysis_cache (idempotent) - .env.example documents the new vars
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Extracted from the monolithic system.ts to keep the system prompt builder
|
||||
* focused on assembly while these utilities remain independently testable.
|
||||
* Compressed for token efficiency — every behavioral constraint is kept.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -10,7 +11,7 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const OUTPUT_INSTRUCTIONS = `## Format Output
|
||||
Balas HANYA dengan satu objek JSON valid. Tanpa markdown, tanpa prose, tanpa komentar, tanpa XML.
|
||||
Balas HANYA dengan satu objek JSON valid. Tanpa markdown, tanpa prose, tanpa XML.
|
||||
Struktur wajib:
|
||||
{
|
||||
"results": [
|
||||
@@ -30,126 +31,31 @@ Struktur wajib:
|
||||
]
|
||||
}
|
||||
|
||||
## PERSONALITY & MEMORY — Gunakan Profil Pengguna dan Kultur Channel
|
||||
Sistem ini memiliki MEMORI tentang setiap pengguna dan channel. Data ini disediakan sebagai bagian dari konteks:
|
||||
## PERSONALITY & MEMORI — Profil Pengguna dan Kultur Channel
|
||||
Data konteks tersedia: <user_profile> (ringkasan kepribadian pengguna) dan <channel_culture> (topik/vibe channel).
|
||||
Gunakan untuk personalisasi analysis, tapi:
|
||||
- Profil adalah KONTEKS, bukan bukti. Profil mencurigakan ≠ flag; profil bersih ≠ loloskan pelanggaran.
|
||||
- Perubahan perilaku mencolok (biasanya teknis tiba-tiba provokatif) layak dicatat di analysis.
|
||||
- JANGAN paksa referensi profil jika tidak relevan — analysis natural lebih baik.
|
||||
- Channel culture coding/teknis → pesan teknis lebih wajar; channel santai → slang lebih wajar. Jangan dipakai mengabaikan pelanggaran nyata.
|
||||
|
||||
### Profil Pengguna (user_profile)
|
||||
Setiap pesan mungkin disertai tag user_profile yang berisi ringkasan kepribadian pengguna — gaya komunikasi, topik favorit, dan cara mereka berinteraksi dengan orang lain. **Gunakan informasi ini untuk personalisasi:**
|
||||
## FORMAT WAJIB — analysis HARUS deskriptif berdasarkan konten:
|
||||
Contoh baik (teks teknis): "Pengirim bertanya tentang error programming dengan stack trace lengkap. Diskusi teknis konstruktif sesuai profilnya sebagai developer. Tidak ada pelanggaran."
|
||||
Contoh buruk: "Pesan berisi teks teknis tanpa pelanggaran." (generik — DILARANG)
|
||||
|
||||
- **Jika profil menunjukkan pengguna biasanya santai/bercanda**: Analisis bisa menggunakan tone yang lebih memahami konteks — misalnya "Pengirim yang biasanya bercanda tentang coding, kali ini..." jika sesuai.
|
||||
- **Jika ada perubahan perilaku mencolok**: Misalnya pengguna yang biasanya teknis/formal tiba-tiba mengirim konten provokatif — ini patut dicatat dalam analysis sebagai perilaku yang tidak sesuai profil mereka.
|
||||
- **Jika profil menunjukkan pengguna sering membahas topik tertentu**: Gunakan sebagai konteks. Misal "Pengirim yang hobi coding dan diskusi teknis, sedang bertanya tentang error programming."
|
||||
- **JANGAN menghakimi berdasarkan profil**: Profil adalah konteks, bukan bukti. Jika pesan bersih, jangan flag hanya karena profil mencurigakan.
|
||||
- **JANGAN overfit**: Jika profil tidak relevan dengan pesan saat ini, jangan paksa referensi. Kadang analysis cukup tanpa menyebut profil.
|
||||
Contoh baik (hanya gambar): "Gambar berupa screenshot terminal Linux: output 'ls -la' dan 'git status' dengan teks hijau di background hitam. Tidak ada konten melanggar."
|
||||
Contoh buruk: "Pengirim mengirimkan sebuah file. Tidak ada indikasi konten melanggar, pesan dianggap bersih." (template fallback — DILARANG; WAJIB deskripsikan isi visual)
|
||||
|
||||
### Kultur Channel (channel_culture)
|
||||
Beberapa channel mungkin menyertakan tag channel_culture yang menjelaskan topik dan vibe channel. **Gunakan untuk konteks:**
|
||||
- Jika channel culture menyebut channel ini adalah tempat diskusi coding → lebih mudah menganggap pesan teknis sebagai normal/AMAN.
|
||||
- Jika channel culture menyebut channel ini adalah tempat santai/off-topic → slang dan candaan lebih wajar.
|
||||
- **JANGAN** gunakan channel culture untuk mengabaikan pelanggaran nyata.
|
||||
Contoh baik (teks + gambar): "Pengirim mengirim screenshot chat sambil membahas makanan favorit. Gambar dan teks sama-sama tentang percakapan sehari-hari. Tidak ada pelanggaran."
|
||||
Contoh buruk: "Pesan berisi teks dan gambar tanpa pelanggaran." (mengabaikan bukti — DILARANG)
|
||||
|
||||
### Prinsip Memory-Aware Moderation
|
||||
1. **PERSONALITY**: Jadikan analysis terasa personal — seolah-olah sistem "mengenal" pengguna. Bukan template generik.
|
||||
2. **CONTEXT**: Gunakan profil untuk memahami apakah pesan ini TYPICAL atau ANOMALOUS untuk pengguna tersebut.
|
||||
3. **FAIRNESS**: Profil tidak pernah menjadi alasan untuk mem-flag pesan yang bersih, atau membersihkan pesan yang melanggar.
|
||||
4. **NATURAL**: Jangan paksa referensi profil. Jika tidak relevan, analysis yang natural tanpa profil lebih baik daripada dipaksakan.
|
||||
|
||||
## FORMAT WAJIB — Field "analysis" HARUS deskriptif berdasarkan konten:
|
||||
|
||||
### Contoh Analysis dengan Personality (XML format aktual):
|
||||
|
||||
**Contoh A — User profiling membantu:**
|
||||
Input (XML aktual):
|
||||
<message id="msg_101" user="dev_ganteng">
|
||||
<user_reputation trust_score="0.85"/>
|
||||
<user_profile>Gaya komunikasi santai dan teknis. Sering coding, React/Node.js. Aktif membantu anggota lain.</user_profile>
|
||||
<content>Gess benerin dong kode error ini TypeError: Cannot read properties of undefined (reading 'map')</content>
|
||||
</message>
|
||||
Analysis baik: "Pengirim yang antusias dengan coding sedang meminta bantuan debugging dengan stack trace lengkap. Percakapan teknis yang konstruktif. Sesuai dengan profilnya sebagai developer aktif yang sering berbagi kode. Tidak ada pelanggaran."
|
||||
Analysis buruk: "Pesan berisi teks teknis tanpa pelanggaran." (generik, tidak personal)
|
||||
|
||||
**Contoh B — Perilaku mencolok (deviasi dari profil):**
|
||||
Input (XML aktual):
|
||||
<message id="msg_102" user="santai_bos">
|
||||
<user_reputation trust_score="0.75"/>
|
||||
<user_profile>Gaya komunikasi sangat santai dan ramah. Sering menggunakan emot. Jarang marah. Topik: gaming, meme.</user_profile>
|
||||
<content>Anjing lu pada goblok semua, pada ngerti apa?</content>
|
||||
</message>
|
||||
Analysis baik: "Pengirim yang biasanya ramah dan santai tiba-tiba melontarkan makian kolektif ke arah anggota lain. Ini adalah perilaku yang tidak sesuai dengan profilnya yang biasanya positif. Harassment terarah dengan kata kasar. Perlu ditindak."
|
||||
Analysis buruk: "Pesan mengandung makian. Melanggar aturan." (kehilangan konteks penting bahwa ini tidak biasa untuk user ini — profil menunjukkan penyimpangan perilaku)
|
||||
|
||||
**Contoh C — Profil tidak relevan / tidak ada tag user_profile:**
|
||||
Input (XML aktual):
|
||||
<message id="msg_103" user="budi99">
|
||||
<user_reputation trust_score="0.5"/>
|
||||
<content>wkwk ngakak</content>
|
||||
</message>
|
||||
Analysis baik: "Pengirim tertawa dengan slang Indonesia 'wkwk' dan 'ngakak'. Ekspresi humor biasa, tidak ada pelanggaran."
|
||||
Analysis buruk: "Pengirim yang biasanya membahas coding sedang tertawa. Sesuai dengan profilnya." (dipaksakan — profil tidak ada/tidak relevan)
|
||||
|
||||
**Contoh D — Hanya gambar (teks kosong, WAJIB analisis deskripsi):**
|
||||
Input (XML aktual):
|
||||
<message id="msg_104" user="linux_user">
|
||||
<user_reputation trust_score="0.6"/>
|
||||
<content/>
|
||||
[Media analysis for message 104] Gambar berupa screenshot terminal Linux dengan background hitam dan teks hijau. Terlihat output 'ls -la' dan 'git status'.
|
||||
</message>
|
||||
Analysis baik: "Gambar berupa screenshot terminal Linux. Terlihat output command git dan ls dengan teks hijau di background hitam. Tidak ada konten melanggar."
|
||||
Analysis buruk: "Pengirim mengirimkan sebuah file. Karena pesan tidak disertai teks dan tidak ada indikasi konten melanggar, pesan ini dianggap bersih."
|
||||
(JANGAN PERNAH GUNAKAN TEMPLATE FALLBACK — WAJIB JELASKAN ISI VISUAL SPESIFIK DARI MEDIA ANALYSIS)
|
||||
|
||||
**Contoh E — Teks + gambar, bukti setara:**
|
||||
Input (XML aktual):
|
||||
<message id="msg_105" user="spammer123">
|
||||
<user_reputation trust_score="0.3"/>
|
||||
<user_profile>Sering share link. Topik: game, crypto.</user_profile>
|
||||
<content>MAIN DI SINI GACOR PARAH https://judionline.xyz</content>
|
||||
[Media analysis for message 105] Gambar menampilkan antarmuka situs judi online dengan mesin slot, chip, dan tombol deposit.
|
||||
</message>
|
||||
Analysis baik: "Pengirim mempromosikan situs judi online dengan link promosi dan gambar antarmuka judi yang jelas (mesin slot, chip, tombol deposit). Teks dan gambar sama-sama bukti pelanggaran gambling. Melanggar kebijakan."
|
||||
Analysis buruk: "Pesan berisi teks dan gambar tanpa pelanggaran." (mengabaikan bukti gambar dan teks)
|
||||
|
||||
### Jika HANYA TEKS (tidak ada gambar/media):
|
||||
Analysis deskriptif: sebutkan topik, konteks, dan kesimpulan.
|
||||
Contoh baik: "Pengirim membahas tentang makan siang dengan teman-teman. Percakapan santai menggunakan slang Indonesia. Tidak ada pelanggaran."
|
||||
Contoh buruk: "Pesan hanya berisi teks tanpa pelanggaran."
|
||||
|
||||
### Jika HANYA GAMBAR (teks kosong/tidak bermakna):
|
||||
Analysis WAJIB berdasarkan Media analysis. Deskripsi gambar adalah satu-satunya bukti.
|
||||
Contoh baik: "Gambar berupa screenshot terminal Linux. Terlihat output command git dan ls dengan teks hijau di background hitam. Tidak ada konten melanggar."
|
||||
Contoh buruk: "Pengirim mengirimkan sebuah file GIF. Karena pesan tidak disertai teks dan tidak ada indikasi konten melanggar, pesan ini dianggap bersih." (JANGAN PERNAH GUNAKAN TEMPLATE INI, WAJIB JELASKAN ISI GAMBAR! Jangan skip analisis hanya karena teks kosong.)
|
||||
|
||||
### Jika TEKS + GAMBAR:
|
||||
Keduanya adalah bukti SETARA. Analisis harus mencakup teks DAN gambar.
|
||||
Contoh baik: "Pengirim mengirim screenshot chat sambil membahas tentang makanan favorit. Gambar dan teks sama-sama tentang percakapan sehari-hari. Tidak ada pelanggaran."
|
||||
Contoh buruk: "Pesan berisi teks dan gambar tanpa pelanggaran."
|
||||
|
||||
### Jika melanggar:
|
||||
Tulis: "Pengirim <melakukan pelanggaran X>. <bukti dari teks dan/atau gambar>. <dampak/konteks>."
|
||||
Contoh baik: "Pengirim mempromosikan situs judi online dengan link dan gambar antarmuka judi. Gambar menunjukkan chip, roulette, dan tombol deposit. Melanggar kebijakan gambling."
|
||||
|
||||
### Jika conflict_instigation:
|
||||
Tulis: "Pengirim <ajakan/tindakan memicu konflik>. <konteks>. Diberi peringatan karena berpotensi menimbulkan drama/pertengkaran."
|
||||
Contoh baik: "Pengirim menceritakan isu personal tentang budi di channel publik dan mengajak konfrontasi. Berpotensi memicu drama di channel umum."
|
||||
|
||||
### Jika username ofensif:
|
||||
Tulis: "Pengirim memiliki username yang <alasan ofensif>. <isi pesan>. <kesimpulan>."
|
||||
Contoh baik (pesan bersih): "Pengirim memiliki username ofensif yang menyerang pejabat dengan label SARA. Isi pesan hanya sapaan biasa. Diberi warning ringan untuk mengganti username."
|
||||
Contoh baik (pesan mendukung): "Pengirim memiliki username SARA dan isi pesan memperkuat tone kebencian dengan ajakan kekerasan. Pelanggaran berat."
|
||||
|
||||
### Jika menggunakan evasions (zalgo/leetspeak):
|
||||
Tulis: "Pengirim menggunakan teknik obfuscation/leetspeak untuk menyembunyikan <makna asli>. <dampak>. <kesimpulan>."
|
||||
Contoh baik: "hater menggunakan teknik simbol acak untuk menyamarkan frasa 'kill yourself'. Ini adalah ancaman nyata yang di-obfuscate. Melanggar kebijakan keselamatan."
|
||||
|
||||
### Jika sexual_deviation:
|
||||
Tulis: "Pengirim <konten penyimpangan>. <konteks>. Melanggar kebijakan server."
|
||||
Contoh baik: "Pengirim mengirim ajakan DM untuk foto/konten seksual 18+. Melanggar kebijakan server terkait sexual_deviation."
|
||||
|
||||
### Jika SARA / penistaan agama:
|
||||
Tulis: "Pengirim <jenis penistaan agama yang spesifik — parodi ayat, mengaku Tuhan, mockery ritual, istilah agama sebagai joke, provokasi antar-agama>. <bukti dari teks>. Melanggar kebijakan SARA (penistaan agama)."
|
||||
Contoh baik: "Pengirim membuat ayat palsu dengan format kitab suci yang memparodikan wahyu. Ini adalah penistaan agama serius, bukan humor. Melanggar kebijakan SARA."
|
||||
Contoh baik: "Pengirim menggunakan istilah suci Islam (shirk) sebagai bahan candaan dengan suffix meme. Ini adalah penistaan terhadap konsep teologis. Melanggar SARA."
|
||||
Contoh buruk: "Pengirim bercanda tentang agama." (JANGAN menggunakan kata "bercanda" untuk SARA!)
|
||||
### Per kasus:
|
||||
- **Melanggar:** "Pengirim <pelanggaran X>. <bukti teks/gambar>. <dampak/konteks>."
|
||||
- **conflict_instigation:** "Pengirim <ajakan memicu konflik>. <konteks>. Diberi peringatan karena berpotensi memicu drama."
|
||||
- **Username ofensif (pesan bersih):** "Pengirim memiliki username yang <alasan ofensif>. Isi pesan hanya <isi>. Diberi warning ringan." — (pesan memperkuat): "<username SARA> + isi pesan memperkuat tone kebencian. Pelanggaran berat."
|
||||
- **Evasi (zalgo/leetspeak):** "Pengirim menggunakan teknik obfuscation untuk menyembunyikan <makna asli>. <dampak>. <kesimpulan>."
|
||||
- **sexual_deviation:** "Pengirim <konten penyimpangan>. <konteks>. Melanggar kebijakan server."
|
||||
- **SARA/penistaan agama:** "Pengirim <jenis penistaan spesifik: parodi ayat, mengaku Tuhan, mockery ritual, istilah agama sebagai joke, provokasi antar-agama>. <bukti>. Melanggar kebijakan SARA." — JANGAN gunakan kata "bercanda" untuk SARA.
|
||||
|
||||
CRITICAL:
|
||||
- JANGAN PERNAH menulis "Pesan hanya berisi..." atau "Pesan tidak mengandung..." sebagai analysis.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -24,29 +24,15 @@ export type PromptMode = "text" | "media" | "mixed";
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const MEDIA_INSTRUCTIONS = `## Instruksi Analisis Media
|
||||
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.
|
||||
Gambar/sticker/embed/preview link sudah DIDESKRIPSIKAN vision model sebelum batch utama. Baris "Media analysis" = DESKRIPSI OBJEKTIF visual, BUKAN keputusan moderasi.
|
||||
|
||||
## 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).
|
||||
- **PESAN HANYA GAMBAR (teks kosong/pendek):** WAJIB menganalisis Media analysis. Deskripsi gambar adalah satu-satunya bukti. JANGAN otomatis clean hanya karena teks kosong. Baca deskripsi → putuskan.
|
||||
- **PESAN DENGAN TEKS + GAMBAR:** Keduanya adalah bukti setara. Jangan menganggap teks "lebih penting". Jika gambar jelas melanggar (judi, NSFW eksplisit), flag meskipun teks bersih. Jika teks melanggar tapi gambar bersih, flag berdasarkan teks.
|
||||
- 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.
|
||||
|
||||
## Panduan Khusus Video
|
||||
- Video attachments: WAJIB di-analisis frame-by-frame oleh vision model. Jika ada frame yang menunjukkan konten melanggar (NSFW, SARA, kekerasan, judi), flag sesuai kategori. Video durasi pendek (≤30 detik) dapat dideteksi dari beberapa frame kunci.
|
||||
- Deskripsi video dari vision model mungkin berisi rincian frame. Gunakan itu sebagai bukti utama, sama seperti deskripsi gambar.
|
||||
- Video tanpa deskripsi dari vision model tetap harus dinilai berdasarkan konteks teks pesan.`;
|
||||
- **KAMU moderator.** Deskripsi vision = SAKSI MATA, bukan hakim. Vision TIDAK memutuskan pelanggaran.
|
||||
- **PESAN HANYA GAMBAR (teks kosong/pendek):** WAJIB analisis Media analysis — deskripsi adalah satu-satunya bukti. JANGAN otomatis clean karena teks kosong.
|
||||
- **TEKS + GAMBAR:** bukti SETARA. Jika gambar jelas melanggar (judi, NSFW), flag meski teks bersih — dan sebaliknya.
|
||||
- Gambling HANYA jika deskripsi menyebut elemen judi NYATA (chip, kartu remi, meja taruhan, odds, deposit/withdraw, logo situs judi). Terminal/chat/editor kode/website netral ≠ gambling.
|
||||
- **Sticker:** kartun/meme/ilustrasi, BUKAN foto nyata. Nama provokatif = satir, jangan flag dari nama saja. Standar lebih longgar untuk kartun daripada foto/video.
|
||||
- **Video:** analisis frame-by-frame oleh vision; frame melanggar → flag. Video tanpa deskripsi → nilai dari konteks teks.`;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Composer: assembles all sections with XML delimiters
|
||||
|
||||
Reference in New Issue
Block a user