LesionDetection / app.py
maregu2023's picture
Fixing three bugs from nnUNetv2 wrapper, such as pacing extraction: (x,y,z) → (z,y,x) to match project convention
5fcd2a4
"""
Hugging Face Spaces entry point for seg_app.
This file must be at repository root for HF Spaces deployment.
IMPORTANT:
- No heavy imports at module level (lazy loading only)
- Model loading happens on first inference, not at startup
- Gradio app is created on import but models are NOT loaded
"""
import os
import logging
import sys
# Fix OpenMP duplicate library error on Windows
# Must be set BEFORE importing numpy/torch
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
# Configure logging before other imports
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
# Validate Python version
if sys.version_info < (3, 8):
logger.error("Python 3.8+ is required")
sys.exit(1)
# =============================================================================
# MONKEY-PATCH: Fix Gradio schema serialization bug
# Bug: gradio_client/utils.py crashes when schema has additionalProperties: true
# because it tries to do `if "const" in schema` on a boolean value.
# This patch adds a guard to handle boolean schemas gracefully.
# =============================================================================
def _patch_gradio_schema_bug():
"""Patch the buggy _json_schema_to_python_type function in gradio_client."""
try:
import gradio_client.utils as client_utils
# Store original function
original_func = client_utils._json_schema_to_python_type
def patched_json_schema_to_python_type(schema, defs=None):
"""Patched version that handles boolean schemas."""
# Handle boolean schema (additionalProperties: true/false)
if isinstance(schema, bool):
return "Any" if schema else "None"
# Handle None schema
if schema is None:
return "Any"
# Call original for normal dict schemas
return original_func(schema, defs)
# Apply patch
client_utils._json_schema_to_python_type = patched_json_schema_to_python_type
logger.info("Applied Gradio schema bug patch")
except Exception as e:
logger.warning(f"Could not patch Gradio schema bug: {e}")
# Apply patch before any Gradio imports
_patch_gradio_schema_bug()
def create_demo():
"""Create and configure the Gradio demo.
This function is called at import time but does NOT load any models.
Models are loaded lazily on first inference via the model registry.
Returns:
Configured Gradio Blocks application
"""
try:
# Import settings and configure
from seg_app.config.settings import (
APP_SETTINGS,
configure_logging,
validate_environment,
is_hf_spaces,
)
# Configure logging based on environment
configure_logging(verbose=not is_hf_spaces())
# Validate environment (warnings only, don't fail startup)
validate_environment()
# Import the Gradio app (models NOT loaded yet)
from seg_app.ui.gradio_app import demo
logger.info("Gradio app created successfully (models will load on first use)")
return demo
except ImportError as e:
logger.error(f"Failed to import required modules: {e}")
logger.error("Please ensure all dependencies are installed: pip install -r requirements.txt")
raise
except Exception as e:
logger.error(f"Failed to create Gradio app: {e}")
raise
# Create the demo at module level (required for HF Spaces)
# This does NOT load models - they are lazy-loaded on first inference
demo = create_demo()
# Launch the app
# HF Spaces runs this file directly with `python app.py`
if __name__ == "__main__":
import os
if os.environ.get("SPACE_ID"):
# Running in HF Spaces
logger.info("Starting seg_app on Hugging Face Spaces...")
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_api=False,
)
else:
# Local development
logger.info("Starting seg_app in local mode...")
demo.launch(
server_name="127.0.0.1",
server_port=7869,
share=False,
)
"""
>> First Launch API server backend: Start the FastAPI backend with uvicorn
# uvicorn seg_app.api.app:app --reload --host 127.0.0.1 --port 8000
uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000
>> Second, Start the FastAPI Frontend:
cd seg_app/ui_slicer
python serve_frontend.py
>> Launch Gradio App for seg_app.
python app.py
# Terminal 1: FastAPI Backend
uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000
# Terminal 2: Frontend Server
cd seg_app/ui_slicer
python serve_frontend.py
Unified Mode (single server — recommended)
One terminal, one port, serves both frontend + backend:
----------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
uvicorn seg_app.backend.api:app --host 127.0.0.1 --port 7860
Split Mode (two terminals — for development)
If you ever need separate frontend/backend (e.g., for hot-reloading the frontend):
Terminal 1 — Backend:
-------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000
Terminal 2 — Frontend:
-------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app/seg_app/ui_slicer
conda activate facenet
python serve_frontend.py
⚠️ In split mode, you'll need to temporarily revert api-client.js to use http://localhost:8000 instead of window.location.origin.
You can test locally with Docker first if you want:
--------------------------
docker build -t brain-seg-app .
docker run -p 7860:7860 brain-seg-app
# Open http://localhost:7860
For future pushes
Whenever you make changes locally and want to update the Space:
--------------------------------------------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
git add -A
git commit -m "your commit message"
git push hf main
"""