nex_basse/backend/app/models/meeting.py

113 lines
5.9 KiB
Python

from sqlalchemy import String, Integer, Text, ForeignKey, DateTime, DECIMAL, Enum
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from .base import Base, TimestampMixin, MYSQL_TABLE_ARGS
class Meeting(Base, TimestampMixin):
__tablename__ = "biz_meeting"
__table_args__ = MYSQL_TABLE_ARGS
meeting_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("sys_user.user_id"), nullable=True)
asr_model_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_ai_model.model_id"), nullable=True)
summary_model_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_ai_model.model_id"), nullable=True)
summary_prompt_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_prompt_template.id"), nullable=True)
title: Mapped[str] = mapped_column(String(255), nullable=False)
tags: Mapped[str | None] = mapped_column(String(255))
meeting_time: Mapped[datetime | None] = mapped_column(DateTime)
access_password: Mapped[str | None] = mapped_column(String(10))
status: Mapped[str] = mapped_column(String(20), default="draft") # draft, transcribing, summarizing, completed
type: Mapped[str] = mapped_column(String(20), default="upload") # live, upload
summary: Mapped[str | None] = mapped_column(Text)
creator = relationship("User", backref="created_meetings")
attendees = relationship("MeetingAttendee", back_populates="meeting", cascade="all, delete-orphan")
audios = relationship("MeetingAudio", back_populates="meeting", cascade="all, delete-orphan")
segments = relationship("TranscriptSegment", back_populates="meeting", cascade="all, delete-orphan")
class MeetingAttendee(Base):
__tablename__ = "biz_meeting_attendees"
__table_args__ = MYSQL_TABLE_ARGS
attendee_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
meeting_id: Mapped[int] = mapped_column(Integer, ForeignKey("biz_meeting.meeting_id", ondelete="CASCADE"), index=True)
user_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("sys_user.user_id"))
meeting = relationship("Meeting", back_populates="attendees")
user = relationship("User")
@property
def display_name(self):
return self.user.display_name if self.user else None
@property
def avatar(self):
return self.user.avatar if self.user else None
class MeetingAudio(Base):
__tablename__ = "biz_meeting_audio"
__table_args__ = MYSQL_TABLE_ARGS
audio_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
meeting_id: Mapped[int] = mapped_column(Integer, ForeignKey("biz_meeting.meeting_id", ondelete="CASCADE"))
file_path: Mapped[str] = mapped_column(String(512), nullable=False)
file_name: Mapped[str | None] = mapped_column(String(200))
file_size: Mapped[float | None] = mapped_column(DECIMAL(10, 0))
duration: Mapped[int] = mapped_column(Integer, default=0)
processing_status: Mapped[str] = mapped_column(String(20), default="uploaded")
upload_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
error_message: Mapped[str | None] = mapped_column(Text)
meeting = relationship("Meeting", back_populates="audios")
class TranscriptTask(Base):
__tablename__ = "biz_transcript_task"
__table_args__ = MYSQL_TABLE_ARGS
task_id: Mapped[str] = mapped_column(String(255), primary_key=True)
meeting_id: Mapped[int] = mapped_column(Integer, ForeignKey("biz_meeting.meeting_id", ondelete="CASCADE"), index=True)
model_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_ai_model.model_id"))
language: Mapped[str] = mapped_column(String(10), default="auto")
status: Mapped[str] = mapped_column(String(20), default="pending") # pending, processing, completed, failed
progress: Mapped[int] = mapped_column(Integer, default=0)
completed_at: Mapped[datetime | None] = mapped_column(DateTime)
error_message: Mapped[str | None] = mapped_column(Text)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
class TranscriptSegment(Base):
__tablename__ = "biz_transcript_segment"
__table_args__ = MYSQL_TABLE_ARGS
segment_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
meeting_id: Mapped[int] = mapped_column(Integer, ForeignKey("biz_meeting.meeting_id", ondelete="CASCADE"))
audio_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_meeting_audio.audio_id", ondelete="CASCADE"))
speaker_id: Mapped[int | None] = mapped_column(Integer)
speaker_tag: Mapped[str | None] = mapped_column(String(50))
start_time_ms: Mapped[int] = mapped_column(Integer, nullable=False)
end_time_ms: Mapped[int] = mapped_column(Integer, nullable=False)
text_content: Mapped[str] = mapped_column(Text, nullable=False)
meeting = relationship("Meeting", back_populates="segments")
class SummarizeTask(Base):
__tablename__ = "biz_summarize_task"
__table_args__ = MYSQL_TABLE_ARGS
task_id: Mapped[str] = mapped_column(String(100), primary_key=True)
meeting_id: Mapped[int] = mapped_column(Integer, ForeignKey("biz_meeting.meeting_id", ondelete="CASCADE"), index=True)
prompt_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_prompt_template.id"))
model_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("biz_ai_model.model_id"))
user_prompt: Mapped[str | None] = mapped_column(Text)
status: Mapped[str] = mapped_column(String(50), default="pending", index=True)
progress: Mapped[int] = mapped_column(Integer, default=0)
result: Mapped[str | None] = mapped_column(Text)
error_message: Mapped[str | None] = mapped_column(Text)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, index=True)
completed_at: Mapped[datetime | None] = mapped_column(DateTime)