import { useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Upload, Mic } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import api from '@/services/api'; import AudioRecorder from '../audio/AudioRecorder'; interface VoiceEnrollmentProps { onEnrollmentComplete?: (voiceData: any) => void; className?: string; } export default function VoiceEnrollment({ onEnrollmentComplete, className = "" }: VoiceEnrollmentProps) { const [voiceName, setVoiceName] = useState(''); const [selectedFile, setSelectedFile] = useState(null); const [recordedAudio, setRecordedAudio] = useState<{ blob: Blob; url: string } | null>(null); const [isUploading, setIsUploading] = useState(false); const { toast } = useToast(); const handleFileSelect = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { if (file.type.startsWith('audio/')) { setSelectedFile(file); setRecordedAudio(null); // Clear recorded audio if file is selected } else { toast({ title: "Invalid file type", description: "Please select an audio file (.mp3, .wav, .m4a, etc.)", variant: "destructive" }); } } }; const handleRecordingComplete = (audioBlob: Blob, audioUrl: string) => { setRecordedAudio({ blob: audioBlob, url: audioUrl }); setSelectedFile(null); // Clear file selection if recording is made }; const handleEnrollment = async () => { if (!voiceName.trim()) { toast({ title: "Voice name required", description: "Please enter a name for this voice", variant: "destructive" }); return; } if (!selectedFile && !recordedAudio) { toast({ title: "No audio provided", description: "Please either upload an audio file or record your voice", variant: "destructive" }); return; } setIsUploading(true); try { // Prepare form data for API call const formData = new FormData(); formData.append('voice_name', voiceName); if (selectedFile) { formData.append('audio', selectedFile); } else if (recordedAudio) { // Convert blob to file const file = new File([recordedAudio.blob], `${voiceName}.wav`, { type: 'audio/wav' }); formData.append('audio', file); } // Call backend API const result = await api.enrollVoice(formData); const voiceData = { id: result.voice_id, name: voiceName, audioData: selectedFile || recordedAudio?.blob, audioUrl: selectedFile ? URL.createObjectURL(selectedFile) : recordedAudio?.url, createdAt: new Date().toISOString() }; onEnrollmentComplete?.(voiceData); toast({ title: "Voice enrolled successfully!", description: `Voice "${voiceName}" has been added to your collection` }); // Reset form setVoiceName(''); setSelectedFile(null); setRecordedAudio(null); } catch (error) { console.error('Enrollment error:', error); toast({ title: "Enrollment failed", description: error instanceof Error ? error.message : "There was an error enrolling your voice. Please try again.", variant: "destructive" }); } finally { setIsUploading(false); } }; return ( Enroll Your Voice Create a voice profile by uploading an audio file or recording directly {/* Voice Name Input */}
setVoiceName(e.target.value)} className="bg-surface border-border" />
{/* Audio Input Tabs */} Record Upload {recordedAudio && (
✓ Recording completed
)}
{selectedFile && (
✓ Selected: {selectedFile.name}
)}
{/* Enrollment Button */}
); }