mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 15:15:27 -07:00
- Rust: Replace fragile body.contains("status") with proper JSON
deserialization validating status=="healthy", model_loaded (bool),
and gpu_available (bool) to prevent misidentifying non-Voicebox services
- Frontend: Validate health response has Voicebox-specific fields before
marking server as ready during fallback polling
- Frontend: Discriminate port-in-use errors (poll for external server) from
real startup failures (missing sidecar, signing issues) — surface errors
immediately with a startupError state and Retry button in the UI
- Frontend: Set explicit startup-error state when 2-minute polling timeout
expires so the loading screen shows actionable feedback instead of hanging
- Architecture: Extract QueryClient to standalone side-effect-free module
(lib/queryClient.ts) to decouple serverStore from React bootstrap entrypoint
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import { queryClient } from '@/lib/queryClient';
|
|
|
|
interface ServerStore {
|
|
serverUrl: string;
|
|
setServerUrl: (url: string) => void;
|
|
|
|
isConnected: boolean;
|
|
setIsConnected: (connected: boolean) => void;
|
|
|
|
mode: 'local' | 'remote';
|
|
setMode: (mode: 'local' | 'remote') => void;
|
|
|
|
keepServerRunningOnClose: boolean;
|
|
setKeepServerRunningOnClose: (keepRunning: boolean) => void;
|
|
|
|
maxChunkChars: number;
|
|
setMaxChunkChars: (value: number) => void;
|
|
|
|
crossfadeMs: number;
|
|
setCrossfadeMs: (value: number) => void;
|
|
|
|
normalizeAudio: boolean;
|
|
setNormalizeAudio: (value: boolean) => void;
|
|
|
|
autoplayOnGenerate: boolean;
|
|
setAutoplayOnGenerate: (value: boolean) => void;
|
|
|
|
customModelsDir: string | null;
|
|
setCustomModelsDir: (dir: string | null) => void;
|
|
}
|
|
|
|
/**
|
|
* Invalidate all React Query caches so stale data from the previous
|
|
* server is not shown. Called when the server URL changes.
|
|
*/
|
|
function invalidateAllServerData() {
|
|
queryClient.invalidateQueries();
|
|
}
|
|
|
|
export const useServerStore = create<ServerStore>()(
|
|
persist(
|
|
(set, get) => ({
|
|
serverUrl: 'http://127.0.0.1:17493',
|
|
setServerUrl: (url) => {
|
|
const prev = get().serverUrl;
|
|
set({ serverUrl: url });
|
|
if (url !== prev) {
|
|
invalidateAllServerData();
|
|
}
|
|
},
|
|
|
|
isConnected: false,
|
|
setIsConnected: (connected) => set({ isConnected: connected }),
|
|
|
|
mode: 'local',
|
|
setMode: (mode) => set({ mode }),
|
|
|
|
keepServerRunningOnClose: false,
|
|
setKeepServerRunningOnClose: (keepRunning) => set({ keepServerRunningOnClose: keepRunning }),
|
|
|
|
maxChunkChars: 800,
|
|
setMaxChunkChars: (value) => set({ maxChunkChars: value }),
|
|
|
|
crossfadeMs: 50,
|
|
setCrossfadeMs: (value) => set({ crossfadeMs: value }),
|
|
|
|
normalizeAudio: true,
|
|
setNormalizeAudio: (value) => set({ normalizeAudio: value }),
|
|
|
|
autoplayOnGenerate: true,
|
|
setAutoplayOnGenerate: (value) => set({ autoplayOnGenerate: value }),
|
|
|
|
customModelsDir: null,
|
|
setCustomModelsDir: (dir) => set({ customModelsDir: dir }),
|
|
}),
|
|
{
|
|
name: 'voicebox-server',
|
|
},
|
|
),
|
|
);
|