166 lines
5.2 KiB
Python
166 lines
5.2 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 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,
|
|
)
|