Prathamesh Sarjerao Vaidya commited on
Commit
2dc4e60
Β·
1 Parent(s): e501ce8

made changes

Browse files
Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
  # Multi-stage Dockerfile for Dance Movement Analyzer
2
- # Optimized for Hugging Face Spaces
3
 
4
  # Stage 1: Base image with dependencies
5
  FROM python:3.10-slim as base
@@ -30,18 +30,35 @@ WORKDIR /app
30
  FROM base as dependencies
31
 
32
  # Copy requirements first for better caching
33
- COPY requirements.txt .
34
 
35
  # Install Python dependencies
36
  RUN pip install --no-cache-dir -r requirements.txt
37
 
38
- # Pre-download MediaPipe models to speed up first run
39
- RUN python -c "import mediapipe as mp; pose = mp.solutions.pose.Pose(); pose.close()" || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  # Stage 3: Production image
42
  FROM base as production
43
 
44
- # Copy installed packages from dependencies stage
45
  COPY --from=dependencies /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
46
  COPY --from=dependencies /usr/local/bin /usr/local/bin
47
 
@@ -60,25 +77,23 @@ COPY startup.sh /app/startup.sh
60
  # Make startup script executable
61
  RUN chmod +x /app/startup.sh
62
 
63
- # Set permissions
64
  RUN chmod -R 755 /app
65
 
66
  # Create non-root user for security
67
  RUN useradd -m -u 1000 appuser && \
68
  chown -R appuser:appuser /app
69
 
 
70
  USER appuser
71
 
72
- # Expose port (7860 for Hugging Face, 8000 for local)
73
  EXPOSE 8000
74
  EXPOSE 7860
75
 
76
- # ⬇️ OPTION B: HEALTHCHECK GOES HERE ⬇️
77
- # Health check with 5 minute startup period (for model loading)
78
- # This allows the container up to 5 minutes to start before health checks begin
79
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
80
  CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1
81
- # ⬆️ HEALTHCHECK ENDS HERE ⬆️
82
 
83
  # Run the application using startup script
84
  CMD ["/app/startup.sh"]
 
1
  # Multi-stage Dockerfile for Dance Movement Analyzer
2
+ # Optimized for Hugging Face Spaces with MediaPipe model pre-download
3
 
4
  # Stage 1: Base image with dependencies
5
  FROM python:3.10-slim as base
 
30
  FROM base as dependencies
31
 
32
  # Copy requirements first for better caching
33
+ COPY backend/requirements.txt .
34
 
35
  # Install Python dependencies
36
  RUN pip install --no-cache-dir -r requirements.txt
37
 
38
+ # Pre-download ALL MediaPipe models (as root before user switch)
39
+ # This downloads the models to the pip packages directory
40
+ RUN python3 -c "\
41
+ import mediapipe as mp; \
42
+ print('Downloading MediaPipe Pose models...'); \
43
+ # Model complexity 0 (Lite) \
44
+ pose0 = mp.solutions.pose.Pose(model_complexity=0, min_detection_confidence=0.5); \
45
+ pose0.close(); \
46
+ print('βœ… Lite model downloaded'); \
47
+ # Model complexity 1 (Full) \
48
+ pose1 = mp.solutions.pose.Pose(model_complexity=1, min_detection_confidence=0.5); \
49
+ pose1.close(); \
50
+ print('βœ… Full model downloaded'); \
51
+ # Model complexity 2 (Heavy) \
52
+ pose2 = mp.solutions.pose.Pose(model_complexity=2, min_detection_confidence=0.5); \
53
+ pose2.close(); \
54
+ print('βœ… Heavy model downloaded'); \
55
+ print('βœ… All MediaPipe models pre-downloaded successfully'); \
56
+ "
57
 
58
  # Stage 3: Production image
59
  FROM base as production
60
 
61
+ # Copy installed packages from dependencies stage (includes downloaded models)
62
  COPY --from=dependencies /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
63
  COPY --from=dependencies /usr/local/bin /usr/local/bin
64
 
 
77
  # Make startup script executable
78
  RUN chmod +x /app/startup.sh
79
 
80
+ # Set permissions for all app files
81
  RUN chmod -R 755 /app
82
 
83
  # Create non-root user for security
84
  RUN useradd -m -u 1000 appuser && \
85
  chown -R appuser:appuser /app
86
 
87
+ # Switch to non-root user
88
  USER appuser
89
 
90
+ # Expose ports (7860 for Hugging Face, 8000 for local)
91
  EXPOSE 8000
92
  EXPOSE 7860
93
 
94
+ # Health check with 5 minute startup period
 
 
95
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
96
  CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1
 
97
 
98
  # Run the application using startup script
99
  CMD ["/app/startup.sh"]
backend/app/main.py CHANGED
@@ -34,7 +34,7 @@ global_processor: Optional[VideoProcessor] = None
34
 
35
  @asynccontextmanager
36
  async def lifespan(app: FastAPI):
37
- """Lifespan event handler for startup and shutdown"""
38
  global global_processor
39
 
40
  # Startup
@@ -44,17 +44,25 @@ async def lifespan(app: FastAPI):
44
  Config.initialize_folders()
45
  logger.info("βœ… Folders initialized")
46
 
47
- # Pre-initialize VideoProcessor to load MediaPipe models
48
- logger.info("πŸ“¦ Loading MediaPipe models...")
49
- global_processor = VideoProcessor()
50
- logger.info("βœ… MediaPipe models loaded successfully")
 
 
 
 
 
51
 
52
  logger.info("πŸŽ‰ Application startup complete!")
53
 
54
  yield
55
 
56
- # Shutdown (cleanup if needed)
57
  logger.info("πŸ‘‹ Shutting down application...")
 
 
 
58
 
59
  # Initialize FastAPI app with lifespan
60
  app = FastAPI(
 
34
 
35
  @asynccontextmanager
36
  async def lifespan(app: FastAPI):
37
+ """Lifespan event handler - models already downloaded in Docker build"""
38
  global global_processor
39
 
40
  # Startup
 
44
  Config.initialize_folders()
45
  logger.info("βœ… Folders initialized")
46
 
47
+ # Initialize VideoProcessor (models already downloaded, just instantiate)
48
+ logger.info("πŸ“¦ Initializing Video Processor...")
49
+ try:
50
+ global_processor = VideoProcessor()
51
+ logger.info("βœ… Video Processor initialized successfully")
52
+ except Exception as e:
53
+ logger.error(f"❌ Error initializing Video Processor: {e}")
54
+ # Continue anyway - will retry on first request
55
+ global_processor = None
56
 
57
  logger.info("πŸŽ‰ Application startup complete!")
58
 
59
  yield
60
 
61
+ # Shutdown
62
  logger.info("πŸ‘‹ Shutting down application...")
63
+ if global_processor is not None:
64
+ # Cleanup if needed
65
+ pass
66
 
67
  # Initialize FastAPI app with lifespan
68
  app = FastAPI(
requirements.txt β†’ backend/requirements.txt RENAMED
File without changes
startup.sh CHANGED
@@ -3,32 +3,42 @@ set -e
3
 
4
  echo "πŸš€ Starting Dance Movement Analyzer..."
5
 
6
- # Pre-warm MediaPipe models
7
- echo "πŸ“¦ Pre-loading MediaPipe models..."
8
  python3 -c "
9
  import mediapipe as mp
10
  import logging
 
 
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
13
 
14
  try:
15
- logger.info('Loading Pose model...')
16
- pose = mp.solutions.pose.Pose(
17
- static_image_mode=False,
18
- model_complexity=1,
19
- min_detection_confidence=0.5,
20
- min_tracking_confidence=0.5
21
- )
22
- pose.close()
23
- logger.info('βœ… Models loaded successfully')
 
 
 
 
 
24
  except Exception as e:
25
- logger.error(f'❌ Error loading models: {e}')
26
- # Continue anyway - models will load on first use
27
- " || echo "⚠️ Model pre-loading failed, will load on first use"
28
 
29
  # Detect port (Hugging Face uses 7860, local uses 8000)
30
  PORT=${PORT:-8000}
31
 
32
- # Start the application
33
  echo "🎬 Starting Uvicorn server on port $PORT..."
34
- exec uvicorn app.main:app --host 0.0.0.0 --port $PORT --workers 1
 
 
 
 
 
3
 
4
  echo "πŸš€ Starting Dance Movement Analyzer..."
5
 
6
+ # Verify MediaPipe models are available
7
+ echo "πŸ“¦ Verifying MediaPipe models..."
8
  python3 -c "
9
  import mediapipe as mp
10
  import logging
11
+ import os
12
+
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger(__name__)
15
 
16
  try:
17
+ # Quick verification that models are accessible
18
+ logger.info('Checking MediaPipe installation...')
19
+
20
+ # Verify model files exist
21
+ model_path = '/usr/local/lib/python3.10/site-packages/mediapipe/modules/pose_landmark'
22
+ if os.path.exists(model_path):
23
+ logger.info(f'βœ… Model directory found: {model_path}')
24
+ model_files = os.listdir(model_path)
25
+ logger.info(f'Available models: {len(model_files)} files')
26
+ else:
27
+ logger.warning('⚠️ Model directory not found, models will load on first use')
28
+
29
+ logger.info('βœ… MediaPipe ready')
30
+
31
  except Exception as e:
32
+ logger.error(f'❌ Error verifying models: {e}')
33
+ # Continue anyway - application will handle it
34
+ "
35
 
36
  # Detect port (Hugging Face uses 7860, local uses 8000)
37
  PORT=${PORT:-8000}
38
 
 
39
  echo "🎬 Starting Uvicorn server on port $PORT..."
40
+ echo "πŸ“ Application will be available at http://0.0.0.0:$PORT"
41
+ echo ""
42
+
43
+ # Start the application
44
+ exec uvicorn app.main:app --host 0.0.0.0 --port $PORT --workers 1 --log-level info