import { zodResolver } from '@hookform/resolvers/zod'; import { Loader2, XCircle } from 'lucide-react'; import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import * as z from 'zod'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { useToast } from '@/components/ui/use-toast'; import { useServerHealth } from '@/lib/hooks/useServer'; import { usePlatform } from '@/platform/PlatformContext'; import { useServerStore } from '@/stores/serverStore'; const connectionSchema = z.object({ serverUrl: z.string().url('Please enter a valid URL'), }); type ConnectionFormValues = z.infer; export function ConnectionForm() { const platform = usePlatform(); const serverUrl = useServerStore((state) => state.serverUrl); const setServerUrl = useServerStore((state) => state.setServerUrl); const keepServerRunningOnClose = useServerStore((state) => state.keepServerRunningOnClose); const setKeepServerRunningOnClose = useServerStore((state) => state.setKeepServerRunningOnClose); const mode = useServerStore((state) => state.mode); const setMode = useServerStore((state) => state.setMode); const { toast } = useToast(); const { data: health, isLoading, error: healthError } = useServerHealth(); const form = useForm({ resolver: zodResolver(connectionSchema), defaultValues: { serverUrl: serverUrl, }, }); // Sync form with store when serverUrl changes externally useEffect(() => { form.reset({ serverUrl }); }, [serverUrl, form]); const { isDirty } = form.formState; function onSubmit(data: ConnectionFormValues) { setServerUrl(data.serverUrl); form.reset(data); toast({ title: 'Server URL updated', description: `Connected to ${data.serverUrl}`, }); } return ( Server Connection
( Server URL Enter the URL of your voicebox backend server )} /> {isDirty && } {/* Connection status */}
{isLoading ? (
Checking connection...
) : healthError ? (
Connection failed: {healthError.message}
) : health ? (
{health.model_loaded || health.model_downloaded ? 'Model Ready' : 'No Model'} GPU: {health.gpu_available ? 'Available' : 'Not Available'} {health.vram_used_mb != null && health.vram_used_mb > 0 && ( VRAM: {health.vram_used_mb.toFixed(0)} MB )}
) : null}
{ setKeepServerRunningOnClose(checked); platform.lifecycle.setKeepServerRunning(checked).catch((error) => { console.error('Failed to sync setting to Rust:', error); }); toast({ title: 'Setting updated', description: checked ? 'Server will continue running when app closes' : 'Server will stop when app closes', }); }} />

When enabled, the server will continue running in the background after closing the app. Disabled by default.

{platform.metadata.isTauri && (
{ setMode(checked ? 'remote' : 'local'); toast({ title: 'Setting updated', description: checked ? 'Network access enabled. Restart the app to apply.' : 'Network access disabled. Restart the app to apply.', }); }} />

Makes the server accessible from other devices on your network. Restart the app after changing this setting.

)}
); }