PixelNavigation commited on
Commit
931edec
·
1 Parent(s): 745b47a

Forced Redirecting pretrained weights to temp/cache

Browse files
Files changed (2) hide show
  1. Dockerfile +27 -21
  2. backend/app.py +39 -33
Dockerfile CHANGED
@@ -1,38 +1,44 @@
1
- # ---------- Stage 1: Build Next.js frontend as static export ----------
2
  FROM node:18 AS frontend-builder
3
  WORKDIR /frontend
4
  COPY frontend/ .
5
- # Install and build
6
  RUN npm install && npm run build
7
 
8
- # ---------- Stage 2: Python backend with Flask + Gunicorn ----------
9
  FROM python:3.10-slim
10
- ENV PYTHONDONTWRITEBYTECODE=1 \
11
- PYTHONUNBUFFERED=1
12
 
13
- # System deps
14
  RUN apt-get update && apt-get install -y --no-install-recommends \
15
- ffmpeg \
16
- && rm -rf /var/lib/apt/lists/*
17
 
18
  WORKDIR /app
19
 
20
- # Copy backend and requirements
21
- COPY backend/ ./backend
22
- COPY backend/requirements.txt ./requirements.txt
23
- RUN pip install --no-cache-dir -r requirements.txt
 
 
 
 
24
 
25
- # Copy exported frontend (Next.js 'out' folder) into Flask static dir
26
- # The Next.js export outputs to frontend/out by default
27
- COPY --from=frontend-builder /frontend/out ./backend/static
28
 
29
- # Expose port used by Hugging Face Spaces (Default is 7860)
30
- EXPOSE 7860
 
 
 
 
31
 
32
- # Environment for Flask
33
- ENV PORT=7860 \
34
- PYTHONPATH=/app
35
 
36
- # Start with gunicorn for production
37
  WORKDIR /app/backend
 
 
 
 
 
38
  CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:7860", "--workers", "2", "--timeout", "180"]
 
1
+ # ---------- Stage 1: Build Next.js / React frontend (adjust if using CRA) ----------
2
  FROM node:18 AS frontend-builder
3
  WORKDIR /frontend
4
  COPY frontend/ .
 
5
  RUN npm install && npm run build
6
 
7
+ # ---------- Stage 2: Backend (Flask + Gunicorn) ----------
8
  FROM python:3.10-slim
 
 
9
 
10
+ # System deps (add more if needed: libgl1 etc. for opencv)
11
  RUN apt-get update && apt-get install -y --no-install-recommends \
12
+ build-essential git wget curl ffmpeg libglib2.0-0 libsm6 libxext6 libxrender1 \
13
+ && rm -rf /var/lib/apt/lists/*
14
 
15
  WORKDIR /app
16
 
17
+ # Writable cache locations to avoid PermissionError: '/.cache'
18
+ ENV HF_HOME=/tmp/.cache/huggingface \
19
+ TORCH_HOME=/tmp/.cache/torch \
20
+ TIMM_CACHE_DIR=/tmp/.cache/timm \
21
+ XDG_CACHE_HOME=/tmp/.cache \
22
+ HF_HUB_CACHE=/tmp/.cache/huggingface \
23
+ TRANSFORMERS_CACHE=/tmp/.cache/huggingface \
24
+ NO_ALBUMENTATIONS_UPDATE=1
25
 
26
+ RUN mkdir -p /tmp/.cache/huggingface /tmp/.cache/torch /tmp/.cache/timm
 
 
27
 
28
+ # Copy backend requirements first for better layer caching
29
+ COPY backend/requirements.txt ./backend/requirements.txt
30
+ RUN pip install --no-cache-dir -r backend/requirements.txt
31
+
32
+ # Copy backend code
33
+ COPY backend/ ./backend
34
 
35
+ # Copy built frontend output into backend static (adjust path if build folder differs)
36
+ COPY --from=frontend-builder /frontend/dist ./backend/static
 
37
 
 
38
  WORKDIR /app/backend
39
+
40
+ # Expose Space port (Hugging Face uses 7860)
41
+ EXPOSE 7860
42
+
43
+ # Start with gunicorn
44
  CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:7860", "--workers", "2", "--timeout", "180"]
backend/app.py CHANGED
@@ -3,51 +3,57 @@ from flask_cors import CORS
3
  from werkzeug.utils import secure_filename
4
  import os
5
  import sys
6
- import torch
7
- import re
8
- import numpy as np
9
- from PIL import Image
10
- import gc
11
  import tempfile
12
  import traceback
 
 
13
 
14
  def _ensure_writable_caches():
15
- """Ensure ML framework caches use writable temp dirs to avoid PermissionError on /.cache."""
16
- tmp = tempfile.gettempdir()
17
- defaults = {
18
- 'HF_HOME': os.path.join(tmp, 'hf_home'),
19
- 'XDG_CACHE_HOME': os.path.join(tmp, '.cache'),
20
- 'TRANSFORMERS_CACHE': os.path.join(tmp, 'hf_home'),
21
- 'TORCH_HOME': os.path.join(tmp, 'torch'),
22
- 'HF_DATASETS_CACHE': os.path.join(tmp, '.cache', 'huggingface', 'datasets'),
23
- 'HF_MODULES_CACHE': os.path.join(tmp, '.cache', 'huggingface', 'modules'),
24
- 'HF_HUB_CACHE': os.path.join(tmp, '.cache', 'huggingface', 'hub'),
25
- 'NO_ALBUMENTATIONS_UPDATE': '1',
26
- 'HF_HUB_OFFLINE': '1', # prevent network downloads during startup
 
 
27
  }
28
- for k, v in defaults.items():
29
- if k not in os.environ:
30
- os.environ[k] = v
31
- # create a subset of directories best-effort
32
- for path in [os.environ.get('HF_HOME'), os.environ.get('XDG_CACHE_HOME'), os.environ.get('TORCH_HOME')]:
33
- try:
34
- if path:
35
- os.makedirs(path, exist_ok=True)
36
- except Exception:
37
- pass
38
 
39
  _ensure_writable_caches()
40
 
41
- # Add the model directory to path and import after cache env is set
42
  sys.path.append('dfdc_model')
43
 
44
- from dfdc_model.kernel_utils import VideoReader, FaceExtractor, confident_strategy, predict_on_video
45
- from dfdc_model.training.zoo.classifiers import DeepFakeClassifier
46
- from enhanced_prediction import enhanced_predict_on_video, enhanced_predict_on_image
 
 
 
 
 
 
47
 
48
- app = Flask(__name__, static_folder='static', static_url_path='')
49
  CORS(app)
50
- # tempfile already imported above
 
 
 
51
 
52
  # Choose an upload folder that is writable in container environments.
53
  # Prefer environment override, then /tmp/uploads, then a tempdir fallback.
 
3
  from werkzeug.utils import secure_filename
4
  import os
5
  import sys
 
 
 
 
 
6
  import tempfile
7
  import traceback
8
+ import logging
9
+ from PIL import Image
10
 
11
  def _ensure_writable_caches():
12
+ """
13
+ Redirect all model / hub caches to writable tmp directories to avoid
14
+ PermissionError inside container (e.g. attempts to write to '/.cache').
15
+ Safe to call multiple times.
16
+ """
17
+ tmp_root = os.environ.get("TMPDIR") or tempfile.gettempdir()
18
+ base_cache = os.path.join(tmp_root, ".cache")
19
+ subdirs = {
20
+ "HF_HOME": "huggingface",
21
+ "HF_HUB_CACHE": "huggingface",
22
+ "TRANSFORMERS_CACHE": "huggingface",
23
+ "TORCH_HOME": "torch",
24
+ "TIMM_CACHE_DIR": "timm",
25
+ "XDG_CACHE_HOME": "", # root of the cache tree
26
  }
27
+ for var, sub in subdirs.items():
28
+ path = os.environ.get(var)
29
+ if not path:
30
+ path = os.path.join(base_cache, sub) if sub else base_cache
31
+ os.environ[var] = path
32
+ os.makedirs(path, exist_ok=True)
33
+ # Quiet albumentations update check noise
34
+ os.environ.setdefault("NO_ALBUMENTATIONS_UPDATE", "1")
 
 
35
 
36
  _ensure_writable_caches()
37
 
38
+ # Add model directory before importing model utilities
39
  sys.path.append('dfdc_model')
40
 
41
+ try:
42
+ from dfdc_model.kernel_utils import VideoReader, FaceExtractor, confident_strategy, predict_on_video
43
+ from dfdc_model.training.zoo.classifiers import DeepFakeClassifier
44
+ except Exception as e:
45
+ traceback.print_exc()
46
+ with open(os.path.join(tempfile.gettempdir(), "startup_error.log"), "w", encoding="utf-8") as f:
47
+ f.write(traceback.format_exc())
48
+ VideoReader = FaceExtractor = confident_strategy = predict_on_video = None
49
+ DeepFakeClassifier = None
50
 
51
+ app = Flask(__name__)
52
  CORS(app)
53
+
54
+ # Choose a writable upload folder
55
+ app.config["UPLOAD_FOLDER"] = os.environ.get("UPLOAD_FOLDER") or os.path.join(tempfile.gettempdir(), "uploads")
56
+ os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
57
 
58
  # Choose an upload folder that is writable in container environments.
59
  # Prefer environment override, then /tmp/uploads, then a tempdir fallback.