diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 00000000..520482e8 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,63 @@ +name: Build Windows + +on: + workflow_dispatch: + +jobs: + build-windows: + permissions: + contents: write + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r backend/requirements.txt + + - name: Build Python server + shell: bash + run: | + cd backend + python build_binary.py + + PLATFORM=$(rustc --print host-tuple) + mkdir -p ../tauri/src-tauri/binaries + cp dist/voicebox-server.exe ../tauri/src-tauri/binaries/voicebox-server-${PLATFORM}.exe + echo "Built voicebox-server-${PLATFORM}.exe" + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + + - name: Rust cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "./tauri/src-tauri -> target" + + - name: Install dependencies + run: bun install + + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + projectPath: tauri + tagName: v__VERSION__ + releaseName: "voicebox v__VERSION__ (test build)" + releaseBody: "Test build for audio export fix" + releaseDraft: true + prerelease: true + args: "" + includeUpdaterJson: false diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..ea444b9c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +uvicorn +fastapi +sqlalchemy +torch +torchvision +soundfile +librosa +python-multipart +huggingface_hub diff --git a/tauri/src-tauri/tauri.conf.json b/tauri/src-tauri/tauri.conf.json index 53b95d18..1a6aa7eb 100644 --- a/tauri/src-tauri/tauri.conf.json +++ b/tauri/src-tauri/tauri.conf.json @@ -12,7 +12,7 @@ "bundle": { "active": true, "targets": "all", - "createUpdaterArtifacts": true, + "createUpdaterArtifacts": false, "externalBin": ["binaries/voicebox-server"], "icon": [ "icons/32x32.png", diff --git a/tauri/src/platform/filesystem.ts b/tauri/src/platform/filesystem.ts index 2292a99a..ff0eaf4d 100644 --- a/tauri/src/platform/filesystem.ts +++ b/tauri/src/platform/filesystem.ts @@ -2,40 +2,25 @@ import type { PlatformFilesystem, FileFilter } from '@/platform/types'; export const tauriFilesystem: PlatformFilesystem = { async saveFile(filename: string, blob: Blob, filters?: FileFilter[]) { - try { - const { save } = await import('@tauri-apps/plugin-dialog'); - const filePath = await save({ - defaultPath: filename, - filters: filters || [], - }); + const { save } = await import('@tauri-apps/plugin-dialog'); + const { writeFile } = await import('@tauri-apps/plugin-fs'); - if (filePath) { - let resolvedPath = ''; - if (typeof filePath === 'string') { - resolvedPath = filePath; - } else if (filePath && typeof filePath === 'object' && 'path' in filePath) { - resolvedPath = (filePath as { path: string }).path; - } + const filePath = await save({ + defaultPath: filename, + filters: filters || [], + }); - if (!resolvedPath) { - throw new Error('Failed to resolve save path'); - } + if (!filePath) return; // User cancelled the dialog - const { writeFile } = await import('@tauri-apps/plugin-fs'); - const arrayBuffer = await blob.arrayBuffer(); - await writeFile(resolvedPath, new Uint8Array(arrayBuffer)); - } - } catch (error) { - console.error('Failed to use Tauri dialog, falling back to browser download:', error); - // Fall back to browser download if Tauri dialog fails - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - document.body.removeChild(a); + const resolvedPath = typeof filePath === 'string' + ? filePath + : (filePath as { path: string }).path; + + if (!resolvedPath) { + throw new Error('Failed to resolve save path from dialog'); } + + const arrayBuffer = await blob.arrayBuffer(); + await writeFile(resolvedPath, new Uint8Array(arrayBuffer)); }, };