cronos3k commited on
Commit
5ebe73c
·
verified ·
1 Parent(s): 16e2a0a

Upload download_models.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. download_models.py +279 -0
download_models.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Model downloader for LongCat-AudioDiT Enhanced.
3
+
4
+ Downloads models to ./models/ so they are available offline.
5
+ Always download BEFORE running the GUI - never let the GUI block on a download.
6
+
7
+ Usage:
8
+ python download_models.py # 1B + whisper turbo (recommended start)
9
+ python download_models.py --tts 1B 3.5B --whisper turbo large-v3
10
+ python download_models.py --all
11
+ python download_models.py --list
12
+ """
13
+
14
+ import argparse
15
+ import logging
16
+ import sys
17
+ import time
18
+ from pathlib import Path
19
+
20
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Model registry
25
+ # ---------------------------------------------------------------------------
26
+ AUDIODIT_MODELS = {
27
+ "1B": ("meituan-longcat/LongCat-AudioDiT-1B", "~4 GB"),
28
+ "3.5B": ("meituan-longcat/LongCat-AudioDiT-3.5B", "~10 GB"),
29
+ }
30
+
31
+ WHISPER_MODELS = {
32
+ "turbo": ("deepdml/faster-whisper-large-v3-turbo-ct2", "~1.6 GB"),
33
+ "large-v3": ("Systran/faster-whisper-large-v3", "~3 GB"),
34
+ "medium": ("Systran/faster-whisper-medium", "~1.5 GB"),
35
+ "small": ("Systran/faster-whisper-small", "~0.5 GB"),
36
+ }
37
+
38
+ # Local cache dirs – always project-local, never Windows user dirs
39
+ MODELS_DIR = Path(__file__).parent / "models"
40
+ AUDIODIT_DIR = MODELS_DIR / "audiodit"
41
+ WHISPER_DIR = MODELS_DIR / "whisper"
42
+
43
+
44
+ # ---------------------------------------------------------------------------
45
+ # Status helpers
46
+ # ---------------------------------------------------------------------------
47
+
48
+ def _audiodit_present(size: str) -> bool:
49
+ """True only when the weights file exists and is fully written (no .incomplete sibling)."""
50
+ weights = AUDIODIT_DIR / size / "model.safetensors"
51
+ incomplete = AUDIODIT_DIR / size / ".cache" / "huggingface" / "download" / "model.safetensors.incomplete"
52
+ return weights.exists() and not incomplete.exists()
53
+
54
+ def _whisper_present(size: str) -> bool:
55
+ """True only when the model.bin weights file exists and is fully written."""
56
+ d = WHISPER_DIR / size
57
+ weights = d / "model.bin"
58
+ incomplete = d / ".cache" / "huggingface" / "download" / "model.bin.incomplete"
59
+ return weights.exists() and not incomplete.exists()
60
+
61
+
62
+ def model_status() -> dict:
63
+ """Return a dict with download status for every model."""
64
+ status = {}
65
+ for k in AUDIODIT_MODELS:
66
+ status[f"audiodit_{k}"] = _audiodit_present(k)
67
+ for k in WHISPER_MODELS:
68
+ status[f"whisper_{k}"] = _whisper_present(k)
69
+ return status
70
+
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Progress callback for huggingface_hub
74
+ # ---------------------------------------------------------------------------
75
+
76
+ class _ProgressPrinter:
77
+ """Prints file-level download progress to stdout."""
78
+
79
+ def __init__(self, label: str):
80
+ self.label = label
81
+ self._last_print = 0.0
82
+ self._files_done: set = set()
83
+
84
+ def __call__(self, info):
85
+ # info is a tqdm-like object from huggingface_hub
86
+ try:
87
+ filename = getattr(info, "filename", "")
88
+ downloaded = getattr(info, "downloaded", 0)
89
+ total = getattr(info, "total", 0)
90
+ now = time.time()
91
+ if total and now - self._last_print >= 2.0:
92
+ pct = downloaded / total * 100
93
+ mb_done = downloaded / 1e6
94
+ mb_total = total / 1e6
95
+ print(
96
+ f"\r [{self.label}] {filename:40s} "
97
+ f"{mb_done:7.1f} / {mb_total:7.1f} MB ({pct:5.1f}%)",
98
+ end="", flush=True,
99
+ )
100
+ self._last_print = now
101
+ except Exception:
102
+ pass
103
+
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Core download functions
107
+ # ---------------------------------------------------------------------------
108
+
109
+ def download_audiodit(size: str, callback=None) -> bool:
110
+ """Download an AudioDiT model. Returns True on success."""
111
+ entry = AUDIODIT_MODELS.get(size)
112
+ if not entry:
113
+ logger.error("Unknown AudioDiT size '%s'. Choose from: %s", size, list(AUDIODIT_MODELS))
114
+ return False
115
+ repo_id, size_hint = entry
116
+ local_dir = AUDIODIT_DIR / size
117
+
118
+ if _audiodit_present(size):
119
+ msg = f"AudioDiT-{size} already downloaded at {local_dir}"
120
+ logger.info(msg)
121
+ if callback:
122
+ callback(msg)
123
+ return True
124
+
125
+ local_dir.mkdir(parents=True, exist_ok=True)
126
+ msg = f"Downloading AudioDiT-{size} ({size_hint}) from {repo_id} ..."
127
+ print(f"\n{msg}")
128
+ if callback:
129
+ callback(msg)
130
+
131
+ try:
132
+ from huggingface_hub import snapshot_download
133
+ snapshot_download(
134
+ repo_id=repo_id,
135
+ local_dir=str(local_dir),
136
+ )
137
+ print() # newline after progress
138
+ msg = f"[OK] AudioDiT-{size} -> {local_dir}"
139
+ logger.info(msg)
140
+ if callback:
141
+ callback(msg)
142
+ return True
143
+ except Exception as e:
144
+ print()
145
+ msg = f"FAILED to download AudioDiT-{size}: {e}"
146
+ logger.error(msg)
147
+ if callback:
148
+ callback(msg)
149
+ return False
150
+
151
+
152
+ def download_whisper(size: str, callback=None) -> bool:
153
+ """Download a Whisper model. Returns True on success."""
154
+ entry = WHISPER_MODELS.get(size)
155
+ if not entry:
156
+ logger.error("Unknown Whisper size '%s'. Choose from: %s", size, list(WHISPER_MODELS))
157
+ return False
158
+ repo_id, size_hint = entry
159
+ local_dir = WHISPER_DIR / size
160
+
161
+ if _whisper_present(size):
162
+ msg = f"Whisper-{size} already downloaded at {local_dir}"
163
+ logger.info(msg)
164
+ if callback:
165
+ callback(msg)
166
+ return True
167
+
168
+ local_dir.mkdir(parents=True, exist_ok=True)
169
+ msg = f"Downloading Whisper-{size} ({size_hint}) from {repo_id} ..."
170
+ print(f"\n{msg}")
171
+ if callback:
172
+ callback(msg)
173
+
174
+ try:
175
+ from huggingface_hub import snapshot_download
176
+ snapshot_download(
177
+ repo_id=repo_id,
178
+ local_dir=str(local_dir),
179
+ )
180
+ print()
181
+ msg = f"[OK] Whisper-{size} -> {local_dir}"
182
+ logger.info(msg)
183
+ if callback:
184
+ callback(msg)
185
+ return True
186
+ except Exception as e:
187
+ print()
188
+ msg = f"FAILED to download Whisper-{size}: {e}"
189
+ logger.error(msg)
190
+ if callback:
191
+ callback(msg)
192
+ return False
193
+
194
+
195
+ # ---------------------------------------------------------------------------
196
+ # CLI helpers
197
+ # ---------------------------------------------------------------------------
198
+
199
+ def list_models():
200
+ print("\n AudioDiT TTS models:")
201
+ print(f" {'Name':<8} {'Size':<8} {'Status':<18} HuggingFace repo")
202
+ print(f" {'-'*8} {'-'*8} {'-'*18} {'-'*40}")
203
+ for k, (repo, hint) in AUDIODIT_MODELS.items():
204
+ st = "[downloaded]" if _audiodit_present(k) else "not downloaded"
205
+ print(f" {k:<8} {hint:<8} {st:<18} {repo}")
206
+
207
+ print(f"\n Whisper STT models:")
208
+ print(f" {'Name':<10} {'Size':<8} {'Status':<18} HuggingFace repo")
209
+ print(f" {'-'*10} {'-'*8} {'-'*18} {'-'*45}")
210
+ for k, (repo, hint) in WHISPER_MODELS.items():
211
+ st = "[downloaded]" if _whisper_present(k) else "not downloaded"
212
+ print(f" {k:<10} {hint:<8} {st:<18} {repo}")
213
+ print()
214
+
215
+
216
+ def main():
217
+ parser = argparse.ArgumentParser(
218
+ description="Download LongCat-AudioDiT + Whisper models to ./models/",
219
+ formatter_class=argparse.RawDescriptionHelpFormatter,
220
+ epilog="""
221
+ Examples:
222
+ python download_models.py # 1B TTS + Whisper Turbo (~6 GB)
223
+ python download_models.py --tts 1B 3.5B # both TTS models
224
+ python download_models.py --whisper large-v3 # best Whisper only
225
+ python download_models.py --all # everything (~19 GB)
226
+ python download_models.py --list # show status and exit
227
+ """,
228
+ )
229
+ parser.add_argument("--tts", nargs="+", metavar="SIZE",
230
+ help=f"TTS models: {list(AUDIODIT_MODELS)}")
231
+ parser.add_argument("--whisper", nargs="+", metavar="SIZE",
232
+ help=f"Whisper models: {list(WHISPER_MODELS)}")
233
+ parser.add_argument("--all", action="store_true", help="Download every model")
234
+ parser.add_argument("--list", action="store_true", help="List status and exit")
235
+ args = parser.parse_args()
236
+
237
+ AUDIODIT_DIR.mkdir(parents=True, exist_ok=True)
238
+ WHISPER_DIR.mkdir(parents=True, exist_ok=True)
239
+
240
+ if args.list:
241
+ list_models()
242
+ return
243
+
244
+ if args.all:
245
+ tts_sizes = list(AUDIODIT_MODELS)
246
+ whisper_sizes = list(WHISPER_MODELS)
247
+ else:
248
+ tts_sizes = args.tts or ["1B"]
249
+ whisper_sizes = args.whisper or ["turbo"]
250
+
251
+ # Show what we're about to do
252
+ print("\n === LongCat-AudioDiT Model Downloader ===")
253
+ for s in tts_sizes:
254
+ _, hint = AUDIODIT_MODELS.get(s, ("?", "?"))
255
+ status = "[already have it]" if _audiodit_present(s) else f"will download {hint}"
256
+ print(f" AudioDiT-{s:<6} {status}")
257
+ for s in whisper_sizes:
258
+ _, hint = WHISPER_MODELS.get(s, ("?", "?"))
259
+ status = "[already have it]" if _whisper_present(s) else f"will download {hint}"
260
+ print(f" Whisper-{s:<8} {status}")
261
+ print()
262
+
263
+ ok = True
264
+ t0 = time.time()
265
+ for s in tts_sizes:
266
+ ok &= download_audiodit(s)
267
+ for s in whisper_sizes:
268
+ ok &= download_whisper(s)
269
+
270
+ elapsed = time.time() - t0
271
+ print(f"\n Done in {elapsed:.0f}s.")
272
+ list_models()
273
+
274
+ if not ok:
275
+ sys.exit(1)
276
+
277
+
278
+ if __name__ == "__main__":
279
+ main()