ai insight rework #3, add root cause to daily ai insight

This commit is contained in:
Alberto-Audrix committed 2026-10-06 14:14:11 +07:00
1 parent c963bb778c
commit d5b0c12c40
8 files changed
+385 -47

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
import { describe, expect, it } from 'vitest';
import { parseAiResult } from '../insightParse.ts';
describe('parseAiResult with akar_masalah', () => {
it('parses standard 3-section json output', () => {
const raw = JSON.stringify({
kesimpulan: 'FCR 1.40 pada hari ke-28 berada di atas standar CP 707 (1.315).',
akar_masalah: 'Suhu lingkungan fluktuatif dan distribusi pakan kurang merata.',
insight: 'Lakukan kalibrasi suhu pemanas dan ratakan tempat pakan.',
});
const res = parseAiResult(raw);
expect(res).not.toBeNull();
expect(res?.summary).toBe('FCR 1.40 pada hari ke-28 berada di atas standar CP 707 (1.315).');
expect(res?.akar_masalah).toBe(
'Suhu lingkungan fluktuatif dan distribusi pakan kurang merata.'
);
expect(res?.insight).toBe('Lakukan kalibrasi suhu pemanas dan ratakan tempat pakan.');
});
it('handles markdown fences and think tags', () => {
const raw = `
<think>
Evaluating data for day 28. FCR is high.
</think>
\`\`\`json
{
"summary": "Kondisi pakan stabil.",
"root_cause": "Kondisi operasional optimal, tidak terdeteksi indikasi anomali.",
"rekomendasi": "Pertahankan ventilasi dan jadwal pemberian pakan."
}
\`\`\`
`;
const res = parseAiResult(raw);
expect(res).not.toBeNull();
expect(res?.summary).toBe('Kondisi pakan stabil.');
expect(res?.akar_masalah).toBe(
'Kondisi operasional optimal, tidak terdeteksi indikasi anomali.'
);
expect(res?.insight).toBe('Pertahankan ventilasi dan jadwal pemberian pakan.');
});
it('tolerates legacy 2-field format without akar_masalah', () => {
const raw = JSON.stringify({
kesimpulan: 'Bobot badan sesuai target.',
insight: 'Lanjutkan monitoring bobot mingguan.',
});
const res = parseAiResult(raw);
expect(res).not.toBeNull();
expect(res?.summary).toBe('Bobot badan sesuai target.');
expect(res?.akar_masalah).toBeUndefined();
expect(res?.insight).toBe('Lanjutkan monitoring bobot mingguan.');
});
});
+18 -1
View File
@@ -15,6 +15,7 @@
export interface AiResult {
summary: string;
akar_masalah?: string;
insight: string;
}
@@ -28,6 +29,17 @@ const KESIMPULAN_KEYS = [
'conclusion',
];
/** Field names seen standing in for the root cause / factors. */
const AKAR_MASALAH_KEYS = [
'akar_masalah',
'akar_penyebab',
'root_cause',
'penyebab',
'faktor_penyebab',
'faktor_pemicu',
'indikasi_masalah',
];
/** Field names seen standing in for the recommendation. */
const INSIGHT_KEYS = [
'insight',
@@ -122,6 +134,9 @@ export const parseAiResult = (text: string): AiResult | null => {
const kesimpulanHit = takeFirst(parsed, KESIMPULAN_KEYS);
if (kesimpulanHit) used.add(kesimpulanHit.key);
const akarMasalahHit = takeFirst(parsed, AKAR_MASALAH_KEYS);
if (akarMasalahHit) used.add(akarMasalahHit.key);
const insightHit = takeFirst(parsed, INSIGHT_KEYS);
if (insightHit) used.add(insightHit.key);
@@ -136,6 +151,7 @@ export const parseAiResult = (text: string): AiResult | null => {
.filter((line) => line.length > 0);
let kesimpulan = kesimpulanHit?.text ?? '';
const akarMasalah = akarMasalahHit?.text ?? '';
let insight = insightHit?.text ?? '';
if (!kesimpulan && leftovers.length > 0) {
@@ -147,10 +163,11 @@ export const parseAiResult = (text: string): AiResult | null => {
insight = [insight, ...leftovers].filter(Boolean).join('\n\n');
}
if (!kesimpulan && !insight) return null;
if (!kesimpulan && !insight && !akarMasalah) return null;
return {
summary: kesimpulan || 'Model tidak mengembalikan ringkasan eksplisit.',
akar_masalah: akarMasalah || undefined,
insight: insight || 'Model tidak mengembalikan rekomendasi eksplisit.',
};
};