Files
dashboard-cpsp/backend/apps/operations/tests_insight_grading.py
T

136 lines
5.3 KiB
Python

"""Regression: dashboard field names must grade; prompt must not invent ids/names."""
from django.test import SimpleTestCase
from apps.operations.services import cp707_knowledge as cp707
from apps.operations.services.insight_service import (
ANTI_HALLUCINATION_RULES,
build_insight_user_prompt,
enforce_mortality_wording,
grade_context,
)
class ResolveDashboardFieldsTests(SimpleTestCase):
def test_resolve_bw_from_bobot_avg_gram(self):
self.assertEqual(cp707._resolve_bw_grams({"bobot_avg_gram": 2100}), 2100.0)
def test_resolve_bw_from_average_weight(self):
self.assertEqual(cp707._resolve_bw_grams({"averageWeight": 1950}), 1950.0)
def test_resolve_mortality_from_mortalitas_kumulatif_persen(self):
self.assertEqual(
cp707._resolve_mortality({"mortalitas_kumulatif_persen": 2.4}),
2.4,
)
def test_resolve_mortality_from_persen_hidup(self):
self.assertAlmostEqual(
cp707._resolve_mortality({"persen_hidup": 97.5}),
2.5,
)
def test_resolve_mortality_from_deaths_over_doc(self):
self.assertAlmostEqual(
cp707._resolve_mortality(
{"kematian_kumulatif_ekor": 50, "doc_in_ekor": 10000}
),
0.5,
)
def test_dashboard_shaped_context_grades_bw_and_mortality(self):
"""Reproduce Kandang 2 day-48 payload: FCR present, BW/mort via dashboard keys."""
ctx = {
"hari_ke": 48,
"fcr_terakhir": 1.71,
"bobot_avg_gram": 2100,
"persen_hidup": 98.0,
"mortalitas_hari_ini_ekor": 0,
"kematian_kumulatif_ekor": 200,
"doc_in_ekor": 10000,
}
graded = grade_context(ctx)
analyses = graded["analyses"]
self.assertIn("fcr", analyses)
self.assertIn("bw", analyses)
self.assertIn("mortality", analyses)
self.assertEqual(analyses["bw"]["actual"], 2100.0)
self.assertEqual(analyses["mortality"]["status"], "ok")
self.assertIn("2.00%", analyses["mortality"]["message"])
self.assertEqual(graded.get("mortalitas_hari_ini_ekor"), 0)
class MissingMetricsGradedAsUnknownTests(SimpleTestCase):
def test_missing_bw_and_mortality_emit_unknown_not_silent(self):
"""When fields are absent, graded facts must say unknown so the LLM cannot use standards as actuals."""
ctx = {"hari_ke": 48, "fcr_terakhir": 1.71}
graded = grade_context(ctx)
self.assertEqual(graded["analyses"]["bw"]["status"], "unknown")
self.assertEqual(graded["analyses"]["mortality"]["status"], "unknown")
self.assertIn("tidak tersedia", graded["analyses"]["bw"]["message"].lower())
class InsightPromptNamingTests(SimpleTestCase):
def test_user_prompt_uses_name_without_kandang_prefix_or_id(self):
prompt = build_insight_user_prompt(
topic="dashboard",
kandang_name="Kandang 2",
report_type="page",
report_period="current",
context={"hari_ke": 48, "kandangId": 6, "cycleId": 99},
)
self.assertIn("untuk `Kandang 2`", prompt)
self.assertNotIn("untuk kandang `Kandang 2`", prompt)
self.assertNotIn("id=", prompt)
self.assertNotIn('"kandangId"', prompt)
self.assertNotIn('"cycleId"', prompt)
def test_anti_hallucination_forbids_standard_as_actual_and_confusing_today_mortality(self):
rules = ANTI_HALLUCINATION_RULES.lower()
self.assertIn("standar", rules)
self.assertIn("bukan nilai aktual", rules)
self.assertIn("mortalitas_hari_ini", rules)
self.assertIn("jangan menyebut id", rules)
self.assertIn("severity_label", rules)
class MortalityWordingConsistencyTests(SimpleTestCase):
def test_critical_mortality_has_explicit_severity_label(self):
result = cp707.analyze_mortality(9.49, 48)
self.assertEqual(result["status"], "critical")
self.assertEqual(result["severity_label"], "SANGAT TINGGI")
self.assertEqual(result["actual_pct"], 9.49)
self.assertIn("rendah", result["dilarang_kata"])
def test_enforce_rewrites_rendah_when_mortality_is_critical(self):
graded = {
"analyses": {
"mortality": cp707.analyze_mortality(9.49, 48),
}
}
parsed = {
"kesimpulan": (
"Kandang 1 menunjukkan mortalitas kumulatif yang rendah pada hari ke-48, "
"mencapai 9.49%, melebihi batas kritis CP707 (>7%)."
),
"insight": "Lakukan nekropsi darurat.",
}
fixed = enforce_mortality_wording(parsed, graded)
text = f"{fixed['kesimpulan']} {fixed['insight']}".lower()
self.assertNotIn("rendah", text)
self.assertIn("sangat tinggi", text)
self.assertIn("9.49", fixed["kesimpulan"])
def test_enforce_leaves_ok_mortality_narrative_alone(self):
graded = {
"analyses": {
"mortality": cp707.analyze_mortality(2.1, 20),
}
}
parsed = {
"kesimpulan": "Mortalitas kumulatif rendah (2.10%), masih dalam batas normal.",
"insight": "Pertahankan biosekuriti.",
}
fixed = enforce_mortality_wording(parsed, graded)
self.assertEqual(fixed["kesimpulan"], parsed["kesimpulan"])