Files
dashboard/backend/services/insightVariation.js
T
2026-08-27 14:26:19 +07:00

102 lines
4.1 KiB
JavaScript

/**
* Blok prompt untuk permintaan generate ULANG.
*
* Operator menekan tombol lagi karena jawaban pertama kurang memuaskan. Datanya
* tidak berubah sama sekali, jadi yang diminta adalah sudut pandang dan tindakan
* yang berbeda — bukan angka yang berbeda.
*
* Percobaan pertama hanya menyuruh model "jangan sama". Itu tidak cukup untuk
* qwen2.5:7b: dengan jawaban lama ikut dikirim, model justru terpaku padanya dan
* mengembalikan kalimat yang sama dengan beberapa anak kalimat tambahan —
* tindakannya identik (terukur 90,7% mirip, daftar tindakan persis sama).
*
* Yang bekerja adalah memberi model LENSA yang konkret dan berbeda, bukan
* sekadar larangan. Tiap permintaan ulang mengambil satu sudut dari daftar di
* bawah, dan tindakan lama dikirim sebagai daftar yang HARUS dihindari, bukan
* sebagai contoh yang bisa ditiru.
*/
/**
* Sudut analisis yang berbeda-beda. Semuanya sah untuk kasus broiler dan tidak
* saling meniadakan — satu masalah yang sama memang bisa ditangani lewat jalur
* berbeda, dan itulah yang diminta operator saat menekan generate ulang.
*/
const ANALYSIS_ANGLES = [
'manajemen pakan — mutu, jadwal, bentuk ransum, dan cara pemberiannya',
'lingkungan kandang — suhu, kelembapan, ventilasi, dan kepadatan',
'kesehatan dan biosekuriti — penyakit subklinis, stres, dan program vaksinasi',
'manajemen air minum dan pencahayaan',
'penanganan operasional harian — keseragaman bobot, sortir, dan waktu panen',
'efisiensi biaya dan kehilangan pakan — tumpah, terbuang, atau tidak tercatat',
];
/** Ambil daftar tindakan dari jawaban sebelumnya supaya bisa dilarang diulang. */
const extractPreviousActions = (previousText) => {
if (typeof previousText !== 'string') return [];
// Bagian TINDAKAN ditulis sebagai daftar bernomor di akhir jawaban.
const section = previousText.split(/TINDAKAN\s*:?/i)[1];
const source = section || previousText;
return source
.split('\n')
.map((line) => line.trim())
.filter((line) => /^\d+[.)]\s+/.test(line))
.map((line) => line.replace(/^\d+[.)]\s+/, '').slice(0, 200))
.slice(0, 6);
};
/**
* @param {string} previousText Jawaban yang sedang tampil di layar.
* @param {number} [angleIndex] Sudut yang dipakai; acak kalau tidak diberikan.
* @returns {string} Blok untuk ditempel di akhir prompt. Kosong kalau tidak ada
* jawaban sebelumnya — artinya ini bukan permintaan ulang.
*/
const buildVariationInstruction = (previousText, angleIndex) => {
if (typeof previousText !== 'string' || previousText.trim().length === 0) {
return '';
}
const index =
Number.isInteger(angleIndex) && angleIndex >= 0
? angleIndex % ANALYSIS_ANGLES.length
: Math.floor(Math.random() * ANALYSIS_ANGLES.length);
const angle = ANALYSIS_ANGLES[index];
const previousActions = extractPreviousActions(previousText);
const banned =
previousActions.length > 0
? `\n\nTINDAKAN BERIKUT SUDAH PERNAH DISARANKAN DAN DILARANG DIULANG:\n${previousActions
.map((action, i) => `${i + 1}. ${action}`)
.join('\n')}`
: '';
return `
PERMINTAAN ULANG — WAJIB BEDA DARI JAWABAN SEBELUMNYA
Operator sudah membaca analisis sebelumnya dan meminta analisis LAIN untuk data
yang sama persis. Aturannya:
1. ANGKA TIDAK BOLEH BERUBAH. Datanya identik, jadi setiap angka wajib sama
persis dengan DATA OPERASIONAL di atas. Angka baru yang tidak ada di data
berarti mengarang, dan itu lebih buruk daripada jawaban yang mirip.
2. SUDUT PANDANG WAJIB: ${angle}.
Bahas penyimpangan yang sama DARI SUDUT INI. Kalau data untuk sudut ini tidak
tersedia, katakan terus terang di bagian BELUM DAPAT DIPASTIKAN — jangan
mengarang datanya, dan jangan diam-diam kembali ke sudut sebelumnya.
3. TINDAKAN WAJIB BARU. Berikan tindakan yang berbeda, yang masuk akal dari
sudut pandang di atas. Menyalin atau memparafrasekan tindakan sebelumnya
dianggap gagal memenuhi permintaan.
4. JANGAN menyalin kalimat mana pun dari jawaban sebelumnya. Tulis ulang dari
awal.${banned}`;
};
module.exports = {
buildVariationInstruction,
extractPreviousActions,
ANALYSIS_ANGLES,
};