Files
xiaoxia-saas/packages/domain/generation_task.py
T
Audit Bot f9e8d6efdc
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
fix: 修复 3 个 P0 端点 500 错误的真正根因
Bug 1 — GET /api/v1/assets → 500:
  asset_repository 所有方法为 async def,但调用方为同步上下文,
  未 await 导致返回 coroutine 对象而非实际数据。
  修复:全部改为 def(同步),与 SQLAlchemy 同步 Session 一致。

Bug 2 — POST /api/v1/generation/tasks → 500:
  GenerationTaskModel 仍定义 edit_plan_id 列,但迁移 011 已从数据库
  删除该列,INSERT 时报 column does not exist。
  修复:从 model、repository、domain entity、application use case、
  所有路由中彻底移除 edit_plan_id 引用。

Bug 3 — GET /api/v1/dashboard/overview → 500:
  generation_task_repository._to_domain() 访问 model.edit_plan_id,
  该列已被迁移 011 删除,触发 AttributeError。
  修复:同上,移除 edit_plan_id 引用。

涉及文件:
  - packages/adapters/sqlalchemy_impl/asset_repository.py (async→sync)
  - packages/ports/asset_repository.py (async→sync 接口)
  - packages/adapters/sqlalchemy_impl/models.py (移除 edit_plan_id 列)
  - packages/adapters/sqlalchemy_impl/generation_task_repository.py
  - packages/domain/generation_task.py
  - packages/application/generation_tasks.py
  - apps/api/app/api/routes/generation_tasks.py
  - apps/api/app/api/routes/task_center.py
2026-06-29 20:10:51 +08:00

67 lines
2.3 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import StrEnum
from uuid import uuid4
class GenerationTaskStatus(StrEnum):
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
@dataclass(slots=True)
class GenerationTask:
id: str
project_id: str
asset_library_id: str
strategy_id: str = ""
voice_library_id: str = ""
template_id: str = ""
asset_ids: list[str] = field(default_factory=list)
title_ids: list[str] = field(default_factory=list)
voice_ids: list[str] = field(default_factory=list)
status: GenerationTaskStatus = GenerationTaskStatus.PENDING
progress: float = 0.0
result_count: int = 0
error_message: str = ""
started_at: datetime | None = None
completed_at: datetime | None = None
created_by_user_id: str = ""
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
@classmethod
def create(
cls,
project_id: str,
asset_library_id: str,
*,
strategy_id: str = "",
voice_library_id: str = "",
template_id: str = "",
asset_ids: list[str] | None = None,
title_ids: list[str] | None = None,
voice_ids: list[str] | None = None,
created_by_user_id: str = "",
) -> "GenerationTask":
if not project_id.strip() and not template_id.strip():
raise ValueError("project_id 或 template_id 至少需要提供一个")
if not asset_library_id.strip() and not (asset_ids or title_ids or voice_ids):
raise ValueError("asset_library_id 或 asset_ids/title_ids/voice_ids 至少需要提供一个")
return cls(
id=uuid4().hex,
project_id=project_id.strip(),
asset_library_id=asset_library_id.strip(),
strategy_id=strategy_id.strip(),
voice_library_id=voice_library_id.strip(),
template_id=template_id.strip(),
asset_ids=list(asset_ids) if asset_ids else [],
title_ids=list(title_ids) if title_ids else [],
voice_ids=list(voice_ids) if voice_ids else [],
created_by_user_id=created_by_user_id.strip(),
)