Files
meijiaka-zy/python-api/scripts/upload_preset_voice_previews.py
T
小鱼开发 67e73b5a51 feat: 素材库重构、七牛上传修复、配音页面优化、MiniMax后端接入
- 素材库: VoiceMaterialLibrary 支持音频/视频分类、Modal弹窗、进度弹窗
- 列表布局: 紧凑单行、灰色图标按钮、重命名功能、删除ConfirmModal
- 生成配音: toast替换为ProgressModal
- 私有音色显示: 描述改为createdAt日期
- 七牛上传: 修复upload_stream参数、修正put_stream参数名
- MiniMax后端: 新增Provider+Service,TTS/克隆/音色列表切到MiniMax
- 前端默认音色: tianxin_xiaoling
- Rust: 新增voice命令、本地音频存储、配音生成功能
- 新增shot统计组件、脚本编辑器优化
2026-04-21 23:27:08 +08:00

129 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""
上传官方预置音色试听音频到七牛云
================================================
KlingAI 已经为每个官方预置音色提供了 trial_url,我们直接下载这个音频
然后上传到七牛云存储,获取永久链接。
运行方式:
cd python-api
python scripts/upload_preset_voice_previews.py
"""
import asyncio
import tempfile
from pathlib import Path
import httpx
from app.config import get_settings
from app.services.qiniu_service import get_qiniu_service
from app.ai.providers.klingai_provider import KlingAIProvider
async def download_file(url: str, temp_path: Path) -> None:
"""下载文件到本地"""
async with httpx.AsyncClient(timeout=60.0) as client:
response = await client.get(url)
response.raise_for_status()
temp_path.write_bytes(response.content)
async def upload_all_previews():
"""下载所有官方预置音色试听并上传到七牛云"""
settings = get_settings()
qiniu = get_qiniu_service()
provider = KlingAIProvider({
"access_key": settings.KLINGAI_ACCESS_KEY or "",
"secret_key": settings.KLINGAI_SECRET_KEY or "",
})
# 获取官方预置音色列表
voices = await provider.list_preset_voices()
print(f"获取到 {len(voices)} 个官方预置音色\n")
description_map = {
"钓系女友": "甜美撒娇",
"温柔女声": "温柔细腻",
"播报男声": "沉稳播报",
"盐系少年": "清新少年",
"撒娇女友": "可爱撒娇",
}
results = []
for idx, voice in enumerate(voices, 1):
if voice.get("status") != "succeed":
print(f"[{idx}] 跳过 - 状态不为 succeed: {voice.get('status')}")
continue
voice_id = voice["voice_id"]
voice_name = voice["voice_name"]
trial_url = voice.get("trial_url")
if not trial_url:
print(f"[{idx}] {voice_name} - 没有 trial_url,跳过")
continue
print(f"[{idx}/{len(voices)}] 处理: {voice_name} ({voice_id})")
print(f" 原地址: {trial_url}")
# 下载到临时文件
ext = ".wav"
with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as f:
temp_path = Path(f.name)
try:
await download_file(trial_url, temp_path)
print(f" ✓ 下载完成 ({temp_path.stat().st_size / 1024:.1f} KB)")
# 上传到七牛云
key = f"meijiaka-zj/audios/{voice_id}{ext}"
result = qiniu.upload_file(
local_path=str(temp_path),
key=key,
file_type="audio",
check_duplicate=False,
)
final_url = result["url"]
print(f" ✓ 上传成功: {final_url}")
results.append({
"voice_id": voice_id,
"name": voice_name,
"description": description_map.get(voice_name, ""),
"previewUrl": final_url,
"language": "zh",
"recommended": voice_name == "温柔女声",
})
except Exception as e:
print(f" ✗ 失败: {str(e)}")
finally:
# 清理临时文件
if temp_path.exists():
temp_path.unlink()
print()
print("\n=== 最终结果 ===")
print("复制以下内容到 TTSService.PRESET_VOICES:")
print()
for r in results:
print(f" {{")
print(f" \"voice_id\": \"{r['voice_id']}\",")
print(f" \"name\": \"{r['name']}\",")
print(f" \"language\": \"{r['language']}\",")
print(f" \"description\": \"{r['description']}\",")
print(f" \"previewUrl\": \"{r['previewUrl']}\",")
print(f" \"recommended\": {str(r['recommended']).lower()},")
print(f" }},")
return results
if __name__ == "__main__":
asyncio.run(upload_all_previews())