mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 04:40:40 -07:00
Move tauri imports behind platform abstraction, merge CUDA build into release workflow
- Add openPath and pickDirectory to PlatformFilesystem interface - Remove direct @tauri-apps/plugin-shell and plugin-dialog imports from app - Merge build-cuda.yml into release.yml as a parallel job
This commit is contained in:
@@ -1,73 +0,0 @@
|
||||
name: Build CUDA Backend
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build-cuda-windows:
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
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: Install PyTorch with CUDA 12.1
|
||||
run: |
|
||||
pip install torch --index-url https://download.pytorch.org/whl/cu121 --force-reinstall --no-deps
|
||||
pip install torchaudio --index-url https://download.pytorch.org/whl/cu121
|
||||
|
||||
- name: Verify CUDA support in torch
|
||||
run: |
|
||||
python -c "import torch; print(f'CUDA available in build: {torch.cuda.is_available()}'); print(f'CUDA version: {torch.version.cuda}')"
|
||||
|
||||
- name: Build CUDA server binary
|
||||
shell: bash
|
||||
working-directory: backend
|
||||
run: python build_binary.py --cuda
|
||||
|
||||
- name: Split binary for GitHub Releases
|
||||
shell: bash
|
||||
run: |
|
||||
python scripts/split_binary.py \
|
||||
backend/dist/voicebox-server-cuda.exe \
|
||||
--output release-assets/
|
||||
|
||||
- name: Upload split parts to GitHub Release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
release-assets/voicebox-server-cuda.part*.exe
|
||||
release-assets/voicebox-server-cuda.sha256
|
||||
release-assets/voicebox-server-cuda.manifest
|
||||
draft: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload binary as workflow artifact (for testing)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: voicebox-server-cuda-windows
|
||||
path: backend/dist/voicebox-server-cuda.exe
|
||||
retention-days: 7
|
||||
|
||||
# Linux CUDA build can be added later with:
|
||||
# build-cuda-linux:
|
||||
# runs-on: ubuntu-22.04
|
||||
# ...
|
||||
@@ -158,3 +158,63 @@ jobs:
|
||||
prerelease: false
|
||||
args: ${{ matrix.args }}
|
||||
includeUpdaterJson: true
|
||||
|
||||
build-cuda-windows:
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
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: Install PyTorch with CUDA 12.1
|
||||
run: |
|
||||
pip install torch --index-url https://download.pytorch.org/whl/cu121 --force-reinstall --no-deps
|
||||
pip install torchaudio --index-url https://download.pytorch.org/whl/cu121
|
||||
|
||||
- name: Verify CUDA support in torch
|
||||
run: |
|
||||
python -c "import torch; print(f'CUDA available in build: {torch.cuda.is_available()}'); print(f'CUDA version: {torch.version.cuda}')"
|
||||
|
||||
- name: Build CUDA server binary
|
||||
shell: bash
|
||||
working-directory: backend
|
||||
run: python build_binary.py --cuda
|
||||
|
||||
- name: Split binary for GitHub Releases
|
||||
shell: bash
|
||||
run: |
|
||||
python scripts/split_binary.py \
|
||||
backend/dist/voicebox-server-cuda.exe \
|
||||
--output release-assets/
|
||||
|
||||
- name: Upload split parts to GitHub Release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
release-assets/voicebox-server-cuda.part*.exe
|
||||
release-assets/voicebox-server-cuda.sha256
|
||||
release-assets/voicebox-server-cuda.manifest
|
||||
draft: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload binary as workflow artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: voicebox-server-cuda-windows
|
||||
path: backend/dist/voicebox-server-cuda.exe
|
||||
retention-days: 7
|
||||
|
||||
@@ -446,8 +446,7 @@ export function ModelManagement() {
|
||||
className="text-xs text-muted-foreground h-7 px-2"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const { open } = await import('@tauri-apps/plugin-shell');
|
||||
await open(cacheDir.path);
|
||||
await platform.filesystem.openPath(cacheDir.path);
|
||||
} catch {
|
||||
toast({ title: 'Failed to open model folder', variant: 'destructive' });
|
||||
}
|
||||
@@ -462,14 +461,9 @@ export function ModelManagement() {
|
||||
className="text-xs text-muted-foreground h-7 px-2"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const { open: openDialog } = await import('@tauri-apps/plugin-dialog');
|
||||
const selected = await openDialog({
|
||||
directory: true,
|
||||
title: 'Choose model storage folder',
|
||||
});
|
||||
if (!selected) return;
|
||||
const newDir =
|
||||
typeof selected === 'string' ? selected : (selected as { path: string }).path;
|
||||
const newDir = await platform.filesystem.pickDirectory(
|
||||
'Choose model storage folder',
|
||||
);
|
||||
if (!newDir) return;
|
||||
setPendingMigrateDir(newDir);
|
||||
} catch {
|
||||
|
||||
@@ -10,6 +10,8 @@ export interface FileFilter {
|
||||
|
||||
export interface PlatformFilesystem {
|
||||
saveFile(filename: string, blob: Blob, filters?: FileFilter[]): Promise<void>;
|
||||
openPath(path: string): Promise<void>;
|
||||
pickDirectory(title: string): Promise<string | null>;
|
||||
}
|
||||
|
||||
export interface UpdateStatus {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PlatformFilesystem, FileFilter } from '@/platform/types';
|
||||
import type { FileFilter, PlatformFilesystem } from '@/platform/types';
|
||||
|
||||
export const tauriFilesystem: PlatformFilesystem = {
|
||||
async saveFile(filename: string, blob: Blob, filters?: FileFilter[]) {
|
||||
@@ -12,9 +12,8 @@ export const tauriFilesystem: PlatformFilesystem = {
|
||||
|
||||
if (!filePath) return; // User cancelled the dialog
|
||||
|
||||
const resolvedPath = typeof filePath === 'string'
|
||||
? filePath
|
||||
: (filePath as { path: string }).path;
|
||||
const resolvedPath =
|
||||
typeof filePath === 'string' ? filePath : (filePath as { path: string }).path;
|
||||
|
||||
if (!resolvedPath) {
|
||||
throw new Error('Failed to resolve save path from dialog');
|
||||
@@ -23,4 +22,17 @@ export const tauriFilesystem: PlatformFilesystem = {
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
await writeFile(resolvedPath, new Uint8Array(arrayBuffer));
|
||||
},
|
||||
|
||||
async openPath(path: string) {
|
||||
const { open } = await import('@tauri-apps/plugin-shell');
|
||||
await open(path);
|
||||
},
|
||||
|
||||
async pickDirectory(title: string) {
|
||||
const { open } = await import('@tauri-apps/plugin-dialog');
|
||||
const selected = await open({ directory: true, title });
|
||||
if (!selected) return null;
|
||||
const dir = typeof selected === 'string' ? selected : (selected as { path: string }).path;
|
||||
return dir || null;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PlatformFilesystem, FileFilter } from '@/platform/types';
|
||||
import type { FileFilter, PlatformFilesystem } from '@/platform/types';
|
||||
|
||||
export const webFilesystem: PlatformFilesystem = {
|
||||
async saveFile(filename: string, blob: Blob, _filters?: FileFilter[]) {
|
||||
@@ -12,4 +12,12 @@ export const webFilesystem: PlatformFilesystem = {
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
},
|
||||
|
||||
async openPath(_path: string) {
|
||||
// No filesystem access in browser
|
||||
},
|
||||
|
||||
async pickDirectory(_title: string) {
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user