Update app.py
Browse files
app.py
CHANGED
|
@@ -312,3 +312,82 @@ def reload_data():
|
|
| 312 |
except Exception as e:
|
| 313 |
raise HTTPException(status_code=500, detail=f"Reload failed: {e}")
|
| 314 |
return {"status": "reloaded"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
except Exception as e:
|
| 313 |
raise HTTPException(status_code=500, detail=f"Reload failed: {e}")
|
| 314 |
return {"status": "reloaded"}
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
# ----------------------------------------------------
|
| 319 |
+
# ENDPOINT 7 — TREN IPS PER ANGKATAN / SEMESTER
|
| 320 |
+
# ----------------------------------------------------
|
| 321 |
+
@app.get("/tren_ips")
|
| 322 |
+
def tren_ips(reload: bool = False):
|
| 323 |
+
if reload:
|
| 324 |
+
load_data_cached.cache_clear()
|
| 325 |
+
|
| 326 |
+
try:
|
| 327 |
+
df = load_data_cached()
|
| 328 |
+
except Exception as e:
|
| 329 |
+
raise HTTPException(500, str(e))
|
| 330 |
+
|
| 331 |
+
final = get_final_records(df)
|
| 332 |
+
final["total_bobot"] = final["sks"] * final["nilai_numerik"]
|
| 333 |
+
|
| 334 |
+
# hitung IPS per (angkatan, semester)
|
| 335 |
+
grouped = final.groupby(["Tahun angkatan", "id_smt"]).agg(
|
| 336 |
+
total_bobot=("total_bobot", "sum"),
|
| 337 |
+
total_sks=("sks", "sum")
|
| 338 |
+
).reset_index()
|
| 339 |
+
|
| 340 |
+
grouped["ips"] = grouped.apply(
|
| 341 |
+
lambda r: (r["total_bobot"] / r["total_sks"]) if r["total_sks"] > 0 else 0.0,
|
| 342 |
+
axis=1
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
result = {}
|
| 346 |
+
for angkatan, d in grouped.groupby("Tahun angkatan"):
|
| 347 |
+
d_sorted = d.sort_values("id_smt")
|
| 348 |
+
result[str(angkatan)] = d_sorted["ips"].round(3).tolist()
|
| 349 |
+
|
| 350 |
+
return result
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
# ----------------------------------------------------
|
| 354 |
+
# ENDPOINT 8 — DISTRIBUSI POPULASI PER ANGKATAN
|
| 355 |
+
# ----------------------------------------------------
|
| 356 |
+
@app.get("/distribusi_populasi")
|
| 357 |
+
def distribusi_populasi(reload: bool = False, min_sks: int = 110):
|
| 358 |
+
if reload:
|
| 359 |
+
load_data_cached.cache_clear()
|
| 360 |
+
|
| 361 |
+
try:
|
| 362 |
+
df = load_data_cached()
|
| 363 |
+
except Exception as e:
|
| 364 |
+
raise HTTPException(500, str(e))
|
| 365 |
+
|
| 366 |
+
final = get_final_records(df)
|
| 367 |
+
|
| 368 |
+
# total mahasiswa per angkatan
|
| 369 |
+
total_mhs = df.groupby("Tahun angkatan")["kode_mhs"].nunique()
|
| 370 |
+
|
| 371 |
+
# eligible per angkatan
|
| 372 |
+
sks_per_mhs = final.groupby("kode_mhs")["sks"].sum()
|
| 373 |
+
eligible = sks_per_mhs[sks_per_mhs > min_sks]
|
| 374 |
+
|
| 375 |
+
angkatan_map = df.set_index("kode_mhs")["Tahun angkatan"].to_dict()
|
| 376 |
+
|
| 377 |
+
eligible_count = {}
|
| 378 |
+
for mhs in eligible.index:
|
| 379 |
+
ang = angkatan_map.get(mhs)
|
| 380 |
+
if ang is not None:
|
| 381 |
+
eligible_count.setdefault(ang, 0)
|
| 382 |
+
eligible_count[ang] += 1
|
| 383 |
+
|
| 384 |
+
# bentuk response
|
| 385 |
+
final_result = {}
|
| 386 |
+
for angkatan in sorted(total_mhs.index):
|
| 387 |
+
final_result[str(angkatan)] = {
|
| 388 |
+
"total": int(total_mhs[angkatan]),
|
| 389 |
+
"eligible": int(eligible_count.get(angkatan, 0))
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
return final_result
|
| 393 |
+
|