jejunepixels commited on
Commit
8884863
·
verified ·
1 Parent(s): 7b8b533

Update hub_models.py

Browse files
Files changed (1) hide show
  1. hub_models.py +52 -1
hub_models.py CHANGED
@@ -7,6 +7,8 @@ import io
7
  import json
8
  import os
9
  import re
 
 
10
  import time
11
 
12
  CACHE_ROOT = Path(__file__).resolve().parent / '.model-cache'
@@ -17,6 +19,11 @@ from huggingface_hub.utils import validate_repo_id
17
  from tqdm.auto import tqdm
18
 
19
  from embeddings import embedding_name
 
 
 
 
 
20
 
21
 
22
  @dataclass(frozen=True)
@@ -47,6 +54,7 @@ class DownloadPlan:
47
  directory: Path
48
  size: int | None
49
  embeddings_only: bool = False
 
50
 
51
 
52
  def safe_filename(name):
@@ -151,11 +159,54 @@ def build_plan(catalog, selection, token=None, cache_root=CACHE_ROOT):
151
  size = sum(sizes) if all(value is not None for value in sizes) else None
152
  model_path = directory if selection.endswith('.index.json') else directory / selection
153
  return DownloadPlan(catalog.repo_id, catalog.commit, selection, files, tuple(weights), model_path,
154
- directory / tokenizer if tokenizer else None, directory, size, embeddings_only)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
 
157
  def download_model(plan, token=None, progress=None):
158
  """Progress callbacks may run on SDK threads; callers should use a queue."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  total_files = len(plan.files)
160
  for index, filename in enumerate(plan.files):
161
  safe_filename(filename)
 
7
  import json
8
  import os
9
  import re
10
+ import shutil
11
+ from threading import Lock
12
  import time
13
 
14
  CACHE_ROOT = Path(__file__).resolve().parent / '.model-cache'
 
19
  from tqdm.auto import tqdm
20
 
21
  from embeddings import embedding_name
22
+ from app_environment import hosted_mode, hosted_download_limit
23
+
24
+
25
+ HOSTED_DOWNLOAD_LOCK = Lock()
26
+ DISK_RESERVE_BYTES = 2_000_000_000
27
 
28
 
29
  @dataclass(frozen=True)
 
54
  directory: Path
55
  size: int | None
56
  embeddings_only: bool = False
57
+ file_sizes: tuple[int | None, ...] = ()
58
 
59
 
60
  def safe_filename(name):
 
159
  size = sum(sizes) if all(value is not None for value in sizes) else None
160
  model_path = directory if selection.endswith('.index.json') else directory / selection
161
  return DownloadPlan(catalog.repo_id, catalog.commit, selection, files, tuple(weights), model_path,
162
+ directory / tokenizer if tokenizer else None, directory, size, embeddings_only, tuple(sizes))
163
+
164
+
165
+ def check_hosted_download(plan):
166
+ """Enforce the per-model limit and leave room for the running Space.
167
+
168
+ Complete cached files need no additional disk space. Incomplete downloads
169
+ are counted at their full size, making this estimate conservative.
170
+ """
171
+ limit = hosted_download_limit()
172
+ if limit is None:
173
+ return
174
+ if plan.size is None or plan.size > limit:
175
+ raise ValueError(f'This Space supports models up to {format_size(limit)} with a known download size. '
176
+ 'Choose smaller weights or embedding shards, or run the app locally.')
177
+ remaining = plan.size
178
+ if len(plan.file_sizes) == len(plan.files):
179
+ for name, size in zip(plan.files, plan.file_sizes):
180
+ safe_filename(name)
181
+ path = plan.directory / name
182
+ if size is not None and path.is_file() and path.stat().st_size == size:
183
+ remaining -= size
184
+ ancestor = plan.directory.resolve()
185
+ while not ancestor.exists():
186
+ ancestor = ancestor.parent
187
+ free = shutil.disk_usage(ancestor).free
188
+ if remaining and remaining + DISK_RESERVE_BYTES > free:
189
+ raise ValueError(f'Not enough free storage on this Space: {format_size(remaining)} still needs downloading, '
190
+ f'but only {format_size(free)} is free. We reserve 2 GB for the app. '
191
+ 'Choose smaller weights or try again after the Space cache is cleared.')
192
 
193
 
194
  def download_model(plan, token=None, progress=None):
195
  """Progress callbacks may run on SDK threads; callers should use a queue."""
196
+ locked = hosted_mode()
197
+ if locked and not HOSTED_DOWNLOAD_LOCK.acquire(blocking=False):
198
+ raise ValueError('Another model is downloading on this Space. Please try again when it finishes.')
199
+ try:
200
+ # Recheck inside the lock: another visitor may have consumed disk space
201
+ # since this session displayed the download plan.
202
+ check_hosted_download(plan)
203
+ return _download_model(plan, token, progress)
204
+ finally:
205
+ if locked:
206
+ HOSTED_DOWNLOAD_LOCK.release()
207
+
208
+
209
+ def _download_model(plan, token=None, progress=None):
210
  total_files = len(plan.files)
211
  for index, filename in enumerate(plan.files):
212
  safe_filename(filename)