diff --git a/server/reflector/db/transcripts.py b/server/reflector/db/transcripts.py index dc832850..de55cac9 100644 --- a/server/reflector/db/transcripts.py +++ b/server/reflector/db/transcripts.py @@ -3,13 +3,13 @@ import json import os import shutil from contextlib import asynccontextmanager -from datetime import datetime +from datetime import datetime, timezone from pathlib import Path from typing import Any, Literal import sqlalchemy from fastapi import HTTPException -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, ConfigDict, Field, field_serializer from reflector.db import database, metadata from reflector.processors.types import Word as ProcessorWord from reflector.settings import settings @@ -82,7 +82,7 @@ transcripts = sqlalchemy.Table( def generate_transcript_name() -> str: - now = datetime.utcnow() + now = datetime.now(timezone.utc) return f"Transcript {now.strftime('%Y-%m-%d %H:%M:%S')}" @@ -150,7 +150,7 @@ class Transcript(BaseModel): status: str = "idle" locked: bool = False duration: float = 0 - created_at: datetime = Field(default_factory=datetime.utcnow) + created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) title: str | None = None short_summary: str | None = None long_summary: str | None = None @@ -168,6 +168,12 @@ class Transcript(BaseModel): source_kind: SourceKind audio_deleted: bool | None = None + @field_serializer("created_at", when_used="json") + def serialize_datetime(self, dt: datetime) -> str: + if dt.tzinfo is None: + dt = dt.replace(tzinfo=timezone.utc) + return dt.isoformat() + def add_event(self, event: str, data: BaseModel) -> TranscriptEvent: ev = TranscriptEvent(event=event, data=data.model_dump()) self.events.append(ev) diff --git a/server/reflector/views/transcripts.py b/server/reflector/views/transcripts.py index 19c273c3..51d59a1c 100644 --- a/server/reflector/views/transcripts.py +++ b/server/reflector/views/transcripts.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Annotated, Literal, Optional import reflector.auth as auth @@ -6,7 +6,7 @@ from fastapi import APIRouter, Depends, HTTPException from fastapi_pagination import Page from fastapi_pagination.ext.databases import paginate from jose import jwt -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, field_serializer from reflector.db.meetings import meetings_controller from reflector.db.migrate_user import migrate_user from reflector.db.rooms import rooms_controller @@ -61,6 +61,13 @@ class GetTranscriptMinimal(BaseModel): target_language: str | None reviewed: bool meeting_id: str | None + + @field_serializer("created_at", when_used="json") + def serialize_datetime(self, dt: datetime) -> str: + if dt.tzinfo is None: + dt = dt.replace(tzinfo=timezone.utc) + return dt.isoformat() + source_kind: SourceKind room_id: str | None = None room_name: str | None = None diff --git a/www/app/(app)/browse/page.tsx b/www/app/(app)/browse/page.tsx index 4a7de7b7..a36a4aba 100644 --- a/www/app/(app)/browse/page.tsx +++ b/www/app/(app)/browse/page.tsx @@ -46,7 +46,7 @@ import useSessionUser from "../../lib/useSessionUser"; import NextLink from "next/link"; import { Room, GetTranscriptMinimal } from "../../api"; import Pagination from "./pagination"; -import { formatTimeMs } from "../../lib/time"; +import { formatTimeMs, formatLocalDate } from "../../lib/time"; import useApi from "../../lib/useApi"; import { useError } from "../../(errors)/errorContext"; import { SourceKind } from "../../api"; @@ -381,15 +381,7 @@ export default function TranscriptBrowser() { ? item.room_name : item.source_kind} -