92 lines
3.4 KiB
Python
92 lines
3.4 KiB
Python
"""Pydantic schemas for the Higgsfield Shorts wrapper.
|
|
|
|
VideoSpec mirrors the Remotion data contract (remotion/src/data/mumum.ts) 1:1.
|
|
The LLM (spec_builder) fills VideoSpec; Higgsfield consumes higgsfield_prompt;
|
|
Remotion consumes the rest (hook / selling_point / brand_lines / end_card).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Literal, Optional
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# ---------- Inbound: interview answers (no complex analysis) ----------
|
|
class GenerateRequest(BaseModel):
|
|
kind: Literal["place", "product", "message"]
|
|
biz_name: str = Field(..., description="업체명·상품명·메시지 제목")
|
|
addr: Optional[str] = Field(None, description="주소 또는 판매 사이트 URL")
|
|
price: Optional[str] = Field(None, description="가격 정보")
|
|
selling: str = Field(..., description="주인/마케터가 생각하는 강력한 한방 셀링포인트")
|
|
|
|
|
|
# ---------- VideoSpec sub-objects (mirror mumum.ts) ----------
|
|
class Hook(BaseModel):
|
|
eyebrow: str
|
|
title: str
|
|
|
|
|
|
class SellingPoint(BaseModel):
|
|
items: list[str] = Field(..., description="3개 독립 배지 카피")
|
|
|
|
|
|
class EndCard(BaseModel):
|
|
brand: str
|
|
location: str
|
|
disclosure: str = "실제 사진 기반, AI 카메라 효과를 적용한 영상입니다."
|
|
|
|
|
|
class VideoSpec(BaseModel):
|
|
# 에너지 프로파일 → Remotion 리듬/트랜지션 기본값 결정
|
|
profile: Literal["Still Cinema", "Rhythm Reveal", "Maximum Viral"]
|
|
# Higgsfield marketing_studio_video 프롬프트 (유형별 톤)
|
|
higgsfield_prompt: str
|
|
hook: Hook
|
|
selling_point: SellingPoint
|
|
brand_lines: list[str] = Field(..., description="감성 카피 2줄")
|
|
end_card: EndCard
|
|
caption: str = Field(..., description="업로드용 캡션+해시태그")
|
|
|
|
|
|
# ---------- Outbound: 자막 스크립트 4블록 ----------
|
|
class ScriptResult(BaseModel):
|
|
intro: str = Field(..., description="인트로 (후킹)")
|
|
selling: str = Field(..., description="셀링포인트")
|
|
story: str = Field(..., description="감성 스토리")
|
|
cta: str = Field(..., description="CTA")
|
|
|
|
|
|
# ---------- Outbound: final result ----------
|
|
class GenerateResult(BaseModel):
|
|
video_url: str
|
|
caption: str
|
|
profile: str
|
|
cost_credits: float = 0.0
|
|
job_id: Optional[str] = None
|
|
|
|
|
|
# ---------- Outbound: 갤러리용 완료 영상 메타데이터 ----------
|
|
class VideoMeta(BaseModel):
|
|
job_id: str
|
|
video_url: str
|
|
biz_name: Optional[str] = None
|
|
caption: Optional[str] = None
|
|
profile: Optional[str] = None
|
|
created_at: float = 0.0 # Unix timestamp
|
|
|
|
|
|
# ---------- Outbound: 비동기 작업 상태 (폴링) ----------
|
|
class JobStatus(BaseModel):
|
|
job_id: str
|
|
# queued: 큐 대기 / running: 생성 중 / done: 완료 / error: 실패
|
|
status: Literal["queued", "running", "done", "error"]
|
|
stage: Optional[str] = Field(None, description="현재 단계: spec | higgsfield | remotion")
|
|
stage_index: int = Field(0, description="단계 인덱스 0..2 (프론트 진행바 매핑)")
|
|
progress: int = Field(0, description="전체 진행률 0..100 (대략)")
|
|
# 완료 시 채워지는 결과 필드 (GenerateResult 와 동일 의미)
|
|
video_url: Optional[str] = None
|
|
caption: Optional[str] = None
|
|
profile: Optional[str] = None
|
|
cost_credits: float = 0.0
|
|
# 실패 시 사용자에게 보여줄 메시지
|
|
error: Optional[str] = None
|