mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
fix: GUI startup with external server + data refresh on server switch
Two fixes for issue #312: 1. GUI stuck on loading screen when backend is already running externally (e.g. via python/uvicorn/Docker): - Rust: add HTTP health check fallback when the process on the port doesn't have 'voicebox' in its name. If /health responds with a valid Voicebox response, reuse the server instead of erroring. - Frontend: when startServer() fails, fall back to polling the health endpoint every 2s instead of permanently blocking. 2. No data refresh when switching server URLs in settings: - serverStore.setServerUrl() now invalidates all React Query caches when the URL actually changes, so profiles/history/models/stories are re-fetched from the new server. - Export queryClient from main.tsx for store-level cache invalidation. Fixes #312
This commit is contained in:
@@ -4,6 +4,7 @@ import voiceboxLogo from '@/assets/voicebox-logo.png';
|
||||
import ShinyText from '@/components/ShinyText';
|
||||
import { TitleBarDragRegion } from '@/components/TitleBarDragRegion';
|
||||
import { useAutoUpdater } from '@/hooks/useAutoUpdater';
|
||||
import { apiClient } from '@/lib/api/client';
|
||||
import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui';
|
||||
import { cn } from '@/lib/utils/cn';
|
||||
import { usePlatform } from '@/platform/PlatformContext';
|
||||
@@ -122,6 +123,24 @@ function App() {
|
||||
serverStartingRef.current = false;
|
||||
// @ts-expect-error - adding property to window
|
||||
window.__voiceboxServerStartedByApp = false;
|
||||
|
||||
// Fall back to polling: the server may already be running externally
|
||||
// (e.g. started via python/uvicorn/Docker). Poll the health endpoint
|
||||
// until it responds, then transition to the main UI.
|
||||
console.log('Falling back to health-check polling...');
|
||||
const pollInterval = setInterval(async () => {
|
||||
try {
|
||||
await apiClient.getHealth();
|
||||
console.log('External server detected via health check');
|
||||
clearInterval(pollInterval);
|
||||
setServerReady(true);
|
||||
} catch {
|
||||
// Server not ready yet, keep polling
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
// Stop polling after 2 minutes to avoid polling forever
|
||||
setTimeout(() => clearInterval(pollInterval), 120_000);
|
||||
});
|
||||
|
||||
// Cleanup: stop server on actual unmount (not StrictMode remount)
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import './index.css';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
|
||||
@@ -30,11 +30,29 @@ interface ServerStore {
|
||||
setCustomModelsDir: (dir: string | null) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all React Query caches and reset UI selection state.
|
||||
* Called when the server URL changes so stale data from the previous
|
||||
* server is not shown.
|
||||
*/
|
||||
function invalidateAllServerData() {
|
||||
// Lazy import to avoid circular dependency (main.tsx -> serverStore -> main.tsx)
|
||||
import('@/main').then(({ queryClient }) => {
|
||||
queryClient.invalidateQueries();
|
||||
});
|
||||
}
|
||||
|
||||
export const useServerStore = create<ServerStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
(set, get) => ({
|
||||
serverUrl: 'http://127.0.0.1:17493',
|
||||
setServerUrl: (url) => set({ serverUrl: url }),
|
||||
setServerUrl: (url) => {
|
||||
const prev = get().serverUrl;
|
||||
set({ serverUrl: url });
|
||||
if (url !== prev) {
|
||||
invalidateAllServerData();
|
||||
}
|
||||
},
|
||||
|
||||
isConnected: false,
|
||||
setIsConnected: (connected) => set({ isConnected: connected }),
|
||||
|
||||
Reference in New Issue
Block a user