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.
8.1 KiB
8.1 KiB
AI Service 集成 FileStorageService
日期: 2026-01-30
类型: Feature Enhancement
影响范围: AI Service, AI Tasks, File Storage
关联文档: docs/requirements/backend/04-services/ai/ai-service.md
变更概述
为 AI 生成任务集成 FileStorageService,实现 AI 生成文件的自动下载和上传到自有对象存储(MinIO/OSS),解决 AI 提供商临时 URL 时效性问题,确保数据主权和文件持久化。
变更动机
问题
- 临时 URL 时效性:AI 提供商(如 OpenAI)返回的文件 URL 通常只有 1 小时有效期
- 数据主权缺失:生成的内容存储在第三方服务器,无法完全控制
- 无法去重:重复生成相同内容时无法利用已有文件
- 引用计数缺失:无法追踪文件被哪些资源引用
解决方案
- 在每个 AI 生成任务完成后,自动下载文件并上传到 FileStorageService
- 利用 SHA256 校验和实现文件去重
- 使用引用计数管理文件生命周期
- 支持 MinIO(开发环境)和云 OSS(生产环境)无缝切换
技术实现
1. 新增依赖
在 ai_tasks.py 中添加:
import httpx # 用于下载 AI 生成的文件
from app.services.file_storage_service import FileStorageService
2. 新增辅助函数
_download_and_upload_file()
async def _download_and_upload_file(
file_url: str,
filename: str,
content_type: str,
category: str,
user_id: str
) -> Dict[str, Any]
功能:
- 使用
httpx.AsyncClient下载 AI 提供商返回的文件 - 调用
FileStorageService.upload_file()上传到自有 OSS - 返回文件元数据(包含自有 URL、校验和、文件大小等)
超时设置:300 秒(5 分钟),适配大文件下载
3. 更新所有生成任务
为以下 5 个任务添加文件上传逻辑:
图片生成任务 (generate_image_task)
- 进度: 30% → 70% → 100%
- 文件类型:
image/png - 存储路径:
ai-generated/images/ - 文件名:
image_{job_id}.png
视频生成任务 (generate_video_task)
- 进度: 30% → 70% → 100%
- 文件类型:
video/mp4 - 存储路径:
ai-generated/videos/ - 文件名:
video_{job_id}.mp4
音效生成任务 (generate_sound_task)
- 进度: 30% → 70% → 100%
- 文件类型:
audio/mpeg - 存储路径:
ai-generated/sounds/ - 文件名:
sound_{job_id}.mp3
配音生成任务 (generate_voice_task)
- 进度: 30% → 70% → 100%
- 文件类型:
audio/mpeg - 存储路径:
ai-generated/voices/ - 文件名:
voice_{job_id}.mp3
字幕生成任务 (generate_subtitle_task)
- 进度: 30% → 70% → 100%
- 文件类型:
text/plain - 存储路径:
ai-generated/subtitles/ - 文件名:
subtitle_{job_id}.srt
文本处理任务 (process_text_task)
- 进度: 30% → 70% → 100%
- 文件类型:
text/plain - 存储路径:
ai-generated/texts/ - 文件名:
text_{job_id}.txt - 说明: 文本处理任务通常不返回文件,但为了完整性也添加了处理逻辑
4. 输出数据格式
更新后的 output_data 包含以下字段:
{
"file_url": "https://minio.example.com/ai-generated/images/xxx.png",
"file_size": 1024000,
"checksum": "abc123...",
"mime_type": "image/png",
"storage_provider": "minio",
"storage_path": "ai-generated/images/user_id/checksum.png",
"original_url": "https://openai.com/temp/xxx.png"
}
字段说明:
file_url: 自有 OSS URL(永久有效)file_size: 文件大小(字节)checksum: SHA256 校验和(用于去重)mime_type: MIME 类型storage_provider: 存储提供商(minio/oss)storage_path: 对象存储路径original_url: AI 提供商原始 URL(保留用于调试)
5. 日志格式修复
将所有日志从 f-string 格式改为 %-formatting:
# ❌ 错误
logger.info(f"任务完成: job_id={job_id}")
# ✅ 正确
logger.info("任务完成: job_id=%s", job_id)
文件修改清单
修改文件
server/app/tasks/ai_tasks.py- 添加
httpx导入 - 添加
FileStorageService导入 - 新增
_download_and_upload_file()函数 - 更新 6 个生成任务的文件上传逻辑
- 修复所有日志格式为 %-formatting
- 添加
新增文件
docs/server/changelogs/2026-01-30-ai-service-file-storage-integration.md
测试建议
单元测试
# 测试文件下载和上传
async def test_download_and_upload_file():
# Mock httpx.AsyncClient
# Mock FileStorageService
# 验证文件元数据
pass
集成测试
# 测试完整的图片生成流程
async def test_generate_image_with_file_storage(async_client, test_auth):
# 1. 调用图片生成 API
# 2. 等待任务完成
# 3. 验证 output_data 包含 file_url
# 4. 验证文件可以访问
# 5. 验证 file_checksum 表有记录
pass
手动测试
# 1. 启动服务
docker-compose up -d
# 2. 调用图片生成 API
curl -X POST http://localhost:8000/api/v1/ai/generate/image \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A beautiful sunset",
"width": 1024,
"height": 1024
}'
# 3. 查询任务状态
curl http://localhost:8000/api/v1/ai/jobs/{job_id} \
-H "Authorization: Bearer $TOKEN"
# 4. 验证 MinIO 中是否有文件
# 访问 http://localhost:9001 (MinIO Console)
# 用户名: minioadmin, 密码: minioadmin
环境配置
开发环境(MinIO)
STORAGE_PROVIDER=minio
MINIO_ENDPOINT=minio:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET=jointo
MINIO_SECURE=false
生产环境(阿里云 OSS)
STORAGE_PROVIDER=oss
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_ACCESS_KEY_ID=your_access_key
OSS_ACCESS_KEY_SECRET=your_secret_key
OSS_BUCKET=jointo-prod
性能考虑
下载超时
- 设置 300 秒超时,适配大文件(如 4K 视频)
- 如果下载失败,任务会自动重试(最多 3 次)
文件去重
- 使用 SHA256 校验和去重,避免重复存储
- 相同内容的文件只存储一次,节省存储空间
引用计数
- 每次使用文件时增加引用计数
- 删除资源时减少引用计数
- 引用计数为 0 时自动删除文件
后续优化
短期(1-2 周)
- 添加文件压缩(图片、视频)
- 添加缩略图生成(图片、视频)
- 添加文件格式转换(如 PNG → WebP)
中期(1-2 月)
- 实现 CDN 加速
- 添加文件访问统计
- 实现文件分级存储(热数据/冷数据)
长期(3-6 月)
- 实现多云存储(阿里云 + 腾讯云)
- 添加文件加密存储
- 实现文件版本管理
风险与注意事项
风险
-
下载失败:AI 提供商 URL 可能失效或网络不稳定
- 缓解措施:设置重试机制(最多 3 次)
-
存储空间不足:大量生成文件可能占用大量存储
- 缓解措施:定期清理无引用文件(30 天)
-
并发冲突:多个任务同时上传相同文件
- 缓解措施:使用校验和去重,数据库唯一约束
注意事项
- 确保 MinIO/OSS 服务正常运行
- 确保网络可以访问 AI 提供商的文件 URL
- 监控存储空间使用情况
- 定期备份重要文件
相关文档
总结
此次集成完成了 AI Service 与 FileStorageService 的深度整合,实现了:
- ✅ AI 生成文件自动下载和上传
- ✅ 文件去重和引用计数
- ✅ 支持 MinIO 和云 OSS
- ✅ 完整的错误处理和重试机制
- ✅ 符合 jointo-tech-stack 规范
所有 AI 生成的文件现在都会永久存储在自有系统中,解决了临时 URL 时效性问题,确保了数据主权和文件持久化。