MCPcopy
hub / github.com/jamiepine/voicebox / ProfileForm

Function ProfileForm

app/src/components/VoiceProfiles/ProfileForm.tsx:132–1317  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

130}
131
132export function ProfileForm() {
133 const { t } = useTranslation();
134 const platform = usePlatform();
135 const open = useUIStore((state) => state.profileDialogOpen);
136 const setOpen = useUIStore((state) => state.setProfileDialogOpen);
137 const editingProfileId = useUIStore((state) => state.editingProfileId);
138 const setEditingProfileId = useUIStore((state) => state.setEditingProfileId);
139 const profileFormDraft = useUIStore((state) => state.profileFormDraft);
140 const setProfileFormDraft = useUIStore((state) => state.setProfileFormDraft);
141 const { data: editingProfile } = useProfile(editingProfileId || '');
142 const createProfile = useCreateProfile();
143 const updateProfile = useUpdateProfile();
144 const addSample = useAddSample();
145 const deleteProfile = useDeleteProfile();
146 const uploadAvatar = useUploadAvatar();
147 const deleteAvatar = useDeleteAvatar();
148 const transcribe = useTranscription();
149 const { toast } = useToast();
150 const [voiceSource, setVoiceSource] = useState<'clone' | 'builtin'>('clone');
151 const [sampleMode, setSampleMode] = useState<'upload' | 'record' | 'system'>('record');
152 const [audioDuration, setAudioDuration] = useState<number | null>(null);
153 const [isValidatingAudio, setIsValidatingAudio] = useState(false);
154 const [avatarPreview, setAvatarPreview] = useState<string | null>(null);
155 const [selectedPresetEngine, setSelectedPresetEngine] = useState<string>('kokoro');
156 const [selectedPresetVoiceId, setSelectedPresetVoiceId] = useState<string>('');
157 const avatarInputRef = useRef<HTMLInputElement>(null);
158 const { isPlaying, playPause, cleanup: cleanupAudio } = useAudioPlayer();
159 const isCreating = !editingProfileId;
160 const serverUrl = useServerStore((state) => state.serverUrl);
161 const [profileEffectsChain, setProfileEffectsChain] = useState<EffectConfig[]>([]);
162 const [effectsDirty, setEffectsDirty] = useState(false);
163 const [defaultEngine, setDefaultEngine] = useState<string>('');
164
165 const form = useForm<ProfileFormValues>({
166 resolver: zodResolver(makeProfileSchema(t)),
167 defaultValues: {
168 name: '',
169 description: '',
170 language: 'en',
171 personality: '',
172 sampleFile: undefined,
173 referenceText: '',
174 avatarFile: undefined,
175 },
176 });
177
178 const selectedFile = form.watch('sampleFile');
179 const selectedAvatarFile = form.watch('avatarFile');
180
181 // Validate audio duration when file is selected
182 useEffect(() => {
183 if (selectedFile && selectedFile instanceof File) {
184 setIsValidatingAudio(true);
185 getAudioDuration(selectedFile as File & { recordedDuration?: number })
186 .then((duration) => {
187 setAudioDuration(duration);
188 if (duration > MAX_AUDIO_DURATION_SECONDS) {
189 form.setError('sampleFile', {

Callers

nothing calls this directly

Calls 15

usePlatformFunction · 0.90
useProfileFunction · 0.90
useCreateProfileFunction · 0.90
useUpdateProfileFunction · 0.90
useAddSampleFunction · 0.90
useDeleteProfileFunction · 0.90
useUploadAvatarFunction · 0.90
useDeleteAvatarFunction · 0.90
useTranscriptionFunction · 0.90
useToastFunction · 0.90
useAudioPlayerFunction · 0.90
getAudioDurationFunction · 0.90

Tested by

no test coverage detected