diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fb2b578d..95956a0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,6 +66,12 @@ jobs: run: | pip install -r backend/requirements-mlx.txt + - name: Install PyTorch with CUDA (Windows only) + if: matrix.platform == 'windows-latest' + run: | + pip install torch --index-url https://download.pytorch.org/whl/cu121 --force-reinstall --no-deps + pip install torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 + - name: Build Python server (Linux/macOS) if: matrix.platform != 'windows-latest' run: | diff --git a/app/src/App.tsx b/app/src/App.tsx index 7a859159..fbe29118 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,13 +1,14 @@ -import { useEffect, useRef, useState } from 'react'; import { RouterProvider } from '@tanstack/react-router'; +import { useEffect, useRef, useState } from 'react'; import voiceboxLogo from '@/assets/voicebox-logo.png'; import ShinyText from '@/components/ShinyText'; import { TitleBarDragRegion } from '@/components/TitleBarDragRegion'; +import { useAutoUpdater } from '@/hooks/useAutoUpdater'; import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui'; import { cn } from '@/lib/utils/cn'; +import { usePlatform } from '@/platform/PlatformContext'; import { router } from '@/router'; import { useServerStore } from '@/stores/serverStore'; -import { usePlatform } from '@/platform/PlatformContext'; const LOADING_MESSAGES = [ 'Warming up tensors...', @@ -38,6 +39,9 @@ function App() { const [loadingMessageIndex, setLoadingMessageIndex] = useState(0); const serverStartingRef = useRef(false); + // Automatically check for app updates on startup and show toast notifications + useAutoUpdater({ checkOnMount: true, showToast: true }); + // Sync stored setting to Rust on startup useEffect(() => { if (platform.metadata.isTauri) { @@ -46,14 +50,18 @@ function App() { console.error('Failed to sync initial setting to Rust:', error); }); } - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.metadata.isTauri, platform.lifecycle]); // Setup lifecycle callbacks useEffect(() => { platform.lifecycle.onServerReady = () => { setServerReady(true); }; - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.lifecycle]); // Setup window close handler and auto-start server when running in Tauri (production only) useEffect(() => { @@ -111,7 +119,9 @@ function App() { // Window close event handles server shutdown based on setting serverStartingRef.current = false; }; - }, [platform]); + // Empty dependency array - platform is stable from context, only run once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [platform.metadata.isTauri, platform.lifecycle]); // Cycle through loading messages every 3 seconds useEffect(() => { diff --git a/app/src/components/History/HistoryTable.tsx b/app/src/components/History/HistoryTable.tsx index 38c4361e..e572f69e 100644 --- a/app/src/components/History/HistoryTable.tsx +++ b/app/src/components/History/HistoryTable.tsx @@ -1,6 +1,13 @@ -import { AudioWaveform, Download, FileArchive, Loader2, MoreHorizontal, Play, Trash2 } from 'lucide-react'; +import { + AudioWaveform, + Download, + FileArchive, + Loader2, + MoreHorizontal, + Play, + Trash2, +} from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; -import type { HistoryResponse } from '@/lib/api/types'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -19,6 +26,7 @@ import { import { Textarea } from '@/components/ui/textarea'; import { useToast } from '@/components/ui/use-toast'; import { apiClient } from '@/lib/api/client'; +import type { HistoryResponse } from '@/lib/api/types'; import { BOTTOM_SAFE_AREA_PADDING } from '@/lib/constants/ui'; import { useDeleteGeneration, @@ -50,7 +58,11 @@ export function HistoryTable() { const limit = 20; const { toast } = useToast(); - const { data: historyData, isLoading, isFetching } = useHistory({ + const { + data: historyData, + isLoading, + isFetching, + } = useHistory({ limit, offset: page * limit, }); @@ -280,6 +292,7 @@ export function HistoryTable() {