Spaces:
Paused
Paused
working good
Browse files
README.md
CHANGED
|
@@ -20,3 +20,23 @@ pinned: false
|
|
| 20 |
6. Update the pipeline
|
| 21 |
7. Update the main.py
|
| 22 |
8. Update the app.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
6. Update the pipeline
|
| 21 |
7. Update the main.py
|
| 22 |
8. Update the app.py
|
| 23 |
+
|
| 24 |
+
## Hugging Face Spaces runtime notes
|
| 25 |
+
|
| 26 |
+
- The app now sets Hugging Face cache paths at startup:
|
| 27 |
+
- `HF_HOME=/data/cache` (fallback: `/tmp/hf_cache`)
|
| 28 |
+
- `TRANSFORMERS_CACHE=/data/cache`
|
| 29 |
+
- `HF_HUB_CACHE=/data/cache/hub`
|
| 30 |
+
- This avoids recurring corrupted tokenizer snapshots in ephemeral `/tmp` cache.
|
| 31 |
+
|
| 32 |
+
### Useful environment variables
|
| 33 |
+
|
| 34 |
+
- `MODEL_LOAD_MAX_ATTEMPTS` (default `3`): number of startup retries for model load.
|
| 35 |
+
- `MODEL_LOAD_RETRY_DELAY` (default `8`): seconds between retries.
|
| 36 |
+
- `RESET_HF_CACHE_ON_START` (default `0`): set to `1` for a one-time cache reset if startup keeps failing.
|
| 37 |
+
|
| 38 |
+
### Recommended recovery procedure
|
| 39 |
+
|
| 40 |
+
1. Set `RESET_HF_CACHE_ON_START=1`.
|
| 41 |
+
2. Trigger a new Space build/restart.
|
| 42 |
+
3. After healthy startup, set `RESET_HF_CACHE_ON_START=0`.
|
app.py
CHANGED
|
@@ -5,10 +5,42 @@ from pydantic import BaseModel
|
|
| 5 |
import uvicorn
|
| 6 |
import subprocess
|
| 7 |
import threading
|
|
|
|
| 8 |
import sys
|
| 9 |
import os
|
|
|
|
|
|
|
| 10 |
from starlette.responses import RedirectResponse
|
| 11 |
from fastapi.responses import Response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
from textSummarizer.pipeline.prediction import PredictionPipeline
|
| 13 |
|
| 14 |
# ββ Shared state ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -20,13 +52,23 @@ _model_error: str | None = None # non-None if load failed
|
|
| 20 |
def _load_model_bg() -> None:
|
| 21 |
"""Background thread: load model and signal readiness."""
|
| 22 |
global _pipeline, _model_error
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
@asynccontextmanager
|
|
|
|
| 5 |
import uvicorn
|
| 6 |
import subprocess
|
| 7 |
import threading
|
| 8 |
+
import time
|
| 9 |
import sys
|
| 10 |
import os
|
| 11 |
+
import shutil
|
| 12 |
+
from pathlib import Path
|
| 13 |
from starlette.responses import RedirectResponse
|
| 14 |
from fastapi.responses import Response
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def _configure_hf_cache() -> None:
|
| 18 |
+
"""Configure Hugging Face cache directory before any model imports.
|
| 19 |
+
|
| 20 |
+
On HuggingFace Spaces, `/data` is persistent between restarts and is safer
|
| 21 |
+
than `/tmp` for large model artifacts.
|
| 22 |
+
"""
|
| 23 |
+
preferred_cache_root = Path("/data/cache")
|
| 24 |
+
fallback_cache_root = Path("/tmp/hf_cache")
|
| 25 |
+
cache_root = preferred_cache_root if preferred_cache_root.parent.exists() else fallback_cache_root
|
| 26 |
+
|
| 27 |
+
cache_root.mkdir(parents=True, exist_ok=True)
|
| 28 |
+
(cache_root / "hub").mkdir(parents=True, exist_ok=True)
|
| 29 |
+
|
| 30 |
+
os.environ["HF_HOME"] = str(cache_root)
|
| 31 |
+
os.environ["TRANSFORMERS_CACHE"] = str(cache_root)
|
| 32 |
+
os.environ["HF_HUB_CACHE"] = str(cache_root / "hub")
|
| 33 |
+
|
| 34 |
+
# Optional: set RESET_HF_CACHE_ON_START=1 for a one-time hard cache reset.
|
| 35 |
+
if os.environ.get("RESET_HF_CACHE_ON_START", "0") == "1":
|
| 36 |
+
hub_cache = cache_root / "hub"
|
| 37 |
+
if hub_cache.exists():
|
| 38 |
+
shutil.rmtree(hub_cache, ignore_errors=True)
|
| 39 |
+
hub_cache.mkdir(parents=True, exist_ok=True)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
_configure_hf_cache()
|
| 43 |
+
|
| 44 |
from textSummarizer.pipeline.prediction import PredictionPipeline
|
| 45 |
|
| 46 |
# ββ Shared state ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 52 |
def _load_model_bg() -> None:
|
| 53 |
"""Background thread: load model and signal readiness."""
|
| 54 |
global _pipeline, _model_error
|
| 55 |
+
max_attempts = int(os.environ.get("MODEL_LOAD_MAX_ATTEMPTS", "3"))
|
| 56 |
+
retry_delay_seconds = int(os.environ.get("MODEL_LOAD_RETRY_DELAY", "8"))
|
| 57 |
+
|
| 58 |
+
_model_error = None
|
| 59 |
+
for attempt in range(1, max_attempts + 1):
|
| 60 |
+
try:
|
| 61 |
+
_pipeline = PredictionPipeline()
|
| 62 |
+
_pipeline.load_model()
|
| 63 |
+
_model_error = None
|
| 64 |
+
_model_ready.set()
|
| 65 |
+
return
|
| 66 |
+
except Exception as exc:
|
| 67 |
+
_model_error = str(exc)
|
| 68 |
+
if attempt < max_attempts:
|
| 69 |
+
time.sleep(retry_delay_seconds)
|
| 70 |
+
|
| 71 |
+
_model_ready.set() # unblock probes after final failure
|
| 72 |
|
| 73 |
|
| 74 |
@asynccontextmanager
|