TNOT commited on
Commit
ec4b9e1
·
1 Parent(s): 9b56c31

fix: 又得我他妈搞镜像了

Browse files
docs/流程文档_AI用.md CHANGED
@@ -171,7 +171,7 @@
171
  | 模块 | 文件 | 功能 |
172
  |------|------|------|
173
  | Silero VAD 下载 | `silero_vad_downloader.py` | 下载语音活动检测模型(支持多镜像源) |
174
- | MFA 模型下载 | `mfa_model_downloader.py` | 下载声学模型和字典(带完整性校验) |
175
  | Whisper 模型 | 通过 HuggingFace 自动下载 | 语音识别模型 |
176
 
177
  支持的语言:
@@ -186,6 +186,11 @@ Silero VAD 下载镜像源(按优先级):
186
  - jsdelivr CDN
187
  - GitHub 原始地址(备选)
188
 
 
 
 
 
 
189
  MFA 字典文件完整性校验:
190
  - 下载完成后计算 SHA256 哈希并保存为 `.sha256` 文件
191
  - 后续启动时校验哈希值,损坏则自动重新下载
 
171
  | 模块 | 文件 | 功能 |
172
  |------|------|------|
173
  | Silero VAD 下载 | `silero_vad_downloader.py` | 下载语音活动检测模型(支持多镜像源) |
174
+ | MFA 模型下载 | `mfa_model_downloader.py` | 下载声学模型和字典(带完整性校验,支持 GitHub 代理镜像) |
175
  | Whisper 模型 | 通过 HuggingFace 自动下载 | 语音识别模型 |
176
 
177
  支持的语言:
 
186
  - jsdelivr CDN
187
  - GitHub 原始地址(备选)
188
 
189
+ MFA 模型下载镜像源(云端环境自动启用):
190
+ - ghfast.top 镜像(优先)
191
+ - gh-proxy.com 镜像
192
+ - GitHub 原始地址(备选)
193
+
194
  MFA 字典文件完整性校验:
195
  - 下载完成后计算 SHA256 哈希并保存为 `.sha256` 文件
196
  - 后续启动时校验哈希值,损坏则自动重新下载
src/mfa_model_downloader.py CHANGED
@@ -3,6 +3,7 @@
3
  MFA 模型下载模块
4
  支持下载中文和日文的声学模型及字典
5
  包含 SHA256 哈希校验,确保文件完整性
 
6
  """
7
 
8
  import os
@@ -11,7 +12,7 @@ import logging
11
  import urllib.request
12
  import urllib.error
13
  from pathlib import Path
14
- from typing import Optional, Callable
15
 
16
  logger = logging.getLogger(__name__)
17
 
@@ -19,6 +20,14 @@ logger = logging.getLogger(__name__)
19
  GITHUB_RELEASE_BASE = "https://github.com/MontrealCorpusTools/mfa-models/releases/download"
20
  GITHUB_RAW_BASE = "https://raw.githubusercontent.com/MontrealCorpusTools/mfa-models/main"
21
 
 
 
 
 
 
 
 
 
22
  # 支持的语言配置
23
  # 格式: {语言代码: {名称, 声学模型信息, 字典信息}}
24
  # sha256: 官方文件的 SHA256 哈希值(清理空行后),用于校验文件完整性
@@ -159,16 +168,36 @@ def _verify_file_integrity(
159
  return True, "文件完整"
160
 
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  def _download_file(
163
  url: str,
164
  dest_path: str,
165
  progress_callback: Optional[Callable[[str], None]] = None
166
  ) -> bool:
167
  """
168
- 下载文件
169
 
170
  参数:
171
- url: 下载地址
172
  dest_path: 保存路径
173
  progress_callback: 进度回调
174
 
@@ -180,65 +209,73 @@ def _download_file(
180
  if progress_callback:
181
  progress_callback(msg)
182
 
183
- try:
184
- log(f"正在下载: {url}")
185
-
186
- # 创建目录
187
- os.makedirs(os.path.dirname(dest_path), exist_ok=True)
188
-
189
- # 下载到临时文件,完成后再重命名
190
- temp_path = dest_path + ".downloading"
191
-
192
- # 下载文件
193
- req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
194
-
195
- with urllib.request.urlopen(req, timeout=120) as response:
196
- total_size = response.headers.get("Content-Length")
197
- if total_size:
198
- total_size = int(total_size)
199
- log(f"文件大小: {total_size / 1024 / 1024:.1f} MB")
200
 
201
- # 分块下载
202
- block_size = 8192
203
- downloaded = 0
204
 
205
- with open(temp_path, "wb") as f:
206
- while True:
207
- chunk = response.read(block_size)
208
- if not chunk:
209
- break
210
- f.write(chunk)
211
- downloaded += len(chunk)
212
-
213
- if total_size and downloaded % (block_size * 100) == 0:
214
- percent = downloaded / total_size * 100
215
- log(f"下载进度: {percent:.1f}%")
216
-
217
- # 下载完成,重命名
218
- if os.path.exists(dest_path):
219
- os.remove(dest_path)
220
- os.rename(temp_path, dest_path)
221
-
222
- log(f"下载完成: {dest_path}")
223
- return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
- except urllib.error.HTTPError as e:
226
- log(f"HTTP 错误: {e.code} - {e.reason}")
227
- return False
228
- except urllib.error.URLError as e:
229
- log(f"网络错误: {e.reason}")
230
- return False
231
- except Exception as e:
232
- log(f"下载失败: {e}")
233
- return False
234
- finally:
235
- # 清理临时文件
236
- temp_path = dest_path + ".downloading"
237
- if os.path.exists(temp_path):
238
- try:
239
- os.remove(temp_path)
240
- except:
241
- pass
242
 
243
 
244
 
 
3
  MFA 模型下载模块
4
  支持下载中文和日文的声学模型及字典
5
  包含 SHA256 哈希校验,确保文件完整性
6
+ 支持 GitHub 代理镜像(云端环境)
7
  """
8
 
9
  import os
 
12
  import urllib.request
13
  import urllib.error
14
  from pathlib import Path
15
+ from typing import Optional, Callable, List
16
 
17
  logger = logging.getLogger(__name__)
18
 
 
20
  GITHUB_RELEASE_BASE = "https://github.com/MontrealCorpusTools/mfa-models/releases/download"
21
  GITHUB_RAW_BASE = "https://raw.githubusercontent.com/MontrealCorpusTools/mfa-models/main"
22
 
23
+ # GitHub 代理镜像列表(云端环境使用)
24
+ # 格式: 代理前缀 + 原始 GitHub URL
25
+ GITHUB_PROXIES = [
26
+ "https://ghfast.top/",
27
+ "https://gh-proxy.com/",
28
+ "", # 最后尝试直连
29
+ ]
30
+
31
  # 支持的语言配置
32
  # 格式: {语言代码: {名称, 声学模型信息, 字典信息}}
33
  # sha256: 官方文件的 SHA256 哈希值(清理空行后),用于校验文件完整性
 
168
  return True, "文件完整"
169
 
170
 
171
+ def _is_cloud_environment() -> bool:
172
+ """检测是否在云端环境运行"""
173
+ return any([
174
+ os.environ.get("SPACE_ID"), # Hugging Face Spaces
175
+ os.environ.get("MODELSCOPE_SPACE"), # 魔塔社区
176
+ os.environ.get("GRADIO_SERVER_NAME"), # 通用 Gradio 云端
177
+ Path("/home/studio_service").exists(), # 魔搭创空间特征目录
178
+ ])
179
+
180
+
181
+ def _get_proxy_urls(original_url: str) -> List[str]:
182
+ """
183
+ 获取带代理的 URL 列表
184
+ 云端环境返回多个代理 URL,本地环境只返回原始 URL
185
+ """
186
+ if _is_cloud_environment():
187
+ return [f"{proxy}{original_url}" for proxy in GITHUB_PROXIES]
188
+ return [original_url]
189
+
190
+
191
  def _download_file(
192
  url: str,
193
  dest_path: str,
194
  progress_callback: Optional[Callable[[str], None]] = None
195
  ) -> bool:
196
  """
197
+ 下载文件(支持代理镜像自动切换)
198
 
199
  参数:
200
+ url: 下载地址(原始 GitHub URL)
201
  dest_path: 保存路径
202
  progress_callback: 进度回调
203
 
 
209
  if progress_callback:
210
  progress_callback(msg)
211
 
212
+ # 获取所有可用的 URL(包括代理)
213
+ urls = _get_proxy_urls(url)
214
+
215
+ for try_url in urls:
216
+ try:
217
+ log(f"正在下载: {try_url}")
 
 
 
 
 
 
 
 
 
 
 
218
 
219
+ # 创建目录
220
+ os.makedirs(os.path.dirname(dest_path), exist_ok=True)
 
221
 
222
+ # 下载到临时文件,完成后再重命名
223
+ temp_path = dest_path + ".downloading"
224
+
225
+ # 下载文件
226
+ req = urllib.request.Request(try_url, headers={"User-Agent": "Mozilla/5.0"})
227
+
228
+ with urllib.request.urlopen(req, timeout=180) as response:
229
+ total_size = response.headers.get("Content-Length")
230
+ if total_size:
231
+ total_size = int(total_size)
232
+ log(f"文件大小: {total_size / 1024 / 1024:.1f} MB")
233
+
234
+ # 分块下载
235
+ block_size = 8192
236
+ downloaded = 0
237
+
238
+ with open(temp_path, "wb") as f:
239
+ while True:
240
+ chunk = response.read(block_size)
241
+ if not chunk:
242
+ break
243
+ f.write(chunk)
244
+ downloaded += len(chunk)
245
+
246
+ if total_size and downloaded % (block_size * 100) == 0:
247
+ percent = downloaded / total_size * 100
248
+ log(f"下载进度: {percent:.1f}%")
249
+
250
+ # 下载完成,重命名
251
+ if os.path.exists(dest_path):
252
+ os.remove(dest_path)
253
+ os.rename(temp_path, dest_path)
254
+
255
+ log(f"下载完成: {dest_path}")
256
+ return True
257
+
258
+ except urllib.error.HTTPError as e:
259
+ log(f"HTTP 错误: {e.code} - {e.reason}")
260
+ except urllib.error.URLError as e:
261
+ log(f"网络错误: {e.reason}")
262
+ except Exception as e:
263
+ log(f"下载失败: {e}")
264
+ finally:
265
+ # 清理临时文件
266
+ temp_path = dest_path + ".downloading"
267
+ if os.path.exists(temp_path):
268
+ try:
269
+ os.remove(temp_path)
270
+ except:
271
+ pass
272
 
273
+ # 当前 URL 失败,尝试下一个
274
+ if try_url != urls[-1]:
275
+ log("尝试下一个镜像...")
276
+
277
+ log("所有镜像均下载失败")
278
+ return False
 
 
 
 
 
 
 
 
 
 
 
279
 
280
 
281