Refactor audio generation components and improve debugging capabilities

- Introduced useGenerationForm hook to streamline audio generation form handling, including validation and model download management.
- Updated FloatingGenerateBox and GenerationForm components to utilize the new hook, enhancing code organization and reducing duplication.
- Replaced console logging with a debug utility for better logging control during audio playback and generation processes.
- Improved error handling in HistoryTable and MainEditor components by integrating toast notifications for user feedback.
- Adjusted audio recording duration limits across various components for consistency.
This commit is contained in:
Jamie Pine
2026-01-28 14:30:33 -08:00
parent 07a91a2381
commit 7208f51eee
14 changed files with 320 additions and 364 deletions
@@ -42,45 +42,13 @@ import {
import { useSystemAudioCapture } from '@/lib/hooks/useSystemAudioCapture';
import { useTranscription } from '@/lib/hooks/useTranscription';
import { isTauri } from '@/lib/tauri';
import { formatAudioDuration } from '@/lib/utils/audio';
import { formatAudioDuration, getAudioDuration } from '@/lib/utils/audio';
import { useUIStore } from '@/stores/uiStore';
import { AudioSampleRecording } from './AudioSampleRecording';
import { AudioSampleSystem } from './AudioSampleSystem';
import { AudioSampleUpload } from './AudioSampleUpload';
import { SampleList } from './SampleList';
// Helper function to get audio duration from File
async function getAudioDuration(file: File & { recordedDuration?: number }): Promise<number> {
// If the file has a recordedDuration property (from our recording hooks),
// use that instead of trying to read metadata. This fixes issues on Windows
// where WebM files from MediaRecorder don't have proper duration metadata.
if (file.recordedDuration !== undefined && Number.isFinite(file.recordedDuration)) {
return file.recordedDuration;
}
return new Promise((resolve, reject) => {
const audio = new Audio();
const url = URL.createObjectURL(file);
audio.addEventListener('loadedmetadata', () => {
URL.revokeObjectURL(url);
// Check if duration is valid (not Infinity or NaN)
if (Number.isFinite(audio.duration) && audio.duration > 0) {
resolve(audio.duration);
} else {
reject(new Error('Audio file has invalid duration metadata'));
}
});
audio.addEventListener('error', () => {
URL.revokeObjectURL(url);
reject(new Error('Failed to load audio file'));
});
audio.src = url;
});
}
const MAX_AUDIO_DURATION_SECONDS = 30;
const baseProfileSchema = z.object({
@@ -187,7 +155,7 @@ export function ProfileForm() {
stopRecording,
cancelRecording,
} = useAudioRecording({
maxDurationSeconds: 30,
maxDurationSeconds: 29,
onRecordingComplete: (blob, recordedDuration) => {
const file = new File([blob], `recording-${Date.now()}.webm`, {
type: blob.type || 'audio/webm',
@@ -213,7 +181,7 @@ export function ProfileForm() {
stopRecording: stopSystemRecording,
cancelRecording: cancelSystemRecording,
} = useSystemAudioCapture({
maxDurationSeconds: 30,
maxDurationSeconds: 29,
onRecordingComplete: (blob, recordedDuration) => {
const file = new File([blob], `system-audio-${Date.now()}.wav`, {
type: blob.type || 'audio/wav',
@@ -73,7 +73,7 @@ export function SampleUpload({ profileId, open, onOpenChange }: SampleUploadProp
stopRecording,
cancelRecording,
} = useAudioRecording({
maxDurationSeconds: 30,
maxDurationSeconds: 29,
onRecordingComplete: (blob, recordedDuration) => {
// Convert blob to File object
const file = new File([blob], `recording-${Date.now()}.webm`, {
@@ -100,7 +100,7 @@ export function SampleUpload({ profileId, open, onOpenChange }: SampleUploadProp
stopRecording: stopSystemRecording,
cancelRecording: cancelSystemRecording,
} = useSystemAudioCapture({
maxDurationSeconds: 30,
maxDurationSeconds: 29,
onRecordingComplete: (blob, recordedDuration) => {
// Convert blob to File object
const file = new File([blob], `system-audio-${Date.now()}.wav`, {