This commit is contained in:
mhilya 2026-07-13 11:34:04 +07:00
commit 15fa7e2acb
4 changed files with 105 additions and 11 deletions

View File

@ -23,9 +23,13 @@ from filelock import FileLock, Timeout
# ────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).parent.parent BASE_DIR = Path(__file__).parent.parent
ML_DIR = BASE_DIR / "ml_assets" ML_DIR = BASE_DIR / "ml_assets"
DATA_DIR = BASE_DIR.parent / "data"
KETERANGAN_PATH = DATA_DIR / "keterangan_ts_kemendiktisaintek.csv"
COORDS_PATH = DATA_DIR / "kabupaten_coords.json"
PIPELINE_PATH = ML_DIR / "ml_pipeline_internal.pkl" PIPELINE_PATH = ML_DIR / "ml_pipeline_internal.pkl"
STATUS_PATH = ML_DIR / "retrain_status.json" STATUS_PATH = ML_DIR / "retrain_status.json"
LOCK_PATH = ML_DIR / "retrain_status.lock" LOCK_PATH = ML_DIR / "retrain_status.lock"
METRICS_PATH = ML_DIR / "metrics_internal_only.json"
RETRAIN_WORKER = Path(__file__).parent / "retrain_worker.py" RETRAIN_WORKER = Path(__file__).parent / "retrain_worker.py"
TEMP_DIR = ML_DIR / "tmp" TEMP_DIR = ML_DIR / "tmp"
TEMP_DIR.mkdir(parents=True, exist_ok=True) TEMP_DIR.mkdir(parents=True, exist_ok=True)
@ -237,6 +241,40 @@ def retrain_status():
except Exception: except Exception:
return JSONResponse(content={"stage": "unknown", "message": "Status tidak terbaca."}) return JSONResponse(content={"stage": "unknown", "message": "Status tidak terbaca."})
@app.get("/api/v1/metrics/internal", dependencies=[Depends(verify_token)])
def get_internal_metrics():
if not METRICS_PATH.exists():
return JSONResponse(status_code=404, content={"status": "error", "message": "Metrics file not found"})
try:
data = json.loads(METRICS_PATH.read_text(encoding="utf-8"))
return JSONResponse(content=data)
except Exception as e:
logger.error(f"Failed to read metrics: {e}")
return JSONResponse(status_code=500, content={"status": "error", "message": "Failed to read metrics"})
from fastapi.responses import Response
@app.get("/api/v1/data/keterangan", dependencies=[Depends(verify_token)])
def get_keterangan_csv():
if not KETERANGAN_PATH.exists():
return JSONResponse(status_code=404, content={"status": "error", "message": "CSV file not found"})
try:
return Response(content=KETERANGAN_PATH.read_bytes(), media_type="text/csv")
except Exception as e:
logger.error(f"Failed to read CSV: {e}")
return JSONResponse(status_code=500, content={"status": "error", "message": "Failed to read CSV"})
@app.get("/api/v1/data/kabupaten_coords", dependencies=[Depends(verify_token)])
def get_coords_json():
if not COORDS_PATH.exists():
return JSONResponse(status_code=404, content={"status": "error", "message": "Coords file not found"})
try:
data = json.loads(COORDS_PATH.read_text(encoding="utf-8"))
return JSONResponse(content=data)
except Exception as e:
logger.error(f"Failed to read coords: {e}")
return JSONResponse(status_code=500, content={"status": "error", "message": "Failed to read coords"})
@app.post("/api/v1/retrain/reload", dependencies=[Depends(verify_token)]) @app.post("/api/v1/retrain/reload", dependencies=[Depends(verify_token)])
def reload_model(): def reload_model():

View File

@ -101,11 +101,7 @@ public function index(Request $request)
'map_lokasi' => $chartLokasi, 'map_lokasi' => $chartLokasi,
]; ];
$metricsPath = base_path('../fastapi/ml_assets/metrics_internal_only.json'); $mlMetrics = app(\App\Services\FastApiWorkerService::class)->getInternalMetrics();
$mlMetrics = null;
if (file_exists($metricsPath)) {
$mlMetrics = json_decode(file_get_contents($metricsPath), true);
}
$manualOverrideCount = ClassificationResult::where('source_type', 'internal_mif') $manualOverrideCount = ClassificationResult::where('source_type', 'internal_mif')
->where('status', 'manual_override') ->where('status', 'manual_override')

View File

@ -14,16 +14,20 @@ public function index()
'total_kemendik' => KemendikRawData::count(), 'total_kemendik' => KemendikRawData::count(),
]; ];
$keteranganPath = base_path('../data/keterangan_ts_kemendiktisaintek.csv');
$keterangan = []; $keterangan = [];
if (file_exists($keteranganPath)) { $csvText = app(\App\Services\FastApiWorkerService::class)->getKemendikKeteranganCsv();
$lines = file($keteranganPath);
if ($csvText) {
$lines = explode("\n", trim($csvText));
if (count($lines) > 0) { if (count($lines) > 0) {
$rawHeaders = str_getcsv(trim($lines[0]), ';'); $rawHeaders = str_getcsv(trim($lines[0]), ';');
$headers = array_map('trim', $rawHeaders); $headers = array_map('trim', $rawHeaders);
for ($i = 1; $i < count($lines); $i++) { for ($i = 1; $i < count($lines); $i++) {
$row = str_getcsv(trim($lines[$i]), ';'); $rowStr = trim($lines[$i]);
if ($rowStr === '') continue;
$row = str_getcsv($rowStr, ';');
foreach ($headers as $index => $header) { foreach ($headers as $index => $header) {
$val = trim($row[$index] ?? ''); $val = trim($row[$index] ?? '');
if ($val !== '') { if ($val !== '') {
@ -75,8 +79,7 @@ public function index()
}, ['< 2 Juta' => 0, '2 - 4 Juta' => 0, '4 - 6 Juta' => 0, '> 6 Juta' => 0]); }, ['< 2 Juta' => 0, '2 - 4 Juta' => 0, '4 - 6 Juta' => 0, '> 6 Juta' => 0]);
$chartPendapatan = array_filter($chartPendapatan); $chartPendapatan = array_filter($chartPendapatan);
$coordsPath = base_path('../data/kabupaten_coords.json'); $kabupatenCoords = app(\App\Services\FastApiWorkerService::class)->getKabupatenCoords() ?? [];
$kabupatenCoords = file_exists($coordsPath) ? json_decode(file_get_contents($coordsPath), true) : [];
$charts = [ $charts = [
'status' => collect($statusCounts), 'status' => collect($statusCounts),

View File

@ -172,4 +172,61 @@ public function reloadModel(): array
return ['error' => "Kesalahan sistem internal: {$e->getMessage()}"]; return ['error' => "Kesalahan sistem internal: {$e->getMessage()}"];
} }
} }
/**
* Ambil data metrics internal ML dari FastAPI
*/
public function getInternalMetrics(): ?array
{
try {
$response = $this->getClient(5)->get($this->baseUrl . '/api/v1/metrics/internal');
if ($response->successful()) {
return $response->json();
}
if ($response->status() !== 404) {
Log::warning("FastAPI Metrics Error: HTTP {$response->status()} | {$response->body()}");
}
return null;
} catch (ConnectionException $e) {
Log::warning("FastAPI Metrics Connection Error: {$e->getMessage()}");
return null;
} catch (\Exception $e) {
Log::error("FastAPI Metrics System Error: {$e->getMessage()}");
return null;
}
}
/**
* Ambil data CSV keterangan Kemendikbud dari FastAPI
*/
public function getKemendikKeteranganCsv(): ?string
{
try {
$response = $this->getClient(5)->get($this->baseUrl . '/api/v1/data/keterangan');
if ($response->successful()) {
return $response->body();
}
return null;
} catch (\Exception $e) {
return null;
}
}
/**
* Ambil data JSON koordinat kabupaten dari FastAPI
*/
public function getKabupatenCoords(): ?array
{
try {
$response = $this->getClient(5)->get($this->baseUrl . '/api/v1/data/kabupaten_coords');
if ($response->successful()) {
return $response->json();
}
return null;
} catch (\Exception $e) {
return null;
}
}
} }