#!/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}/")