from pydantic import BaseModel, Field, validator from typing import Optional, List from datetime import datetime class MeetingBase(BaseModel): title: str = Field(..., max_length=255) tags: Optional[str] = None meeting_time: Optional[datetime] = None status: str = "draft" asr_model_id: Optional[int] = None summary_model_id: Optional[int] = None type: str = "upload" # live, upload @validator('meeting_time', pre=True) def parse_meeting_time(cls, v): if v == "": return None return v class MeetingCreate(MeetingBase): participants: Optional[List[int]] = None file_path: Optional[str] = None prompt_id: Optional[int] = None class MeetingUpdate(BaseModel): title: Optional[str] = None tags: Optional[str] = None status: Optional[str] = None summary: Optional[str] = None class AttendeeOut(BaseModel): attendee_id: int user_id: Optional[int] display_name: Optional[str] = None avatar: Optional[str] = None class Config: from_attributes = True class MeetingOut(MeetingBase): meeting_id: int user_id: Optional[int] asr_model_id: Optional[int] = None summary_model_id: Optional[int] = None summary_prompt_id: Optional[int] = None creator_name: Optional[str] = None creator_avatar: Optional[str] = None summary: Optional[str] = None created_at: datetime updated_at: datetime attendees: List[AttendeeOut] = [] class Config: from_attributes = True class TranscriptSegmentOut(BaseModel): segment_id: int speaker_id: Optional[int] speaker_tag: Optional[str] start_time_ms: int end_time_ms: int text_content: str class Config: from_attributes = True class TranscriptTaskOut(BaseModel): task_id: str status: str progress: int error_message: Optional[str] = None created_at: datetime class Config: from_attributes = True class SummarizeTaskOut(BaseModel): task_id: str status: str progress: int error_message: Optional[str] = None created_at: datetime class Config: from_attributes = True class MeetingAudioOut(BaseModel): audio_id: int file_name: Optional[str] = None file_size: Optional[float] = None duration: int processing_status: str upload_time: datetime error_message: Optional[str] = None audio_url: Optional[str] = None class Config: from_attributes = True class MeetingDetailOut(MeetingOut): segments: List[TranscriptSegmentOut] = [] latest_transcript_task: Optional[TranscriptTaskOut] = None latest_summarize_task: Optional[SummarizeTaskOut] = None audio_files: List[MeetingAudioOut] = [] class MeetingListOut(BaseModel): items: List[MeetingOut] total: int