""" SQLAlchemy ORM 모델 정의 모듈. TranscriptionRecord (1) : (N) TranscriptionSegment 관계를 구성합니다. """ from datetime import datetime, timezone from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Text, Boolean from sqlalchemy.orm import relationship from app.db.database import Base class TranscriptionRecord(Base): """STT 변환 1건 전체 기록 테이블""" __tablename__ = "transcription_records" id = Column(Integer, primary_key=True, index=True) filename = Column(String(512), nullable=False, comment="원본 업로드 파일명") full_text = Column(Text, nullable=True, comment="전체 변환 텍스트") language = Column(String(16), nullable=True, comment="인식된 언어 코드") base_datetime = Column(DateTime(timezone=True), nullable=True, comment="녹음 시작 절대 시간(KST)") processing_time_sec = Column(Float, nullable=True, comment="STT 처리 소요 시간 (초)") audio_duration_sec = Column(Float, nullable=True, comment="오디오 총 길이 (초)") peak_memory_mb = Column(Float, nullable=True, comment="최대 메모리 점유율 (MB)") process_speed_x = Column(Float, nullable=True, comment="처리 속도 배수") # ── LLM 분석 결과 컬럼 ─────────────────────────────────────────────────── title = Column(String(256), nullable=True, comment="LLM 생성 제목") summary = Column(Text, nullable=True, comment="LLM 생성 1줄 요약") keywords = Column(String(512), nullable=True, comment="LLM 생성 키워드 (쉼표 구분)") urgency = Column(String(16), nullable=True, comment="LLM 판단 긴급도 (긴급/일반)") created_at = Column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False, comment="레코드 생성 시각 (UTC)" ) # 1:N 관계 segments = relationship( "TranscriptionSegment", back_populates="record", cascade="all, delete-orphan", lazy="select" ) class TranscriptionSegment(Base): """STT 변환 세그먼트(발화 단위) 테이블""" __tablename__ = "transcription_segments" id = Column(Integer, primary_key=True, index=True) record_id = Column(Integer, ForeignKey("transcription_records.id", ondelete="CASCADE"), nullable=False) start_sec = Column(Float, nullable=False, comment="발화 시작 시간 (초)") end_sec = Column(Float, nullable=False, comment="발화 종료 시간 (초)") text = Column(Text, nullable=True, comment="교정된 발화 텍스트") speaker = Column(String(32), nullable=True, comment="발화자 식별 결과") absolute_start_time = Column(String(64), nullable=True, comment="ISO 8601 절대 시작 시간") absolute_end_time = Column(String(64), nullable=True, comment="ISO 8601 절대 종료 시간") audio_path = Column(String(512), nullable=True, comment="Opus 압축본 로컬 경로") is_reviewed = Column( Boolean, default=False, nullable=False, comment="수동 검토 완료 여부 (불명 세그먼트 후처리 추적용)" ) # N:1 역참조 record = relationship("TranscriptionRecord", back_populates="segments")