mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
Add Tauri integration and server management features. Introduced auto-start functionality for the bundled server in Tauri environment, added configuration management for data directories, and refactored backend components to utilize the new config module. Updated dependencies and improved project structure for better organization.
This commit is contained in:
+51
-2
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { GenerationForm } from '@/components/Generation/GenerationForm';
|
||||
import { HistoryTable } from '@/components/History/HistoryTable';
|
||||
import { ConnectionForm } from '@/components/ServerSettings/ConnectionForm';
|
||||
@@ -7,14 +7,63 @@ import { ModelManagement } from '@/components/ServerSettings/ModelManagement';
|
||||
import { Toaster } from '@/components/ui/toaster';
|
||||
import { ProfileList } from '@/components/VoiceProfiles/ProfileList';
|
||||
import { Sidebar } from '@/components/Sidebar';
|
||||
import { isTauri, startServer, stopServer } from '@/lib/tauri';
|
||||
|
||||
// Track if server is starting to prevent duplicate starts
|
||||
let serverStarting = false;
|
||||
|
||||
function App() {
|
||||
const [activeTab, setActiveTab] = useState('profiles');
|
||||
const [serverReady, setServerReady] = useState(false);
|
||||
|
||||
// Auto-start server when running in Tauri
|
||||
useEffect(() => {
|
||||
if (!isTauri() || serverStarting) {
|
||||
return;
|
||||
}
|
||||
|
||||
serverStarting = true;
|
||||
console.log('Running in Tauri, starting bundled server...');
|
||||
|
||||
startServer(false)
|
||||
.then(() => {
|
||||
console.log('Server is ready');
|
||||
setServerReady(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to auto-start server:', error);
|
||||
serverStarting = false;
|
||||
});
|
||||
|
||||
// Cleanup: stop server on actual unmount (not StrictMode remount)
|
||||
return () => {
|
||||
// In production builds, we want to stop the server on unmount
|
||||
// In dev mode, React StrictMode causes remounts, so we skip cleanup
|
||||
if (import.meta.env?.PROD) {
|
||||
stopServer().catch((error) => {
|
||||
console.error('Failed to stop server on cleanup:', error);
|
||||
});
|
||||
serverStarting = false;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Show loading screen while server is starting in Tauri
|
||||
if (isTauri() && !serverReady) {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex items-center justify-center">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto"></div>
|
||||
<p className="text-muted-foreground">Starting server...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex">
|
||||
<Sidebar activeTab={activeTab} onTabChange={setActiveTab} />
|
||||
|
||||
|
||||
<main className="flex-1 ml-20">
|
||||
<div className="container mx-auto px-8 py-8 max-w-7xl">
|
||||
{activeTab === 'profiles' && (
|
||||
|
||||
@@ -14,13 +14,11 @@ import { useToast } from '@/components/ui/use-toast';
|
||||
import { apiClient } from '@/lib/api/client';
|
||||
import { useDeleteGeneration, useHistory } from '@/lib/hooks/useHistory';
|
||||
import { formatDate, formatDuration } from '@/lib/utils/format';
|
||||
import { useServerStore } from '@/stores/serverStore';
|
||||
|
||||
export function HistoryTable() {
|
||||
const [page, setPage] = useState(0);
|
||||
const limit = 20;
|
||||
const { toast } = useToast();
|
||||
const _serverUrl = useServerStore((state) => state.serverUrl);
|
||||
|
||||
const { data: historyData, isLoading } = useHistory({
|
||||
limit,
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Mic, Plus } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useDeleteProfile, useProfiles } from '@/lib/hooks/useProfiles';
|
||||
import { useProfiles } from '@/lib/hooks/useProfiles';
|
||||
import { useUIStore } from '@/stores/uiStore';
|
||||
import { ProfileCard } from './ProfileCard';
|
||||
import { ProfileForm } from './ProfileForm';
|
||||
|
||||
export function ProfileList() {
|
||||
const { data: profiles, isLoading, error } = useProfiles();
|
||||
const _deleteProfile = useDeleteProfile();
|
||||
const setDialogOpen = useUIStore((state) => state.setProfileDialogOpen);
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Tauri integration utilities
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
/**
|
||||
* Check if running in Tauri environment
|
||||
*/
|
||||
export function isTauri(): boolean {
|
||||
return '__TAURI_INTERNALS__' in window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the bundled Python server (Tauri only)
|
||||
*/
|
||||
export async function startServer(remote = false): Promise<string> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri environment');
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await invoke<string>('start_server', { remote });
|
||||
console.log('Server started:', result);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Failed to start server:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the bundled Python server (Tauri only)
|
||||
*/
|
||||
export async function stopServer(): Promise<void> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri environment');
|
||||
}
|
||||
|
||||
try {
|
||||
await invoke('stop_server');
|
||||
console.log('Server stopped');
|
||||
} catch (error) {
|
||||
console.error('Failed to stop server:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user