From 25f6609a9f9ea1f14ab1c746ec717383cd826658 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Sun, 2 Aug 2026 10:32:58 +0700 Subject: [PATCH] fix(recordings): stop faking duration from file size + render edited content in search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The voice_recordings table has no duration column, but the backend aliased duration_bytes = size_bytes (file size in bytes) and RecordingCard divided it by 60 as if it were seconds — a 3MB MP3 rendered as a nonsensical '55924:3' fake timestamp. Drop the fabricated field and show real file size instead. Also render edited_content fallback in the analysis search results for consistency with message cards/detail. --- .../backend/src/modules/recordings/recordings.service.ts | 2 -- .../frontend/src/components/analysis/search-panel.tsx | 5 ++++- .../src/components/recordings/recording-card.tsx | 9 +++++---- services/frontend/src/lib/types/recording.ts | 2 -- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/backend/src/modules/recordings/recordings.service.ts b/services/backend/src/modules/recordings/recordings.service.ts index e540768..6538e1f 100644 --- a/services/backend/src/modules/recordings/recordings.service.ts +++ b/services/backend/src/modules/recordings/recordings.service.ts @@ -20,7 +20,6 @@ export interface RecordingRow { upload_error: string | null; created_at: number; uploaded_at: number | null; - duration_bytes: number; } export interface PaginatedRecordings { @@ -69,7 +68,6 @@ export class RecordingsService { upload_error: pgVoiceRecordingsTable.upload_error, created_at: pgVoiceRecordingsTable.created_at, uploaded_at: pgVoiceRecordingsTable.uploaded_at, - duration_bytes: pgVoiceRecordingsTable.size_bytes, }) .from(pgVoiceRecordingsTable) .where(where) diff --git a/services/frontend/src/components/analysis/search-panel.tsx b/services/frontend/src/components/analysis/search-panel.tsx index 2323c8d..c0aaaae 100644 --- a/services/frontend/src/components/analysis/search-panel.tsx +++ b/services/frontend/src/components/analysis/search-panel.tsx @@ -96,7 +96,10 @@ export function SearchPanel() { )}

- {renderMessageContent(msg.content, msg.metadata)} + {renderMessageContent( + msg.edited_content ?? msg.content, + msg.metadata, + )}

{msg.ai_moderation_flags && msg.ai_moderation_flags !== "[]" && ( diff --git a/services/frontend/src/components/recordings/recording-card.tsx b/services/frontend/src/components/recordings/recording-card.tsx index b5acd28..3649399 100644 --- a/services/frontend/src/components/recordings/recording-card.tsx +++ b/services/frontend/src/components/recordings/recording-card.tsx @@ -3,6 +3,7 @@ import { Download, Loader2, Pause, Play } from "lucide-react"; import { useState } from "react"; import { GlassCard } from "@/components/glass/card"; +import { formatBytes } from "@/lib/format"; import type { VoiceRecording } from "@/lib/types"; interface RecordingCardProps { @@ -24,9 +25,9 @@ export function RecordingCard({ onTogglePlay, }: RecordingCardProps) { const [downloading, setDownloading] = useState(false); - const durationStr = recording.duration_bytes - ? `${Math.floor(recording.duration_bytes / 60)}:${String(recording.duration_bytes % 60).padStart(2, "0")}` - : "--:--"; + const sizeStr = recording.size_bytes + ? formatBytes(recording.size_bytes) + : "--"; // Fetch the file (CORS is open on the uploader) → blob → force download with // the real filename. Falls back to opening the URL in a new tab. @@ -119,7 +120,7 @@ export function RecordingCard({
- {durationStr} + {sizeStr} {new Date(recording.created_at).toLocaleString()} diff --git a/services/frontend/src/lib/types/recording.ts b/services/frontend/src/lib/types/recording.ts index a4a2b15..26126f7 100644 --- a/services/frontend/src/lib/types/recording.ts +++ b/services/frontend/src/lib/types/recording.ts @@ -8,8 +8,6 @@ export interface VoiceRecording { channel_name?: string | null; filename: string; size_bytes: number; - /** Present on REST rows; absent on WS voice_recording_uploaded events */ - duration_bytes?: number | null; download_url?: string | null; upload_status: string; upload_error?: string | null;