| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- #!/usr/bin/env python3
- """从阿里云帮助页面提取全部音色并下载音频样本"""
- import json, os, re, requests, subprocess, time
- OUTPUT_DIR = "docs/voices/audio"
- os.makedirs(OUTPUT_DIR, exist_ok=True)
- # 用 playwright 提取音色数据
- print("正在提取音色列表...")
- result = subprocess.run([
- "npx", "playwright-cli", "run-code",
- r"""async (page) => {
- const data = [];
- // 遍历所有包含音频的表格行
- const rows = document.querySelectorAll('tr');
- rows.forEach(tr => {
- const audioEl = tr.querySelector('audio');
- if (!audioEl) return;
- const src = audioEl.querySelector('source')?.src || audioEl.src;
- if (!src) return;
-
- // 提取voice参数
- const text = tr.textContent || '';
- const voiceMatch = text.match(/voice参数[::]\s*(\S+)/);
- const nameMatch = voiceMatch ? text.match(/名称[::]\s*(\S+)/) : null;
- const sceneMatch = text.match(/(?:^|\n)([^\n]{3,20}?)\s*名称[::]/);
-
- data.push({
- url: src,
- voice: voiceMatch ? voiceMatch[1] : '',
- name: nameMatch ? nameMatch[1] : '',
- scene: sceneMatch ? sceneMatch[1].trim() : ''
- });
- });
- return JSON.stringify(data);
- }"""], capture_output=True, text=True, cwd="c:/Users/caoyg/ai/audio-tts/audio_codebuddy")
- # 解析输出
- output = result.stdout
- # 提取 JSON
- json_start = output.find('[')
- json_end = output.rfind(']') + 1
- if json_start < 0 or json_end <= json_start:
- print("未找到音色数据")
- print(output[:500])
- exit(1)
- voices = json.loads(output[json_start:json_end])
- print(f"找到 {len(voices)} 个音色")
- # 写音色索引
- index_lines = ["# 官方音色样本索引\n", f"\n共 {len(voices)} 个音色,来源:阿里云百炼帮助中心\n\n"]
- index_lines.append("| 音色名称 | voice参数 | 适用场景 | 文件名 |\n")
- index_lines.append("|---------|----------|---------|--------|\n")
- downloaded = 0
- for i, v in enumerate(voices):
- url = v['url']
- voice_param = v['voice']
- name = v['name']
- scene = v['scene']
-
- # 文件名:场景_音色名_voice参数.mp3
- safe_name = f"{scene}_{name}_{voice_param}" if scene else f"{name}_{voice_param}"
- safe_name = re.sub(r'[\\/:*?"<>|]', '_', safe_name)
- fname = f"{safe_name}.mp3"
- fpath = os.path.join(OUTPUT_DIR, fname)
-
- index_lines.append(f"| {name} | `{voice_param}` | {scene} | [{fname}](audio/{fname}) |\n")
-
- if os.path.exists(fpath):
- print(f" [{i+1}/{len(voices)}] 跳过(已存在): {fname}")
- downloaded += 1
- continue
-
- try:
- print(f" [{i+1}/{len(voices)}] 下载: {voice_param} -> {fname}")
- resp = requests.get(url, timeout=30)
- if resp.status_code == 200:
- with open(fpath, 'wb') as f:
- f.write(resp.content)
- downloaded += 1
- else:
- print(f" HTTP {resp.status_code}")
- except Exception as e:
- print(f" 错误: {e}")
- time.sleep(0.3)
- # 写索引文件
- index_path = os.path.join(OUTPUT_DIR, "INDEX.md")
- with open(index_path, 'w', encoding='utf-8') as f:
- f.writelines(index_lines)
- print(f"\n完成!下载 {downloaded}/{len(voices)} 个音色到 {OUTPUT_DIR}/")
|