75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
"""
|
|
STT 이력 조회용 Pydantic 응답 스키마 모듈.
|
|
ORM 모델(app/db/models.py)과 분리하여 API 계층의 직렬화 규격을 관리합니다.
|
|
"""
|
|
from pydantic import BaseModel, Field, ConfigDict
|
|
from typing import Optional, List
|
|
from datetime import datetime
|
|
|
|
|
|
class SegmentSchema(BaseModel):
|
|
"""TranscriptionSegment ORM → JSON 직렬화 스키마"""
|
|
model_config = ConfigDict(from_attributes=True) # Pydantic v2: ORM 객체 직렬화 허용
|
|
|
|
id: int
|
|
start_sec: float
|
|
end_sec: float
|
|
text: Optional[str]
|
|
speaker: Optional[str]
|
|
absolute_start_time: Optional[str]
|
|
absolute_end_time: Optional[str]
|
|
|
|
|
|
class RecordListResponse(BaseModel):
|
|
"""TranscriptionRecord ORM → JSON 직렬화 스키마 (세그먼트 포함)"""
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: int
|
|
filename: str
|
|
full_text: Optional[str]
|
|
language: Optional[str]
|
|
base_datetime: Optional[datetime]
|
|
processing_time_sec: Optional[float]
|
|
audio_duration_sec: Optional[float]
|
|
peak_memory_mb: Optional[float]
|
|
process_speed_x: Optional[float]
|
|
# LLM 메타데이터
|
|
title: Optional[str] = None
|
|
summary: Optional[str] = None
|
|
keywords: Optional[str] = None
|
|
urgency: Optional[str] = None
|
|
created_at: datetime
|
|
segments: List[SegmentSchema] = Field(default_factory=list)
|
|
|
|
|
|
class RecordPageResponse(BaseModel):
|
|
"""페이징이 적용된 목록 조회 응답 래퍼"""
|
|
total: int = Field(..., description="필터 조건에 해당하는 전체 레코드 수")
|
|
skip: int = Field(..., description="현재 오프셋")
|
|
limit: int = Field(..., description="현재 페이지 크기")
|
|
records: List[RecordListResponse] = Field(default_factory=list)
|
|
|
|
|
|
class DailySegmentResponse(BaseModel):
|
|
"""일자별 채팅 뷰용 세그먼트 평면 응답 스키마"""
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: int
|
|
record_id: int
|
|
start_sec: float
|
|
end_sec: float
|
|
text: Optional[str]
|
|
speaker: Optional[str]
|
|
is_reviewed: bool = False
|
|
absolute_start_time: Optional[str] = Field(None, description="ISO 8601 발화 절대 시작 시간")
|
|
absolute_end_time: Optional[str] = Field(None, description="ISO 8601 발화 절대 종료 시간")
|
|
|
|
|
|
class DailySegmentPage(BaseModel):
|
|
"""Cursor 기반 페이지네이션 래퍼 — COUNT(*) 없이 인덱스만 사용."""
|
|
items: List[DailySegmentResponse] = Field(..., description="세그먼트 목록")
|
|
next_cursor: Optional[int] = Field(None, description="다음 페이지 시작 커서 (마지막 item의 id). None이면 마지막 페이지.")
|
|
has_more: bool = Field(..., description="다음 페이지 존재 여부")
|
|
|
|
|