face-recognition / main.py
ISHASI's picture
Update main.py
91075e7 verified
Raw History Blame Contribute Delete
6.63 kB
import os
import gc
import time
import shutil
import logging
import psutil
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import JSONResponse
from deepface import DeepFace
# Setup Logging
logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger("AIMonitor")
app = FastAPI()
# ----------------------------------------------------------------------------
# Helper Pengukur RAM
# ----------------------------------------------------------------------------
def get_mem():
ram = psutil.virtual_memory()
proc = psutil.Process(os.getpid())
app_gb = proc.memory_info().rss / (1024 ** 3)
free_gb = ram.available / (1024 ** 3)
return app_gb, free_gb
# Path database lokal (bawaan lama)
DB_PATH = "/app/face_db"
if not os.path.exists(DB_PATH):
os.makedirs(DB_PATH)
# ============================================================================
# MIDDLEWARE RAM TRACKER
# ============================================================================
@app.middleware("http")
async def ram_tracker_middleware(request, call_next):
# Abaikan logging jika hanya healthcheck root "/"
if request.url.path == "/":
return await call_next(request)
start_time = time.time()
ram_awal, free_awal = get_mem()
# Catat log saat request mulai masuk
print("\n" + "-" * 70)
logger.info(f"[HIT MASUK] {request.method} {request.url.path}")
logger.info(f" |-- RAM Awal App : {ram_awal:.2f} GB")
logger.info(f" |-- Sisa RAM Server: {free_awal:.2f} GB")
logger.info(f" |-- Status : Sedang memproses AI...")
# Jalankan kode AI
response = await call_next(request)
# Catat durasi dan bersihkan RAM sementara (Garbage Collector)
duration_ms = (time.time() - start_time) * 1000
ram_proses, _ = get_mem()
gc.collect() # Langsung lepaskan RAM sementara
ram_akhir, free_akhir = get_mem()
# Cetak alur naik dan turunnya RAM
logger.info(f"[SELESAI] Status: {response.status_code} | Durasi: {duration_ms:.0f} ms")
logger.info(
f"[SIKLUS RAM] {ram_awal:.2f} GB --(naik proses)--> {ram_proses:.2f} GB --(turun cooldown)--> {ram_akhir:.2f} GB"
)
logger.info(f"[SISA RAM SERVER] {free_akhir:.2f} GB")
print("-" * 70 + "\n")
return response
# ============================================================================
# CODINGAN MODEL AI
# ============================================================================
@app.get("/")
async def root():
ram_app, ram_free = get_mem()
return {
"status": "AI Face Recognition System is Running",
"app_ram_gb": round(ram_app, 2),
"available_ram_gb": round(ram_free, 2)
}
@app.post("/api/represent")
async def represent_face(
image: UploadFile = File(...),
name: str = Form(None),
detector_backend: str = Form("retinaface")
):
"""Endpoint stateless untuk mengekstrak vektor embedding wajah (512 dimensi untuk Facenet512)"""
temp_path = f"temp_{int(time.time()*1000)}.jpg"
try:
if name:
logger.info(f" |-- Subjek: {name} (detector: {detector_backend})")
# Simpan gambar secara temporer
with open(temp_path, "wb") as buffer:
shutil.copyfileobj(image.file, buffer)
# Hitung representasi vektor wajah
representations = DeepFace.represent(
img_path=temp_path,
model_name="Facenet512",
detector_backend=detector_backend,
enforce_detection=False
)
if len(representations) > 0:
embedding = representations[0]["embedding"]
return {"success": True, "embedding": embedding}
return JSONResponse(status_code=400, content={"success": False, "error": "Wajah tidak dapat dideteksi."})
except Exception as e:
logger.error(f" [ERROR] Error in represent: {str(e)}")
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
finally:
if os.path.exists(temp_path):
os.remove(temp_path)
@app.post("/api/register")
async def register_face(name: str = Form(...), image: UploadFile = File(...)):
try:
clean_name = name.replace(" ", "_").lower()
img_path = os.path.join(DB_PATH, f"{clean_name}.jpg")
with open(img_path, "wb") as buffer:
shutil.copyfileobj(image.file, buffer)
for file in os.listdir(DB_PATH):
if file.endswith(".pkl"):
os.remove(os.path.join(DB_PATH, file))
return {"success": True, "message": f"Wajah {name} berhasil didaftarkan."}
except Exception as e:
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
@app.post("/api/recognize")
async def recognize_face(image: UploadFile = File(...)):
temp_path = f"temp_scan_{int(time.time()*1000)}.jpg"
try:
with open(temp_path, "wb") as buffer:
shutil.copyfileobj(image.file, buffer)
has_images = any(f.lower().endswith(('.jpg', '.jpeg', '.png')) for f in os.listdir(DB_PATH))
if not has_images:
return {"success": False, "name": "Tidak Dikenali"}
dfs = DeepFace.find(
img_path=temp_path,
db_path=DB_PATH,
model_name="VGG-Face",
enforce_detection=False,
silent=True
)
if len(dfs) > 0 and not dfs[0].empty:
result_path = dfs[0]["identity"][0]
name = os.path.basename(result_path).replace(".jpg", "").replace("_", " ").title()
return {"success": True, "name": name}
return {"success": False, "name": "Tidak Dikenali"}
except Exception as e:
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
finally:
if os.path.exists(temp_path):
os.remove(temp_path)
@app.post("/api/reset-ai")
async def reset_ai():
try:
for filename in os.listdir(DB_PATH):
file_path = os.path.join(DB_PATH, filename)
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
return {"success": True, "message": "Database AI lokal dibersihkan."}
except Exception as e:
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})