87 lines
3.0 KiB
Python
87 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 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", task.analysis_grid_url),
|
|
) if url},
|
|
}
|