Files
meijiaka-zy/python-api/app/api/v1/materials.py
T
小鱼开发 447f3c2ffe feat: 空镜素材系统数据库化 + 修复积分不足弹窗叠加
后端:
- 新增 BrollCategory/BrollMaterial/BrollTag 模型及表(mjk_categories/materials/tags)
- 新增 Alembic 迁移 69274ce979a5
- 新增 broll_category/broll_material CRUD 层
- 重构 material_service:删除 JSON 配置,改用 PostgreSQL + Redis 去重
- 新增 /materials/batch-match 接口,删除 /materials/reload
- usage_count 原子递增,Redis 失败自动降级

前端:
- materials API 改为 projectId 去重,新增 batchMatch
- VideoGeneration 批量匹配改用 batchMatch,删除 usedUrls 手动维护
- 修复积分不足时进度弹窗与充值弹窗叠加的 bug
- 操作前预检积分,不足时显示提示条+立即充值按钮
2026-05-11 17:40:38 +08:00

88 lines
2.3 KiB
Python

"""
空镜素材 API
============
提供空镜素材匹配接口(基于 PostgreSQL + Redis 去重)。
"""
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.session import get_db
from app.schemas.common import ApiResponse, success_response
from app.schemas.materials import (
BatchMatchMaterialRequest,
BatchMatchMaterialResponse,
MatchMaterialRequest,
MaterialInfo,
)
from app.services.material_service import batch_match, match_material
router = APIRouter()
@router.post("/match", response_model=ApiResponse[MaterialInfo | None])
async def match_material_endpoint(
request: MatchMaterialRequest,
db: AsyncSession = Depends(get_db),
):
"""
根据场景描述和所需时长匹配空镜素材
返回匹配到的素材信息,无匹配返回 data: null
"""
result = await match_material(
db,
scene=request.scene,
required_duration=request.duration,
project_id=request.project_id,
)
if result is None:
return success_response(data=None, message="未匹配到素材")
await db.commit()
return success_response(
data=MaterialInfo(url=result["url"], duration=result["duration"]),
message="匹配成功",
)
@router.post("/batch-match", response_model=ApiResponse[BatchMatchMaterialResponse])
async def batch_match_materials_endpoint(
request: BatchMatchMaterialRequest,
db: AsyncSession = Depends(get_db),
):
"""
批量匹配空镜素材
根据分镜列表一次性匹配所有素材,自动进行项目级去重。
"""
raw_scenes = [
{"scene": s.scene, "duration": s.duration} for s in request.scenes
]
results = await batch_match(
db,
scenes=raw_scenes,
project_id=request.project_id,
)
matched: list[MaterialInfo | None] = [
MaterialInfo(url=r["url"], duration=r["duration"]) if r else None
for r in results
]
await db.commit()
success_count = sum(1 for r in matched if r is not None)
return success_response(
data=BatchMatchMaterialResponse(
project_id=request.project_id,
results=matched,
),
message=f"批量匹配完成,成功 {success_count}/{len(matched)}",
)