playreel/backend/routers/view.py

88 lines
3.0 KiB
Python

"""잡 행을 프론트가 그리는 모양으로 옮김
필드는 web/lib/api.ts 의 Job, web/lib/playreel.ts 의 PlayreelJob 과 맞춤
"""
from models.motion import MotionPlan
from models.pipeline_state import PlayreelState, PosterAliveState, stage_keys
from pipelines.gate import build_review
from pipelines.playreel import thumbnail_url
from tables.task import PlayreelTask, PosterAliveTask
def current_stage(task) -> str | None:
return next((key for key, entry in (task.stage_timings or {}).items()
if entry["status"] == "running"), None)
def error_view(task) -> dict | None:
if not task.error_stage:
return None
return {"stage": task.error_stage, "detail": task.error_detail or ""}
def motion_elements(motion_plan: dict | None) -> list[str] | None:
if not motion_plan:
return None
return [item.motion for item in MotionPlan.model_validate(motion_plan).kept]
IDLE = {"status": "idle", "started": None, "ended": None}
# 이름은 narration_text 가 포스터에서 읽어 채운다. 그 전까지 화면에 쓸 말
UNNAMED = "이름 없는 행사"
def ordered_stages(task, state_type) -> dict:
"""스테퍼가 키 순서대로 그리므로 실행 순서로 다시 세운다.
JSON 객체는 순서를 담는 자리가 아니고, 순서의 정본은 state enum이다.
"""
stored = task.stage_timings or {}
return {key: stored.get(key, IDLE) for key in stage_keys(state_type)}
def base_view(task, state_type) -> dict:
return {
"id": task.id,
"name": task.name or UNNAMED,
"status": task.status,
"stage": current_stage(task),
"stages": ordered_stages(task, state_type),
"error": error_view(task),
"created_at": task.created_at.timestamp(),
"credits_used": task.credits_used,
"queue_size": 0,
}
def poster_alive_view(task: PosterAliveTask) -> dict:
return {
**base_view(task, PosterAliveState),
"kind": "f1",
"narration": task.narration_lines,
"motion_elements": motion_elements(task.motion_plan),
"metadata": task.poster_metadata,
"template_id": None,
"poster_size": [task.poster_width, task.poster_height],
"low_res": task.is_low_resolution,
"artifacts": {key: url for key, url in (
("video", task.video_url),
("thumbnail", task.thumbnail_url),
("check_jpg", task.detect_check_url),
) if url},
}
def playreel_view(task: PlayreelTask) -> dict:
return {
**base_view(task, PlayreelState),
"kind": "playreel",
"source": {"url": task.source_url, "goods_id": task.goods_id, "slug": task.slug},
"gate": task.gate,
"review": build_review(task, task.gate) if task.gate else None,
"version": task.version,
"narration": [line["text"] for line in task.narration_lines or []] or None,
"metadata": None,
"artifacts": {key: url for key, url in (
("video", task.video_url),
("thumbnail", thumbnail_url(task)),
) if url},
}