| | from config import CLASS_NAMES |
| | import os, logging, numpy as np, asyncio |
| | from fastapi import FastAPI |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from contextlib import asynccontextmanager |
| | from huggingface_hub import hf_hub_download |
| | import gradio as gr |
| | from PIL import Image |
| |
|
| | from api.v1 import router as v1_router |
| | from models.model_loader import load_skin_condition_model |
| | from utils.predictor import predict_skin_condition |
| |
|
| | |
| | logging.basicConfig( |
| | level=logging.INFO, |
| | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| | ) |
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0" |
| |
|
| | @asynccontextmanager |
| | async def lifespan(app: FastAPI): |
| | try: |
| | |
| | cache_dir = os.environ.get("HF_HOME", "/tmp/huggingface") |
| | |
| | logger.info(f"Downloading model from Hugging Face Hub using cache_dir: {cache_dir}...") |
| | model_path = hf_hub_download( |
| | repo_id="yasyn14/skin-analyzer", |
| | filename="model-v1.keras", |
| | cache_dir=cache_dir |
| | ) |
| | |
| | logger.info(f"Loading model from path: {model_path}") |
| | model = await asyncio.to_thread(load_skin_condition_model, model_path) |
| | |
| | |
| | dummy = np.zeros((1, 224, 224, 3), dtype=np.uint8) |
| | await asyncio.to_thread(model.predict, dummy) |
| | |
| | app.state.model = model |
| | logger.info("Model ready ✅") |
| | yield |
| | |
| | except Exception as e: |
| | logger.exception("Failed during startup:") |
| | raise RuntimeError("Failed to load skin-condition model") from e |
| | |
| | finally: |
| | logger.info("Shutting down: releasing resources") |
| | if hasattr(app.state, "model"): |
| | del app.state.model |
| |
|
| | |
| | app = FastAPI( |
| | lifespan=lifespan, |
| | title="Skin Condition Classifier API", |
| | description="Upload skin images to detect skin conditions using AI", |
| | version="1.0.0", |
| | ) |
| |
|
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | @app.get("/healthz", tags=["Health"]) |
| | async def health_check(): |
| | return {"status": "ok"} |
| |
|
| | |
| | app.include_router(v1_router) |
| |
|
| | |
| | def predict_skin_condition_grad(image: Image.Image): |
| | if image is None: |
| | return "No image provided" |
| | |
| | if not hasattr(app.state, "model"): |
| | return "Model is not loaded yet. Please try again in a moment." |
| | |
| | model = app.state.model |
| | |
| | |
| | img = image.resize((224, 224)).convert("RGB") |
| | img_array = np.array(img) |
| | |
| | |
| | prediction = predict_skin_condition(img_array, model) |
| | |
| | confidence = prediction.get("confidence") |
| | label = prediction.get("condition") |
| | |
| | return f"{label} ({confidence:.2%} confidence)" |
| |
|
| | gradio_interface = gr.Interface( |
| | fn=predict_skin_condition_grad, |
| | inputs=gr.Image( |
| | type="pil", |
| | label="Upload or capture a skin image", |
| | sources=["upload", "webcam"], |
| | webcam_options={"facingMode": "environment"} |
| | ), |
| | outputs=gr.Text(label="Prediction"), |
| | title="Skin Analyzer", |
| | description="Upload a photo or use your camera to detect skin conditions like acne, eczema, dryness, etc.", |
| | examples=[ |
| | |
| | |
| | |
| | ], |
| | allow_flagging="never" |
| | ) |
| |
|
| | |
| | app = gr.mount_gradio_app(app, gradio_interface, path="") |