Files
xiaoxia-saas/packages/domain/edit_template.py
T
用户CI Test 9287ab9e3f
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 9s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 7s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1650h38m52s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1650h38m54s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1650h38m54s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1650h47m53s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 1650h47m55s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1650h47m55s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 1650h47m57s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1651h10m23s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Failing after 1651h10m25s
CI/CD Pipeline / Build Production Runtime Images (pull_request) Failing after 1651h10m25s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Failing after 1651h19m24s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1651h19m26s
feat: 扩展剪辑模板体系 + 实现剪辑计划生成器
- EditTemplate 新增 editing_mode 字段,支持四种剪辑模式
  (one_take/pip/voice_over/voice_pip)
- config_schemas 扩展:editing_mode + transition_enabled
- 新建 PlanGeneratorService:基于模板+素材自动生成 EditPlan
  - ONE_TAKE: 素材顺序分配给 main clips
  - PIP: 第1个素材→main,其余→overlay
  - VOICE_OVER: 素材→main clips (B-roll)
  - VOICE_PIP: 第1个→background, 第2个→corner_voice, 其余→b_roll
- 新增 POST /edit-plans/generate-from-template API 端点
- Alembic 迁移 035:edit_templates 表加 editing_mode 列
- 单元测试 32 个(14 个计划生成器 + 18 个模板 editing_mode)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 20:40:57 +08:00

105 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""EditTemplate domain entity for Phase 8 模板编排引擎."""
from __future__ import annotations
import sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
if sys.version_info >= (3, 11):
from enum import StrEnum
else:
from enum import Enum
class StrEnum(str, Enum):
pass
from typing import Any
from uuid import uuid4
from .editing_mode import EditingMode
class EditTemplateStatus(StrEnum):
"""模板状态"""
ACTIVE = "active"
INACTIVE = "inactive"
_VALID_EDITING_MODES = {m.value for m in EditingMode}
@dataclass(slots=True)
class EditTemplate:
"""Phase 8 剪辑模板实体
全局模板库中的模板,定义剪辑风格、配置参数和预览信息。
不绑定到具体项目,可被多个 EditPlan 引用。
editing_mode 指定模板对应的剪辑模式(one_take / pip / voice_over / voice_pip),
决定剪辑计划生成时的片段结构。
"""
id: str
name: str
description: str = ""
template_type: str = "default"
editing_mode: str = EditingMode.ONE_TAKE.value
config: dict[str, Any] = field(default_factory=dict)
preview_url: str = ""
sort_weight: int = 0
status: EditTemplateStatus = EditTemplateStatus.ACTIVE
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
@classmethod
def create(
cls,
name: str,
*,
description: str = "",
template_type: str = "default",
editing_mode: str = EditingMode.ONE_TAKE.value,
config: dict[str, Any] | None = None,
preview_url: str = "",
sort_weight: int = 0,
status: EditTemplateStatus = EditTemplateStatus.ACTIVE,
) -> EditTemplate:
"""创建新模板实例"""
clean_name = name.strip()
if not clean_name:
raise ValueError("模板名称不能为空")
clean_mode = editing_mode.strip() or EditingMode.ONE_TAKE.value
if clean_mode not in _VALID_EDITING_MODES:
raise ValueError(
f"无效的 editing_mode: {clean_mode}," f"允许值: {', '.join(sorted(_VALID_EDITING_MODES))}"
)
return cls(
id=uuid4().hex,
name=clean_name,
description=description.strip(),
template_type=template_type.strip() or "default",
editing_mode=clean_mode,
config=config or {},
preview_url=preview_url.strip(),
sort_weight=sort_weight,
status=status,
)
def activate(self) -> None:
"""激活模板"""
self.status = EditTemplateStatus.ACTIVE
self.updated_at = datetime.now(timezone.utc)
def deactivate(self) -> None:
"""停用模板"""
self.status = EditTemplateStatus.INACTIVE
self.updated_at = datetime.now(timezone.utc)
@property
def is_active(self) -> bool:
"""模板是否处于激活状态"""
return self.status == EditTemplateStatus.ACTIVE