Rthur2003 commited on
Commit
c1db98e
·
1 Parent(s): 129f521

feat: add startup script for model downloads and upload script for Hugging Face Hub

Browse files
Files changed (3) hide show
  1. Dockerfile +13 -6
  2. startup.py +141 -0
  3. upload_models_to_hub.py +97 -0
Dockerfile CHANGED
@@ -37,10 +37,15 @@ COPY requirements.txt .
37
 
38
  # PyTorch CPU versiyonu + diğer paketler
39
  RUN pip install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu \
40
- && pip install --no-cache-dir -r requirements.txt
 
41
 
42
  # Uygulama kodu
43
  COPY app ./app
 
 
 
 
44
 
45
  # Hugging Face Spaces için non-root kullanıcı (güvenlik)
46
  RUN useradd -m -u 1000 user \
@@ -48,14 +53,16 @@ RUN useradd -m -u 1000 user \
48
  USER user
49
 
50
  ENV HOME=/home/user \
51
- PATH=/home/user/.local/bin:$PATH
 
 
52
 
53
  # Hugging Face Spaces varsayılan port: 7860
54
  EXPOSE 7860
55
 
56
- # Health check
57
- HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
58
  CMD curl -f http://localhost:7860/api/health || exit 1
59
 
60
- # Başlat
61
- CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
 
37
 
38
  # PyTorch CPU versiyonu + diğer paketler
39
  RUN pip install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu \
40
+ && pip install --no-cache-dir -r requirements.txt \
41
+ && pip install --no-cache-dir "huggingface-hub>=0.20.0"
42
 
43
  # Uygulama kodu
44
  COPY app ./app
45
+ COPY startup.py .
46
+
47
+ # Models dizini — startup.py çalışınca doldurulacak
48
+ RUN mkdir -p /app/models
49
 
50
  # Hugging Face Spaces için non-root kullanıcı (güvenlik)
51
  RUN useradd -m -u 1000 user \
 
53
  USER user
54
 
55
  ENV HOME=/home/user \
56
+ PATH=/home/user/.local/bin:$PATH \
57
+ AURIS_MODELS_REPO=Rtur2003/auris-models \
58
+ MODELS_DIR=/app/models
59
 
60
  # Hugging Face Spaces varsayılan port: 7860
61
  EXPOSE 7860
62
 
63
+ # Health check — model download ~2-3 dk sürebilir, start-period uzun
64
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=180s --retries=5 \
65
  CMD curl -f http://localhost:7860/api/health || exit 1
66
 
67
+ # Başlat: önce modelleri indir, sonra API'yi ayağa kaldır
68
+ CMD ["sh", "-c", "python startup.py && uvicorn app.main:app --host 0.0.0.0 --port 7860"]
startup.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AURIS startup script — downloads model artifacts from HuggingFace Hub
3
+ before the API server starts.
4
+
5
+ Usage (in Dockerfile CMD):
6
+ python startup.py && uvicorn app.main:app --host 0.0.0.0 --port 7860
7
+
8
+ Environment variables:
9
+ HF_TOKEN — HuggingFace access token (optional for public repos)
10
+ AURIS_MODELS_REPO — HF repo ID, default: Rtur2003/auris-models
11
+ MODELS_DIR — Local destination, default: /app/models
12
+ SKIP_MODEL_DOWNLOAD — Set to "1" to skip (for local dev)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import os
18
+ import sys
19
+ import time
20
+ from pathlib import Path
21
+
22
+ REPO_ID = os.getenv("AURIS_MODELS_REPO", "Rtur2003/auris-models")
23
+ MODELS_DIR = Path(os.getenv("MODELS_DIR", "/app/models"))
24
+ HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN")
25
+ SKIP = os.getenv("SKIP_MODEL_DOWNLOAD", "0") == "1"
26
+
27
+ # Files that must exist for the API to work
28
+ REQUIRED_FILES = [
29
+ "auris_classifier_v1.pkl",
30
+ "feature_scaler_v1.pkl",
31
+ "feature_columns_v1.json",
32
+ "feature_stats_v1.json",
33
+ "training_results.json",
34
+ "deep_learning_results.json",
35
+ "model_lightgbm.pkl",
36
+ "model_xgboost.pkl",
37
+ "model_random_forest.pkl",
38
+ "model_gradient_boosting.pkl",
39
+ "model_svm_rbf.pkl",
40
+ "model_mlp_neural_network.pkl",
41
+ "model_logistic_regression.pkl",
42
+ "model_dl_deep_mlp_512_256_128_64.pkl",
43
+ "model_dl_1d_cnn.pkl",
44
+ "model_dl_residual_mlp_3_blocks.pkl",
45
+ "model_dl_attention_mlp.pkl",
46
+ "wav2vec2_auris_v1.pt",
47
+ ]
48
+
49
+ # Large files that are optional (wav2vec2 tower works without wav2vec2)
50
+ OPTIONAL_FILES = {
51
+ "wav2vec2_auris_v1.pt",
52
+ }
53
+
54
+
55
+ def _already_downloaded() -> bool:
56
+ """Return True if all required non-optional files already exist."""
57
+ missing = [
58
+ f for f in REQUIRED_FILES
59
+ if f not in OPTIONAL_FILES and not (MODELS_DIR / f).exists()
60
+ ]
61
+ if missing:
62
+ print(f"[startup] Missing files: {missing}")
63
+ return False
64
+ return True
65
+
66
+
67
+ def download_models() -> None:
68
+ if SKIP:
69
+ print("[startup] SKIP_MODEL_DOWNLOAD=1 — skipping download.")
70
+ return
71
+
72
+ MODELS_DIR.mkdir(parents=True, exist_ok=True)
73
+
74
+ if _already_downloaded():
75
+ print("[startup] All required model files already present — skipping download.")
76
+ return
77
+
78
+ print(f"[startup] Downloading models from {REPO_ID} → {MODELS_DIR}")
79
+ t0 = time.time()
80
+
81
+ try:
82
+ from huggingface_hub import hf_hub_download, list_repo_files
83
+ except ImportError:
84
+ print("[startup] huggingface_hub not installed — pip install huggingface-hub")
85
+ sys.exit(1)
86
+
87
+ kwargs = {"repo_id": REPO_ID, "repo_type": "model"}
88
+ if HF_TOKEN:
89
+ kwargs["token"] = HF_TOKEN
90
+
91
+ # Get list of files in the repo
92
+ try:
93
+ repo_files = list(list_repo_files(**{k: v for k, v in kwargs.items() if k != "token"},
94
+ token=HF_TOKEN))
95
+ except Exception as e:
96
+ print(f"[startup] Cannot list repo files: {e}")
97
+ print("[startup] Trying to download known files directly...")
98
+ repo_files = REQUIRED_FILES
99
+
100
+ errors: list[str] = []
101
+ for filename in REQUIRED_FILES:
102
+ dest = MODELS_DIR / filename
103
+ if dest.exists():
104
+ print(f"[startup] skip {filename} (exists)")
105
+ continue
106
+
107
+ if filename not in repo_files and filename not in REQUIRED_FILES:
108
+ if filename in OPTIONAL_FILES:
109
+ print(f"[startup] skip {filename} (not in repo, optional)")
110
+ continue
111
+
112
+ is_optional = filename in OPTIONAL_FILES
113
+ try:
114
+ print(f"[startup] dl {filename} ...", end=" ", flush=True)
115
+ path = hf_hub_download(
116
+ filename=filename,
117
+ local_dir=str(MODELS_DIR),
118
+ **kwargs,
119
+ )
120
+ print(f"OK ({Path(path).stat().st_size / 1024 / 1024:.1f} MB)")
121
+ except Exception as e:
122
+ if is_optional:
123
+ print(f"SKIP (optional: {e})")
124
+ else:
125
+ print(f"ERROR: {e}")
126
+ errors.append(f"{filename}: {e}")
127
+
128
+ elapsed = time.time() - t0
129
+ print(f"[startup] Download complete in {elapsed:.1f}s")
130
+
131
+ if errors:
132
+ print(f"[startup] FATAL — {len(errors)} required file(s) failed:")
133
+ for err in errors:
134
+ print(f" - {err}")
135
+ print("[startup] Set AURIS_MODELS_REPO and HF_TOKEN env vars if repo is private.")
136
+ sys.exit(1)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ download_models()
141
+ print("[startup] Ready.")
upload_models_to_hub.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ One-time script: upload all AURIS model artifacts to HuggingFace Hub.
3
+
4
+ Usage:
5
+ python upload_models_to_hub.py
6
+
7
+ Requires:
8
+ pip install huggingface-hub
9
+ huggingface-cli login (or set HF_TOKEN env var)
10
+
11
+ Creates / updates: Rtur2003/auris-models (model repo, public)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ REPO_ID = "Rtur2003/auris-models"
21
+ MODELS_DIR = Path(__file__).parent / "models"
22
+ HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN")
23
+
24
+ FILES_TO_UPLOAD = [
25
+ # Core classifier
26
+ "auris_classifier_v1.pkl",
27
+ "feature_scaler_v1.pkl",
28
+ "feature_columns_v1.json",
29
+ "feature_stats_v1.json",
30
+ "training_results.json",
31
+ "deep_learning_results.json",
32
+ # ML models
33
+ "model_logistic_regression.pkl",
34
+ "model_random_forest.pkl",
35
+ "model_gradient_boosting.pkl",
36
+ "model_svm_rbf.pkl",
37
+ "model_mlp_neural_network.pkl",
38
+ "model_xgboost.pkl",
39
+ "model_lightgbm.pkl",
40
+ # DL models
41
+ "model_dl_deep_mlp_512_256_128_64.pkl",
42
+ "model_dl_1d_cnn.pkl",
43
+ "model_dl_residual_mlp_3_blocks.pkl",
44
+ "model_dl_attention_mlp.pkl",
45
+ # wav2vec2 transformer
46
+ "wav2vec2_auris_v1.pt",
47
+ ]
48
+
49
+
50
+ def main() -> None:
51
+ try:
52
+ from huggingface_hub import HfApi, create_repo
53
+ except ImportError:
54
+ print("ERROR: pip install huggingface-hub")
55
+ sys.exit(1)
56
+
57
+ api = HfApi(token=HF_TOKEN)
58
+
59
+ # Create repo if it doesn't exist
60
+ try:
61
+ create_repo(REPO_ID, repo_type="model", exist_ok=True, token=HF_TOKEN)
62
+ print(f"Repo ready: https://huggingface.co/{REPO_ID}")
63
+ except Exception as e:
64
+ print(f"WARNING: could not create repo: {e}")
65
+
66
+ errors: list[str] = []
67
+ for filename in FILES_TO_UPLOAD:
68
+ src = MODELS_DIR / filename
69
+ if not src.exists():
70
+ print(f" SKIP {filename} (not found locally)")
71
+ continue
72
+
73
+ size_mb = src.stat().st_size / 1024 / 1024
74
+ print(f" UP {filename} ({size_mb:.1f} MB) ...", end=" ", flush=True)
75
+ try:
76
+ api.upload_file(
77
+ path_or_fileobj=str(src),
78
+ path_in_repo=filename,
79
+ repo_id=REPO_ID,
80
+ repo_type="model",
81
+ )
82
+ print("OK")
83
+ except Exception as e:
84
+ print(f"ERROR: {e}")
85
+ errors.append(f"{filename}: {e}")
86
+
87
+ if errors:
88
+ print(f"\n{len(errors)} upload(s) failed:")
89
+ for e in errors:
90
+ print(f" - {e}")
91
+ sys.exit(1)
92
+ else:
93
+ print(f"\nAll files uploaded to https://huggingface.co/{REPO_ID}")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()