roysun2006 commited on
Commit
5f0742d
·
verified ·
1 Parent(s): dc46b79

Add unified model downloader and usage guides

Browse files
Files changed (3) hide show
  1. README.md +62 -8
  2. README_zh.md +51 -5
  3. download_models.py +193 -0
README.md CHANGED
@@ -118,7 +118,9 @@ All values are reported in the
118
  │ ├── model-*.safetensors # Sharded model weights
119
  │ ├── config.json, *.py # Model config and custom Transformers code
120
  │ └── assets/ # Reference voice, Token2wav, demo audio
121
- ├── assets/ # Brand resources (logo)
 
 
122
  ├── README.md
123
  ├── README_zh.md
124
  └── LICENSE
@@ -129,19 +131,71 @@ new output directory when repeating an experiment.
129
 
130
  ## 6. 🛠️ Installation
131
 
132
- Requires Python 3.10, CUDA, and FFmpeg. Download the repository (the two
133
- checkpoints live in its sub-directories) and install the Python dependencies:
 
134
 
135
  ```bash
136
- huggingface-cli download inclusionAI/Realtime-Venus --local-dir .
137
- # or: modelscope download --model inclusionAI/Realtime-Venus --local_dir .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
 
 
 
 
 
 
 
 
 
139
  python -m pip install -r Realtime-Venus-Omni/requirements.txt
140
  ```
141
 
142
- All example paths below are relative to the downloaded repository's root
143
- directory. The examples load the local `Realtime-Venus-Omni/` and
144
- `Realtime-Venus-Audio/` checkpoints through Hugging Face Transformers.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
  ## 7. 🎙️ Realtime-Venus-Omni Usages
147
 
 
118
  │ ├── model-*.safetensors # Sharded model weights
119
  │ ├── config.json, *.py # Model config and custom Transformers code
120
  │ └── assets/ # Reference voice, Token2wav, demo audio
121
+ ├── assets/ # Brand resources (logo)
122
+ ├── config.yaml # Model names and download directory mapping
123
+ ├── download_models.py # Unified Omni / Audio / all downloader
124
  ├── README.md
125
  ├── README_zh.md
126
  └── LICENSE
 
131
 
132
  ## 6. 🛠️ Installation
133
 
134
+ Running the inference examples requires Python 3.10, CUDA, and FFmpeg. First,
135
+ install the download dependencies and fetch the unified downloader from this
136
+ Hugging Face repository:
137
 
138
  ```bash
139
+ python -m pip install 'huggingface_hub>=0.34' 'PyYAML>=6.0'
140
+ hf download inclusionAI/Realtime-Venus download_models.py --local-dir .
141
+ ```
142
+
143
+ Then choose the models to download:
144
+
145
+ | `--model` | Download |
146
+ | --- | --- |
147
+ | `omni` | Realtime-Venus-Omni for audio-visual interaction |
148
+ | `audio` | Realtime-Venus-Audio for audio understanding and conversation |
149
+ | `all` | Both models |
150
+
151
+ For example, download both models into the current directory:
152
+
153
+ ```bash
154
+ python download_models.py --model all --local-dir .
155
+ ```
156
 
157
+ Use `--model omni` or `--model audio` to download only the model you need.
158
+ The downloader reads this repository's root `config.yaml` and downloads each
159
+ selected model's complete directory, including weights, custom code, and
160
+ assets. It saves a download manifest and uses the Hugging Face Hub's standard
161
+ progress display and cache. Each download uses one repository revision.
162
+
163
+ Install the inference dependencies after downloading. For Omni or `all`:
164
+
165
+ ```bash
166
  python -m pip install -r Realtime-Venus-Omni/requirements.txt
167
  ```
168
 
169
+ Audio uses the same published dependency list; it does not have a separate
170
+ `requirements.txt`. If you downloaded only Audio, fetch that small file first
171
+ without downloading the Omni weights:
172
+
173
+ ```bash
174
+ hf download inclusionAI/Realtime-Venus Realtime-Venus-Omni/requirements.txt --local-dir .
175
+ python -m pip install -r Realtime-Venus-Omni/requirements.txt
176
+ ```
177
+
178
+ To download from Python instead, run this once from the directory containing
179
+ `download_models.py`. It uses the same downloader as the command above:
180
+
181
+ ```python
182
+ from download_models import download_models
183
+
184
+ paths = download_models(model="omni", local_dir=".") # "omni", "audio", or "all"
185
+ model_dir = paths["omni"] # pathlib.Path; use paths["audio"] for Audio
186
+ ```
187
+
188
+ The inference examples below load the downloaded local model directories. Run
189
+ them from the same directory; all asset and output paths are relative to it.
190
+
191
+ As an independent alternative, the ModelScope CLI (installed separately) can
192
+ download the entire mirror repository:
193
+
194
+ ```bash
195
+ modelscope download --model inclusionAI/Realtime-Venus --local_dir .
196
+ ```
197
+
198
+ This mirror command is separate from the Hugging Face downloader above.
199
 
200
  ## 7. 🎙️ Realtime-Venus-Omni Usages
201
 
README_zh.md CHANGED
@@ -79,7 +79,9 @@
79
  │ ├── model-*.safetensors # 分片模型权重
80
  │ ├── config.json, *.py # 模型配置与自定义 Transformers 代码
81
  │ └── assets/ # 参考音色、Token2wav、演示音频
82
- ├── assets/ # 品牌资源(标志)
 
 
83
  ├── README.md
84
  ├── README_zh.md
85
  └── LICENSE
@@ -89,16 +91,60 @@
89
 
90
  ## 6. 🛠️ 安装
91
 
92
- 运行示例需要 Python 3.10、CUDA 和 FFmpeg。先下载模型仓库,再安装 Python 依赖;两个模型的权重分别位于各自的子目录中:
93
 
94
  ```bash
95
- huggingface-cli download inclusionAI/Realtime-Venus --local-dir .
96
- # 或:modelscope download --model inclusionAI/Realtime-Venus --local_dir .
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
 
 
 
 
 
98
  python -m pip install -r Realtime-Venus-Omni/requirements.txt
99
  ```
100
 
101
- 下文所有示例路径均相对于下载后的仓库根目录。示例通过 Hugging Face Transformers 加载本地的 `Realtime-Venus-Omni/` 与 `Realtime-Venus-Audio/` 模型。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  ## 7. 🎙️ Realtime-Venus-Omni 使用方法
104
 
 
79
  │ ├── model-*.safetensors # 分片模型权重
80
  │ ├── config.json, *.py # 模型配置与自定义 Transformers 代码
81
  │ └── assets/ # 参考音色、Token2wav、演示音频
82
+ ├── assets/ # 品牌资源(标志)
83
+ ├── config.yaml # 模型名称与下载目录映射
84
+ ├── download_models.py # Omni / Audio / all 统一下载入口
85
  ├── README.md
86
  ├── README_zh.md
87
  └── LICENSE
 
91
 
92
  ## 6. 🛠️ 安装
93
 
94
+ 运行推理示例需要 Python 3.10、CUDA 和 FFmpeg。首先安装下载依赖,并从本 Hugging Face 仓库获取统一下载脚本:
95
 
96
  ```bash
97
+ python -m pip install 'huggingface_hub>=0.34' 'PyYAML>=6.0'
98
+ hf download inclusionAI/Realtime-Venus download_models.py --local-dir .
99
+ ```
100
+
101
+ 然后选择需要下载的模型:
102
+
103
+ | `--model` | 下载内容 |
104
+ | --- | --- |
105
+ | `omni` | 用于音视频交互的 Realtime-Venus-Omni |
106
+ | `audio` | 用于音频理解与语音对话的 Realtime-Venus-Audio |
107
+ | `all` | 两款模型 |
108
+
109
+ 例如,将两款模型下载到当前目录:
110
+
111
+ ```bash
112
+ python download_models.py --model all --local-dir .
113
+ ```
114
 
115
+ 如只需一款模型,将参数改为 `--model omni` 或 `--model audio`。下载器读取本仓库根目录的 `config.yaml`,下载所选模型的完整子目录,包括权重、自定义代码和资源文件;同时保存下载清单,并使用 Hugging Face Hub 的标准进度显示与缓存。单次下载中的所有文件均来自同一个仓库版本。
116
+
117
+ 下载后安装推理依赖。选择 Omni 或 `all` 时运行:
118
+
119
+ ```bash
120
  python -m pip install -r Realtime-Venus-Omni/requirements.txt
121
  ```
122
 
123
+ Audio 使用相同的已发布依赖清单,没有独立的 `requirements.txt`。如果只下载了 Audio,先单独获取这份小文件,无需下载 Omni 权重:
124
+
125
+ ```bash
126
+ hf download inclusionAI/Realtime-Venus Realtime-Venus-Omni/requirements.txt --local-dir .
127
+ python -m pip install -r Realtime-Venus-Omni/requirements.txt
128
+ ```
129
+
130
+ 也可以在包含 `download_models.py` 的目录中,通过 Python 完成一次下载准备。它与上述命令使用同一个下载入口:
131
+
132
+ ```python
133
+ from download_models import download_models
134
+
135
+ paths = download_models(model="omni", local_dir=".") # 可选 "omni"、"audio" 或 "all"
136
+ model_dir = paths["omni"] # pathlib.Path;Audio 使用 paths["audio"]
137
+ ```
138
+
139
+ 下文推理示例直接加载下载后的本地模型目录。请在同一目录中运行,资源文件和输出路径均相对于当前目录。
140
+
141
+ 也可以独立使用 ModelScope CLI(需另行安装)下载整个镜像仓库:
142
+
143
+ ```bash
144
+ modelscope download --model inclusionAI/Realtime-Venus --local_dir .
145
+ ```
146
+
147
+ 该镜像命令与上述 Hugging Face 下载器相互独立。
148
 
149
  ## 7. 🎙️ Realtime-Venus-Omni 使用方法
150
 
download_models.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Download Realtime-Venus checkpoints using the model repository's manifest."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import math
8
+ import re
9
+ from pathlib import Path, PurePosixPath
10
+
11
+ import yaml
12
+ from huggingface_hub import HfApi, hf_hub_download, snapshot_download
13
+
14
+
15
+ REPO_ID = "inclusionAI/Realtime-Venus"
16
+ MANIFEST = "config.yaml"
17
+ MODEL_CHOICES = ("omni", "audio", "all")
18
+
19
+
20
+ def _model_paths(manifest: object) -> dict[str, str]:
21
+ if not isinstance(manifest, dict) or manifest.get("name") != "Realtime-Venus":
22
+ raise ValueError("config.yaml must describe the Realtime-Venus repository.")
23
+ models = manifest.get("models")
24
+ if not isinstance(models, dict):
25
+ raise ValueError("config.yaml must contain a models mapping.")
26
+
27
+ paths = {}
28
+ for name in ("omni", "audio"):
29
+ entry = models.get(name)
30
+ value = entry.get("path") if isinstance(entry, dict) else None
31
+ if not isinstance(value, str) or not re.fullmatch(
32
+ r"[A-Za-z0-9_-][A-Za-z0-9._/-]*", value
33
+ ):
34
+ raise ValueError(f"Invalid directory for {name} in config.yaml.")
35
+ if any(part in ("", ".", "..") for part in value.split("/")):
36
+ raise ValueError(f"Invalid directory for {name} in config.yaml.")
37
+ paths[name] = value
38
+
39
+ omni, audio = (PurePosixPath(paths[name]) for name in ("omni", "audio"))
40
+ if omni == audio or omni in audio.parents or audio in omni.parents:
41
+ raise ValueError("The Omni and Audio directories must not overlap.")
42
+ return paths
43
+
44
+
45
+ def _check_destination(root: Path, filename: str) -> Path:
46
+ """Keep downloaded files and Hub metadata inside the selected directory."""
47
+ relative = PurePosixPath(filename)
48
+ if relative.is_absolute() or any(p in ("", ".", "..") for p in filename.split("/")):
49
+ raise ValueError(f"Invalid repository file path: {filename!r}")
50
+ if "\\" in filename:
51
+ raise ValueError(f"Invalid repository file path: {filename!r}")
52
+ destination = root.joinpath(*relative.parts)
53
+ if not destination.resolve().is_relative_to(root):
54
+ raise ValueError(f"Download path leaves the destination directory: {filename}")
55
+ return destination
56
+
57
+
58
+ def _verify_downloads(
59
+ root: Path,
60
+ filenames: list[str],
61
+ revision: str,
62
+ sizes: dict[str, int | None] | None = None,
63
+ ) -> None:
64
+ """Reject the Hub's offline fallback to files from an older revision.
65
+
66
+ In local-dir mode, huggingface_hub records the commit hash on the first
67
+ line of each .metadata file. Checking it avoids reporting an incomplete
68
+ or stale download as successful after a network failure.
69
+ """
70
+ for filename in filenames:
71
+ destination = _check_destination(root, filename)
72
+ metadata = _check_destination(
73
+ root, f".cache/huggingface/download/{filename}.metadata"
74
+ )
75
+ try:
76
+ with metadata.open(encoding="utf-8") as handle:
77
+ downloaded_revision = handle.readline().strip()
78
+ etag = handle.readline().strip()
79
+ timestamp = float(handle.readline().strip())
80
+ stat = destination.stat()
81
+ expected_size = (sizes or {}).get(filename)
82
+ valid = (
83
+ destination.is_file()
84
+ and downloaded_revision == revision
85
+ and bool(etag)
86
+ and math.isfinite(timestamp)
87
+ and stat.st_mtime <= timestamp + 1
88
+ and (expected_size is None or stat.st_size == expected_size)
89
+ )
90
+ except (OSError, ValueError):
91
+ valid = False
92
+ if not valid:
93
+ raise RuntimeError(
94
+ f"Could not confirm {filename} at revision {revision}. "
95
+ "Check the connection and rerun the same download command; "
96
+ "completed files will be reused."
97
+ )
98
+
99
+
100
+ def download_models(
101
+ model: str = "all",
102
+ local_dir: str | Path = ".",
103
+ revision: str = "main",
104
+ max_workers: int = 8,
105
+ token: str | bool | None = None,
106
+ ) -> dict[str, Path]:
107
+ """Download omni, audio, or both, returning their local checkpoint paths.
108
+
109
+ The root config.yaml is downloaded and read before selecting model files.
110
+ All requests use one resolved commit. Existing up-to-date files are reused
111
+ by huggingface_hub; other local files and model directories are not removed.
112
+ """
113
+ if model not in MODEL_CHOICES:
114
+ raise ValueError(f"model must be one of {', '.join(MODEL_CHOICES)}")
115
+ if max_workers < 1:
116
+ raise ValueError("max_workers must be at least 1")
117
+
118
+ root = Path(local_dir).expanduser().resolve()
119
+ _check_destination(root, MANIFEST)
120
+ _check_destination(root, ".cache/huggingface")
121
+ _check_destination(root, f".cache/huggingface/download/{MANIFEST}.metadata")
122
+ _check_destination(root, f".cache/huggingface/download/{MANIFEST}.lock")
123
+ info = HfApi().model_info(
124
+ REPO_ID, revision=revision, token=token, files_metadata=True
125
+ )
126
+ commit = info.sha
127
+ if not commit:
128
+ raise RuntimeError(f"Could not resolve revision {revision!r}.")
129
+ sizes = {entry.rfilename: entry.size for entry in info.siblings or []}
130
+ print(f"Repository: {REPO_ID} @ {commit}", flush=True)
131
+ manifest_file = hf_hub_download(
132
+ repo_id=REPO_ID,
133
+ filename=MANIFEST,
134
+ revision=commit,
135
+ local_dir=root,
136
+ token=token,
137
+ )
138
+ _verify_downloads(root, [MANIFEST], commit, sizes)
139
+ with Path(manifest_file).open(encoding="utf-8") as handle:
140
+ paths = _model_paths(yaml.safe_load(handle))
141
+ selected = paths if model == "all" else {model: paths[model]}
142
+
143
+ available = set(sizes)
144
+ filenames = sorted(
145
+ filename
146
+ for filename in available
147
+ if any(filename.startswith(f"{path}/") for path in selected.values())
148
+ )
149
+ for name, path in selected.items():
150
+ if f"{path}/config.json" not in available:
151
+ raise ValueError(f"The manifest's {name} directory has no config.json: {path}")
152
+ print(f"{name}: {root / path}", flush=True)
153
+ for filename in filenames:
154
+ _check_destination(root, filename)
155
+ _check_destination(root, f".cache/huggingface/download/{filename}.metadata")
156
+ _check_destination(root, f".cache/huggingface/download/{filename}.lock")
157
+
158
+ # The manifest is already present. Fetch only the selected model directories
159
+ # so choosing Audio does not also download the Omni checkpoint.
160
+ snapshot_download(
161
+ repo_id=REPO_ID,
162
+ revision=commit,
163
+ local_dir=root,
164
+ allow_patterns=[f"{path}/*" for path in selected.values()],
165
+ max_workers=max_workers,
166
+ token=token,
167
+ )
168
+ _verify_downloads(root, filenames, commit, sizes)
169
+ return {name: root / path for name, path in selected.items()}
170
+
171
+
172
+ def main() -> None:
173
+ parser = argparse.ArgumentParser(description=__doc__)
174
+ parser.add_argument("--model", choices=MODEL_CHOICES, default="all")
175
+ parser.add_argument("--local-dir", default=".", help="Destination root (default: current directory)")
176
+ parser.add_argument("--revision", default="main", help="Hub branch, tag, or commit (default: main)")
177
+ parser.add_argument("--max-workers", type=int, default=8, help="Concurrent file downloads (default: 8)")
178
+ args = parser.parse_args()
179
+ try:
180
+ paths = download_models(
181
+ model=args.model,
182
+ local_dir=args.local_dir,
183
+ revision=args.revision,
184
+ max_workers=args.max_workers,
185
+ )
186
+ except (OSError, ValueError, RuntimeError, yaml.YAMLError) as error:
187
+ parser.exit(1, f"Download failed: {error}\n")
188
+ for name, path in paths.items():
189
+ print(f"Ready: {name} -> {path}")
190
+
191
+
192
+ if __name__ == "__main__":
193
+ main()