66 lines
2.8 KiB
Python
66 lines
2.8 KiB
Python
"""Модель SessionAudioTrack — записанный per-track аудиотрек участника сеанса.
|
|
|
|
Каждая строка соответствует одной аудио-дорожке (микрофону) одного участника
|
|
одного сеанса, записываемой отдельным LiveKit Track Egress. Диаризация не
|
|
нужна: трек = спикер, атрибуция — к `conference_participants` (ADR-002).
|
|
"""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import DateTime, Enum, ForeignKey, Index, String, Text, UniqueConstraint, text
|
|
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from models.base import Base
|
|
|
|
AudioTrackStatus = Enum(
|
|
"recording",
|
|
"recorded",
|
|
"transcribed",
|
|
"failed",
|
|
name="audio_track_status",
|
|
)
|
|
|
|
|
|
class SessionAudioTrack(Base):
|
|
"""Одна аудиодорожка сеанса, записанная LiveKit Track Egress в отдельный файл.
|
|
|
|
`status` — состояние per-track шага пайплайна (независимо от
|
|
`conference_sessions.pipeline_status`):
|
|
`recording` (egress запущен) -> `recorded` (файл финализирован по
|
|
`egress_ended`) -> `transcribed` (сегменты Whisper сохранены в `segments`)
|
|
либо `failed` на любом шаге.
|
|
"""
|
|
|
|
__tablename__ = "session_audio_tracks"
|
|
__table_args__ = (
|
|
UniqueConstraint("session_id", "track_sid", name="uq_session_track"),
|
|
Index("ix_session_audio_tracks_session_id", "session_id"),
|
|
Index("ix_session_audio_tracks_session_id_status", "session_id", "status"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")
|
|
)
|
|
session_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("conference_sessions.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
)
|
|
participant_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("conference_participants.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
)
|
|
track_sid: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
egress_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
file_path: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
status: Mapped[str] = mapped_column(
|
|
AudioTrackStatus, nullable=False, server_default="recording"
|
|
)
|
|
started_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
ended_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
segments: Mapped[list[dict[str, Any]] | None] = mapped_column(JSONB, nullable=True)
|