352221f199
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m0s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 2m42s
CI/CD Pipeline / Integration Tests (push) Successful in 3m50s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m35s
CI/CD Pipeline / Validate - Style (push) Successful in 4m42s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m29s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 43s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m5s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m10s
CI/CD Pipeline / Validate - Security (push) Successful in 11m12s
CI/CD Pipeline / Unit Tests (push) Successful in 11m18s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Failing after 27h18m15s
CI/CD Pipeline / Build Production API Image (push) Failing after 27h18m15s
CI/CD Pipeline / Frontend Lint (push) Failing after 27h29m35s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 27h24m8s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 27h28m58s
CI/CD Pipeline / PR Build API Image (push) Failing after 27h29m0s
CI/CD Pipeline / Deploy Production (push) Failing after 27h17m36s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 27h17m38s
CI/CD Pipeline / Build Production Web Image (push) Failing after 27h17m38s
CI/CD Pipeline / Canary Release to Production (push) Failing after 27h17m36s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 27h24m7s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 27h24m8s
CI/CD Pipeline / PR Build Web Image (push) Failing after 27h28m58s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 27h29m0s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
"""独立的从素材创建片段端点(不依赖 template_id 路径参数).
|
||
|
||
POST /api/v1/clips/from-assets
|
||
- 与 /api/v1/templates/{template_id}/editor/clips/from-assets 功能一致
|
||
- 区别:template_id 从 body 传入(可选),为空时后端自动创建/查找默认模板
|
||
- 解决前端首次加载时 templateId 为空导致双斜杠 404 的问题(P0 #1922)
|
||
- 内部复用 resolve_draft_plan_id 和 create_clips_from_assets_editor 的核心逻辑
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
|
||
from app.auth import AuthenticatedUser, get_current_user
|
||
from app.dependencies import get_asset_repository, get_db_session
|
||
from app.services.edit_plan_service import EditPlanService
|
||
from app.services.edit_template_service import EditTemplateService
|
||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
|
||
from sqlalchemy.orm import Session
|
||
|
||
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
|
||
|
||
from ._default_template import get_or_create_default_template_id
|
||
from .templates_editor.clips import create_clips_from_assets_editor
|
||
from .templates_editor.dependencies import resolve_draft_plan_id
|
||
from .templates_editor.schemas import ClipsFromAssetsRequest, ClipsFromAssetsResponse
|
||
|
||
logger = logging.getLogger(__name__)
|
||
router = APIRouter(tags=["Clips"])
|
||
|
||
|
||
class StandaloneClipsRequest(ClipsFromAssetsRequest):
|
||
"""扩展请求:template_id 可选(不传则后端自动兜底默认模板)。"""
|
||
|
||
template_id: str | None = None
|
||
|
||
|
||
def _get_editor_services_direct(db: Session) -> tuple[EditTemplateService, EditPlanService]:
|
||
"""直接构造服务实例(非 Depends 版本,供独立端点内部调用)。"""
|
||
return EditTemplateService(db), EditPlanService(db)
|
||
|
||
|
||
@router.post("/clips/from-assets", response_model=ClipsFromAssetsResponse)
|
||
def create_clips_from_assets(
|
||
body: StandaloneClipsRequest,
|
||
background_tasks: BackgroundTasks,
|
||
db: Session = Depends(get_db_session),
|
||
current_user: AuthenticatedUser = Depends(get_current_user),
|
||
asset_repo: SQLAlchemyAssetRepository = Depends(get_asset_repository),
|
||
) -> ClipsFromAssetsResponse:
|
||
"""从素材批量创建片段(template_id 可选,为空自动兜底)。"""
|
||
user_id = str(current_user.user.id)
|
||
services = _get_editor_services_direct(db)
|
||
|
||
# 1. 解析/兜底 template_id,拿到 plan_id
|
||
template_id = (body.template_id or "").strip()
|
||
if not template_id:
|
||
template_id = get_or_create_default_template_id(db, user_id)
|
||
if not template_id:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail="无法自动创建默认模板,请刷新页面重试",
|
||
)
|
||
plan_id = resolve_draft_plan_id(
|
||
template_id=template_id,
|
||
services=services,
|
||
current_user=current_user,
|
||
db=db,
|
||
auto_create_default=False, # 上面已兜底过
|
||
)
|
||
|
||
# 2. 构造标准化请求(去除独立端扩展字段),复用原端点核心逻辑
|
||
core_body = ClipsFromAssetsRequest(
|
||
asset_ids=body.asset_ids,
|
||
clip_type=body.clip_type,
|
||
clip_count=body.clip_count,
|
||
required_clips_count=body.required_clips_count,
|
||
)
|
||
|
||
# 3. 直接调用原端点函数(此时所有 Depends 依赖已手动传入)
|
||
return create_clips_from_assets_editor(
|
||
template_id=template_id,
|
||
body=core_body,
|
||
background_tasks=background_tasks,
|
||
plan_id=plan_id,
|
||
services=services,
|
||
asset_repo=asset_repo,
|
||
db=db,
|
||
current_user=current_user,
|
||
)
|