You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.3 KiB
4.3 KiB
修复 ElevenLabs 音效生成 OSS 上传问题
日期: 2026-02-10
类型: Bug 修复
影响范围: AI 音效生成任务
问题描述
ElevenLabs 音效生成后未上传到 OSS,导致:
- 生成的音频文件无法访问
- 任务完成但
output_data中缺少file_url - 用户无法下载生成的音效
根本原因
-
ElevenLabs Provider 返回格式:
- 返回
{'audio_data': bytes, 'audio_url': None, ...} - 音频数据以二进制形式存储在
audio_data字段
- 返回
-
任务检查逻辑错误(
generate_sound_task):# ❌ 错误:只检查 'url' 字段 if result.get('url'): file_metadata = await _download_and_upload_file(...)- ElevenLabs 不返回
url字段,条件永远为 False - 跳过 OSS 上传逻辑
- ElevenLabs 不返回
-
不一致性:
generate_voice_task已正确处理audio_data字段generate_sound_task缺少相同逻辑
解决方案
修改 generate_sound_task
参考 generate_voice_task 的实现,添加 audio_data 检查逻辑:
# ✅ 修复后:优先检查 audio_data(二进制数据)
if result.get('audio_data'):
# 直接上传二进制数据到 MinIO
file_metadata = await _upload_file_from_bytes(
file_data=result['audio_data'],
filename=f"sound_{job_id}.mp3",
content_type='audio/mpeg',
category='ai-generated/sounds',
user_id=user_id
)
# 更新 result,移除 audio_data,添加文件元数据
result.pop('audio_data', None)
result.update(file_metadata)
elif result.get('url'):
# 兼容旧的 URL 方式(其他 Provider)
file_metadata = await _download_and_upload_file(...)
result.update(file_metadata)
处理流程
-
优先检查
audio_data(ElevenLabs 返回格式)- 使用
_upload_file_from_bytes()直接上传二进制数据 - 移除
audio_data字段(避免存储大量二进制数据) - 添加文件元数据(
file_url,file_size,checksum等)
- 使用
-
降级检查
url(兼容其他 Provider)- 使用
_download_and_upload_file()下载后上传 - 保持向后兼容性
- 使用
影响范围
修改文件
server/app/tasks/ai_tasks.py-generate_sound_task函数
受益功能
- ElevenLabs 音效生成(
/api/v1/ai/generate-sound) - 所有使用 ElevenLabs 的音效生成任务
兼容性
- ✅ 向后兼容:保留
url检查逻辑 - ✅ 不影响其他 Provider(OpenAI、Mock 等)
- ✅ 与
generate_voice_task逻辑一致
测试验证
测试步骤
-
调用音效生成 API:
docker exec jointo-server-app python -c " import asyncio from app.services.ai_providers.elevenlabs_provider import ElevenLabsProvider async def test(): provider = ElevenLabsProvider('elevenlabs-sound-v2') result = await provider.generate_sound_effect( text='Dog barking in the distance', duration_seconds=5.0 ) print(f'✅ 音效生成成功: {len(result[\"audio_data\"])} bytes') asyncio.run(test()) " -
检查任务输出:
- 查询
ai_jobs表的output_data字段 - 验证包含
file_url,file_size,checksum等字段
- 查询
-
验证文件可访问:
- 访问
file_url确认音频文件可下载 - 检查 MinIO 存储路径
ai-generated/sounds/source/2026/02/10/
- 访问
预期结果
{
"file_url": "/api/v1/files/ai-generated/sounds/source/2026/02/10/abc123.mp3",
"file_size": 81920,
"checksum": "abc123...",
"mime_type": "audio/mpeg",
"storage_provider": "minio",
"storage_path": "ai-generated/sounds/source/2026/02/10/abc123.mp3",
"duration": 5.0,
"metadata": {
"text": "Dog barking in the distance",
"duration_seconds": 5.0,
"audio_size": 81920
}
}
相关文档
- RFC 142: ElevenLabs 集成方案
- Changelog: 2026-02-10 ElevenLabs 集成实现
- 测试结果:
server/tests/manual/elevenlabs_test_results.md
后续优化
-
统一上传逻辑:
- 所有 AI 生成任务统一使用
audio_data优先策略 - 减少 URL 下载的网络开销
- 所有 AI 生成任务统一使用
-
添加单元测试:
- 测试
generate_sound_task的audio_data处理逻辑 - 测试
url降级逻辑
- 测试
-
监控告警:
- 监控 OSS 上传失败率
- 告警音频文件缺失情况