mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-10-03 09:05:17 -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
|
prerelease: false
|
||||||
args: ${{ matrix.args }}
|
args: ${{ matrix.args }}
|
||||||
includeUpdaterJson: true
|
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"
|
className="text-xs text-muted-foreground h-7 px-2"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const { open } = await import('@tauri-apps/plugin-shell');
|
await platform.filesystem.openPath(cacheDir.path);
|
||||||
await open(cacheDir.path);
|
|
||||||
} catch {
|
} catch {
|
||||||
toast({ title: 'Failed to open model folder', variant: 'destructive' });
|
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"
|
className="text-xs text-muted-foreground h-7 px-2"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const { open: openDialog } = await import('@tauri-apps/plugin-dialog');
|
const newDir = await platform.filesystem.pickDirectory(
|
||||||
const selected = await openDialog({
|
'Choose model storage folder',
|
||||||
directory: true,
|
);
|
||||||
title: 'Choose model storage folder',
|
|
||||||
});
|
|
||||||
if (!selected) return;
|
|
||||||
const newDir =
|
|
||||||
typeof selected === 'string' ? selected : (selected as { path: string }).path;
|
|
||||||
if (!newDir) return;
|
if (!newDir) return;
|
||||||
setPendingMigrateDir(newDir);
|
setPendingMigrateDir(newDir);
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export interface FileFilter {
|
|||||||
|
|
||||||
export interface PlatformFilesystem {
|
export interface PlatformFilesystem {
|
||||||
saveFile(filename: string, blob: Blob, filters?: FileFilter[]): Promise<void>;
|
saveFile(filename: string, blob: Blob, filters?: FileFilter[]): Promise<void>;
|
||||||
|
openPath(path: string): Promise<void>;
|
||||||
|
pickDirectory(title: string): Promise<string | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateStatus {
|
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 = {
|
export const tauriFilesystem: PlatformFilesystem = {
|
||||||
async saveFile(filename: string, blob: Blob, filters?: FileFilter[]) {
|
async saveFile(filename: string, blob: Blob, filters?: FileFilter[]) {
|
||||||
@@ -12,9 +12,8 @@ export const tauriFilesystem: PlatformFilesystem = {
|
|||||||
|
|
||||||
if (!filePath) return; // User cancelled the dialog
|
if (!filePath) return; // User cancelled the dialog
|
||||||
|
|
||||||
const resolvedPath = typeof filePath === 'string'
|
const resolvedPath =
|
||||||
? filePath
|
typeof filePath === 'string' ? filePath : (filePath as { path: string }).path;
|
||||||
: (filePath as { path: string }).path;
|
|
||||||
|
|
||||||
if (!resolvedPath) {
|
if (!resolvedPath) {
|
||||||
throw new Error('Failed to resolve save path from dialog');
|
throw new Error('Failed to resolve save path from dialog');
|
||||||
@@ -23,4 +22,17 @@ export const tauriFilesystem: PlatformFilesystem = {
|
|||||||
const arrayBuffer = await blob.arrayBuffer();
|
const arrayBuffer = await blob.arrayBuffer();
|
||||||
await writeFile(resolvedPath, new Uint8Array(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 = {
|
export const webFilesystem: PlatformFilesystem = {
|
||||||
async saveFile(filename: string, blob: Blob, _filters?: FileFilter[]) {
|
async saveFile(filename: string, blob: Blob, _filters?: FileFilter[]) {
|
||||||
@@ -12,4 +12,12 @@ export const webFilesystem: PlatformFilesystem = {
|
|||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
document.body.removeChild(a);
|
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