update ai insight migration for all page
This commit is contained in:
1 parent
07d36081ce
commit
18790ab8f6
69 files changed
+9457
-399
No files matched your search
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Environment standards from the CP 707 book, for client-side charting only.
|
||||
*
|
||||
* Mirrors temperature / air-quality tables in
|
||||
* `backend/apps/operations/services/cp707_knowledge.py` — that Python module
|
||||
* is authoritative for LLM grading. This TS copy exists so IoT charts can
|
||||
* draw targets without a round trip. Keep both in sync when the book edition
|
||||
* changes.
|
||||
*/
|
||||
|
||||
/** Target suhu pemeliharaan per umur (buku CP 707). */
|
||||
const TEMPERATURE_STANDARD = [
|
||||
{ from: 1, to: 2, temp_C: 32 },
|
||||
{ from: 3, to: 4, temp_C: 31 },
|
||||
{ from: 5, to: 7, temp_C: 30 },
|
||||
{ from: 8, to: 14, temp_C: 29 },
|
||||
{ from: 15, to: 21, temp_C: 28 },
|
||||
{ from: 22, to: 28, temp_C: 26 },
|
||||
{ from: 29, to: 35, temp_C: 23 },
|
||||
{ from: 36, to: 99, temp_C: 22 },
|
||||
];
|
||||
|
||||
/** Kelembapan ideal sama untuk semua umur menurut tabel buku: 50–70 %. */
|
||||
export const HUMIDITY_RANGE_PCT = { min: 50, max: 70 };
|
||||
|
||||
/** Standar kualitas udara (Lampiran 3). */
|
||||
export const AIR_QUALITY = {
|
||||
/** Amonia: ideal <10 ppm, batas kritis >25 ppm. */
|
||||
ammoniaSafe_ppm: 10,
|
||||
ammoniaCritical_ppm: 25,
|
||||
/** CO2: ideal <3000 ppm, kritis >3500 ppm. */
|
||||
co2Ideal_ppm: 3000,
|
||||
};
|
||||
|
||||
/**
|
||||
* Standar konsumsi air per 1000 ekor per hari pada suhu 21°C (buku CP 707).
|
||||
* Di atas 21°C kebutuhan naik rata-rata 6.5% per derajat.
|
||||
*/
|
||||
const WATER_CONSUMPTION_STANDARD: { week: number; minLiter: number; maxLiter: number }[] = [
|
||||
{ week: 1, minLiter: 58, maxLiter: 65 },
|
||||
{ week: 2, minLiter: 102, maxLiter: 115 },
|
||||
{ week: 3, minLiter: 149, maxLiter: 167 },
|
||||
{ week: 4, minLiter: 192, maxLiter: 216 },
|
||||
{ week: 5, minLiter: 232, maxLiter: 261 },
|
||||
{ week: 6, minLiter: 274, maxLiter: 308 },
|
||||
{ week: 7, minLiter: 309, maxLiter: 347 },
|
||||
{ week: 8, minLiter: 342, maxLiter: 385 },
|
||||
];
|
||||
|
||||
/** Standar konsumsi air (rata-rata min–max) untuk umur hari tertentu, atau null. */
|
||||
export const getWaterStandardByDay = (
|
||||
dayAge: number | null | undefined
|
||||
): { min: number; max: number } | null => {
|
||||
if (typeof dayAge !== 'number' || !Number.isFinite(dayAge) || dayAge <= 0) return null;
|
||||
const week = Math.min(Math.ceil(dayAge / 7), WATER_CONSUMPTION_STANDARD.length);
|
||||
const row = WATER_CONSUMPTION_STANDARD.find((r) => r.week === week);
|
||||
return row ? { min: row.minLiter, max: row.maxLiter } : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Suhu target untuk umur tertentu, atau null bila umurnya tidak masuk akal.
|
||||
* Umur di luar tabel jatuh ke baris terakhir (36+ hari), sesuai isi buku.
|
||||
*/
|
||||
export const getTempStandardByDay = (dayAge: number | null | undefined): number | null => {
|
||||
if (typeof dayAge !== 'number' || !Number.isFinite(dayAge) || dayAge <= 0) return null;
|
||||
const row = TEMPERATURE_STANDARD.find((r) => dayAge >= r.from && dayAge <= r.to);
|
||||
return row ? row.temp_C : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Number out of a display-formatted reading.
|
||||
*
|
||||
* `computeDashboard` hands back strings like "32,1 °C" and "62,8 %" — already
|
||||
* scaled from the raw sensor encoding, which is why they are the safe source —
|
||||
* so the chart has to strip the unit and accept the Indonesian decimal comma.
|
||||
* A plain number passes through unchanged.
|
||||
*/
|
||||
export const parseReading = (value: unknown): number | null => {
|
||||
if (typeof value === 'number') return Number.isFinite(value) ? value : null;
|
||||
if (typeof value !== 'string' || value.trim() === '') return null;
|
||||
const cleaned = value
|
||||
.replace(/[^\d,.-]/g, '')
|
||||
.replace(/\.(?=\d{3}\b)/g, '')
|
||||
.replace(',', '.');
|
||||
const n = Number(cleaned);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
};
|
||||
Reference in new issue
Block a user