Inayatgaming commited on
Commit
cac383d
·
verified ·
1 Parent(s): 0caef99

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +16 -0
  2. app.py +131 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ ENV PYTHONUNBUFFERED=1 \
6
+ PIP_NO_CACHE_DIR=1 \
7
+ ICMR_DATA_DIR=/data \
8
+ PORT=7860
9
+
10
+ RUN mkdir -p /data
11
+
12
+ COPY app.py /app/app.py
13
+
14
+ EXPOSE 7860
15
+
16
+ CMD ["python", "/app/app.py"]
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Hugging Face Docker Space bootstrapper."""
3
+
4
+ import os
5
+ import sys
6
+ import subprocess
7
+ from pathlib import Path
8
+ from urllib.request import Request, urlopen
9
+ from urllib.error import HTTPError, URLError
10
+
11
+ DATA_REPO = os.getenv("DATA_REPO", "Kzr0xx/icrm-hitek-full-db-mixed")
12
+ INDEX_REPO = os.getenv("INDEX_REPO", "CutehackX/icrm-hitek-full-db-mixed-bucket")
13
+ CODE_REPO = os.getenv("CODE_REPO", "CutehackX/icrm-hitek-full-db-mixed-bucket")
14
+ DATA_DIR = Path(os.getenv("ICMR_DATA_DIR", "/data"))
15
+ PORT = int(os.getenv("PORT", "7860"))
16
+
17
+ FILES = ["part1.parquet", "part2a.parquet", "part2b_new.parquet"]
18
+
19
+ IDX = [
20
+ "idx_phone.0.parquet", "idx_phone.1.parquet", "idx_phone.2.parquet",
21
+ "idx_phone.3.parquet", "idx_phone.4.parquet", "idx_phone.5.parquet",
22
+ "idx_phone.6.parquet", "idx_aadhar.0.parquet", "idx_aadhar.1.parquet",
23
+ "idx_aadhar.2.parquet", "idx_aadhar.3.parquet", "idx_aadhar.4.parquet",
24
+ "idx_aadhar.5.parquet", "idx_aadhar.6.parquet",
25
+ ]
26
+
27
+ CODE = ["main.py", "build_index.py", "requirements.txt"]
28
+
29
+
30
+ def download(repo: str, name: str, destination: Path):
31
+ """Download directly from Hugging Face resolve/main URL, with resume support."""
32
+ destination.parent.mkdir(parents=True, exist_ok=True)
33
+
34
+ url = f"https://huggingface.co/datasets/{repo}/resolve/main/{name}"
35
+ token = os.getenv("HF_TOKEN", "").strip()
36
+ existing = destination.stat().st_size if destination.exists() else 0
37
+
38
+ print(f"[DOWNLOAD] {url}", flush=True)
39
+
40
+ headers = {"User-Agent": "hf-docker-space-downloader/1.0"}
41
+ if token:
42
+ headers["Authorization"] = f"Bearer {token}"
43
+ if existing:
44
+ headers["Range"] = f"bytes={existing}-"
45
+
46
+ request = Request(url, headers=headers)
47
+
48
+ try:
49
+ with urlopen(request, timeout=120) as response:
50
+ status = getattr(response, "status", 200)
51
+
52
+ # If the server ignores Range, restart the file instead of appending.
53
+ if existing and status != 206:
54
+ print("[INFO] Server did not return partial content; restarting download.", flush=True)
55
+ existing = 0
56
+
57
+ mode = "ab" if existing and status == 206 else "wb"
58
+ total = response.headers.get("Content-Length")
59
+ total_bytes = int(total) + existing if total and status == 206 else int(total) if total else None
60
+ downloaded = existing
61
+
62
+ with open(destination, mode) as f:
63
+ while True:
64
+ chunk = response.read(16 * 1024 * 1024)
65
+ if not chunk:
66
+ break
67
+ f.write(chunk)
68
+ downloaded += len(chunk)
69
+ if total_bytes:
70
+ pct = downloaded * 100 / total_bytes
71
+ print(f"\r {downloaded:,}/{total_bytes:,} bytes ({pct:.1f}%)", end="", flush=True)
72
+ else:
73
+ print(f"\r {downloaded:,} bytes", end="", flush=True)
74
+
75
+ print(f"\n[OK] {destination} ({downloaded:,} bytes)", flush=True)
76
+
77
+ except HTTPError as e:
78
+ raise RuntimeError(f"Download failed: HTTP {e.code} for {url}") from e
79
+ except URLError as e:
80
+ raise RuntimeError(f"Download failed: {url}: {e.reason}") from e
81
+
82
+
83
+ def install_requirements(path: Path):
84
+ print("[SETUP] Installing API requirements...", flush=True)
85
+ subprocess.check_call([
86
+ sys.executable, "-m", "pip", "install", "--no-cache-dir", "-r", str(path)
87
+ ])
88
+
89
+
90
+ def start_api():
91
+ env = os.environ.copy()
92
+ env["ICMR_DATA_DIR"] = str(DATA_DIR)
93
+ print(f"[START] Uvicorn on 0.0.0.0:{PORT}", flush=True)
94
+ os.execvpe(sys.executable, [
95
+ sys.executable, "-m", "uvicorn", "main:app",
96
+ "--host", "0.0.0.0", "--port", str(PORT), "--workers", "1"
97
+ ], env)
98
+
99
+
100
+ def main():
101
+ DATA_DIR.mkdir(parents=True, exist_ok=True)
102
+ skip = os.getenv("SKIP_DOWNLOAD", "").lower() in {"1", "true", "yes", "on"}
103
+
104
+ if not skip:
105
+ print("[1/3] Downloading parquet data from Kzr0xx...", flush=True)
106
+ for name in FILES:
107
+ download(DATA_REPO, name, DATA_DIR / name)
108
+
109
+ print("[2/3] Downloading 14 indexes from CutehackX...", flush=True)
110
+ for name in IDX:
111
+ download(INDEX_REPO, name, DATA_DIR / name)
112
+
113
+ print("[3/3] Downloading API code from CutehackX...", flush=True)
114
+ for name in CODE:
115
+ download(CODE_REPO, name, Path("/app") / name)
116
+ else:
117
+ print("[SKIP_DOWNLOAD] Using existing files.", flush=True)
118
+
119
+ requirements = Path("/app/requirements.txt")
120
+ if not requirements.exists():
121
+ raise FileNotFoundError("/app/requirements.txt was not downloaded.")
122
+
123
+ if not Path("/app/main.py").exists():
124
+ raise FileNotFoundError("/app/main.py was not downloaded.")
125
+
126
+ install_requirements(requirements)
127
+ start_api()
128
+
129
+
130
+ if __name__ == "__main__":
131
+ main()