o2o-castad-backend/app/lyric/schemas/lyric.py

225 lines
6.9 KiB
Python

"""
Lyric API Schemas
이 모듈은 가사 관련 API 엔드포인트에서 사용되는 Pydantic 스키마를 정의합니다.
사용 예시:
from app.lyric.schemas.lyric import (
LyricStatusResponse,
LyricDetailResponse,
LyricListItem,
PaginatedResponse,
)
# 라우터에서 response_model로 사용
@router.get("/lyric/{task_id}", response_model=LyricDetailResponse)
async def get_lyric(task_id: str):
...
# 페이지네이션 응답 (다른 모델에서도 재사용 가능)
@router.get("/songs", response_model=PaginatedResponse[SongListItem])
async def list_songs(...):
...
"""
import math
from datetime import datetime
from typing import Generic, List, Optional, TypeVar
from pydantic import BaseModel, Field
class GenerateLyricRequest(BaseModel):
"""가사 생성 요청 스키마
Usage:
POST /lyric/generate
Request body for generating lyrics.
Example Request:
{
"customer_name": "스테이 머뭄",
"region": "군산",
"detail_region_info": "군산 신흥동 말랭이 마을",
"language": "Korean"
}
"""
model_config = {
"json_schema_extra": {
"example": {
"customer_name": "스테이 머뭄",
"region": "군산",
"detail_region_info": "군산 신흥동 말랭이 마을",
"language": "Korean",
}
}
}
customer_name: str = Field(..., description="고객명/가게명")
region: str = Field(..., description="지역명")
detail_region_info: Optional[str] = Field(None, description="상세 지역 정보")
language: str = Field(
default="Korean",
description="가사 출력 언어 (Korean, English, Chinese, Japanese, Thai, Vietnamese)",
)
class GenerateLyricResponse(BaseModel):
"""가사 생성 응답 스키마
Usage:
POST /lyric/generate
Returns the generated lyrics.
Example Response:
{
"success": true,
"lyric": "생성된 가사...",
"language": "Korean",
"prompt_used": "..."
}
"""
success: bool = Field(..., description="생성 성공 여부")
lyric: Optional[str] = Field(None, description="생성된 가사")
language: str = Field(..., description="가사 언어")
prompt_used: Optional[str] = Field(None, description="사용된 프롬프트")
error_message: Optional[str] = Field(None, description="에러 메시지 (실패 시)")
class LyricStatusResponse(BaseModel):
"""가사 상태 조회 응답 스키마
Usage:
GET /lyric/status/{task_id}
Returns the current processing status of a lyric generation task.
Example Response:
{
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
"status": "completed",
"message": "가사 생성이 완료되었습니다."
}
"""
task_id: str = Field(..., description="작업 고유 식별자")
status: str = Field(..., description="처리 상태 (processing, completed, failed)")
message: str = Field(..., description="상태 메시지")
class LyricDetailResponse(BaseModel):
"""가사 상세 조회 응답 스키마
Usage:
GET /lyric/{task_id}
Returns the generated lyric content for a specific task.
Example Response:
{
"id": 1,
"task_id": "019123ab-cdef-7890-abcd-ef1234567890",
"project_id": 1,
"status": "completed",
"lyric_prompt": "...",
"lyric_result": "생성된 가사...",
"created_at": "2024-01-01T12:00:00"
}
"""
id: int = Field(..., description="가사 ID")
task_id: str = Field(..., description="작업 고유 식별자")
project_id: int = Field(..., description="프로젝트 ID")
status: str = Field(..., description="처리 상태")
lyric_prompt: str = Field(..., description="가사 생성 프롬프트")
lyric_result: Optional[str] = Field(None, description="생성된 가사")
created_at: Optional[datetime] = Field(None, description="생성 일시")
class LyricListItem(BaseModel):
"""가사 목록 아이템 스키마
Usage:
Used as individual items in paginated lyric list responses.
"""
id: int = Field(..., description="가사 ID")
task_id: str = Field(..., description="작업 고유 식별자")
status: str = Field(..., description="처리 상태")
lyric_result: Optional[str] = Field(None, description="생성된 가사 (미리보기)")
created_at: Optional[datetime] = Field(None, description="생성 일시")
T = TypeVar("T")
class PaginatedResponse(BaseModel, Generic[T]):
"""페이지네이션 응답 스키마 (재사용 가능)
Usage:
다른 모델에서도 페이지네이션이 필요할 때 재사용 가능:
- PaginatedResponse[LyricListItem]
- PaginatedResponse[SongListItem]
- PaginatedResponse[VideoListItem]
Example:
from app.lyric.schemas.lyric import PaginatedResponse
@router.get("/items", response_model=PaginatedResponse[ItemModel])
async def get_items(page: int = 1, page_size: int = 20):
...
Example Response:
{
"items": [...],
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5,
"has_next": true,
"has_prev": false
}
"""
items: List[T] = Field(..., description="데이터 목록")
total: int = Field(..., description="전체 데이터 수")
page: int = Field(..., description="현재 페이지 (1부터 시작)")
page_size: int = Field(..., description="페이지당 데이터 수")
total_pages: int = Field(..., description="전체 페이지 수")
has_next: bool = Field(..., description="다음 페이지 존재 여부")
has_prev: bool = Field(..., description="이전 페이지 존재 여부")
@classmethod
def create(
cls,
items: List[T],
total: int,
page: int,
page_size: int,
) -> "PaginatedResponse[T]":
"""페이지네이션 응답을 생성하는 헬퍼 메서드
Args:
items: 현재 페이지의 데이터 목록
total: 전체 데이터 수
page: 현재 페이지 번호
page_size: 페이지당 데이터 수
Returns:
PaginatedResponse: 완성된 페이지네이션 응답
Usage:
items = [LyricListItem(...) for lyric in lyrics]
return PaginatedResponse.create(items, total=100, page=1, page_size=20)
"""
total_pages = math.ceil(total / page_size) if total > 0 else 1
return cls(
items=items,
total=total,
page=page,
page_size=page_size,
total_pages=total_pages,
has_next=page < total_pages,
has_prev=page > 1,
)