From c9aa46263f876b6123767353319abfce71d4fc71 Mon Sep 17 00:00:00 2001 From: weikeyi Date: Sun, 24 May 2026 13:04:53 +0800 Subject: [PATCH] Fix Sherpa local ASR asset and state handling --- .../app/src-tauri/src/asr/local/sherpa.rs | 22 +++++++++- openless-all/app/src/pages/LocalAsr.tsx | 41 +++++++++++++++---- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/openless-all/app/src-tauri/src/asr/local/sherpa.rs b/openless-all/app/src-tauri/src/asr/local/sherpa.rs index 3e808643..8354ea5d 100644 --- a/openless-all/app/src-tauri/src/asr/local/sherpa.rs +++ b/openless-all/app/src-tauri/src/asr/local/sherpa.rs @@ -142,7 +142,10 @@ fn required_path_is_dir(alias: &str, required: &str) -> bool { fn required_dir_is_valid(alias: &str, required: &str, path: &Path) -> bool { match (alias, required) { - ("qwen3-asr-0.6b-int8", "tokenizer") => path.join("tokenizer.json").is_file(), + ("qwen3-asr-0.6b-int8", "tokenizer") => { + path.join("tokenizer.json").is_file() + || (path.join("vocab.json").is_file() && path.join("merges.txt").is_file()) + } _ => false, } } @@ -345,7 +348,7 @@ mod tests { } #[test] - fn qwen3_tokenizer_requires_tokenizer_json() { + fn qwen3_tokenizer_accepts_supported_layouts() { let dir = std::env::temp_dir().join(format!( "openless-sherpa-tokenizer-{}", uuid::Uuid::new_v4() @@ -365,6 +368,21 @@ mod tests { &dir )); + fs::remove_file(dir.join("tokenizer.json")).expect("remove tokenizer json"); + fs::write(dir.join("vocab.json"), b"{}").expect("write vocab json"); + assert!(!required_path_is_valid( + "qwen3-asr-0.6b-int8", + "tokenizer", + &dir + )); + + fs::write(dir.join("merges.txt"), b"#version: 0.2").expect("write merges txt"); + assert!(required_path_is_valid( + "qwen3-asr-0.6b-int8", + "tokenizer", + &dir + )); + let _ = fs::remove_dir_all(dir); } diff --git a/openless-all/app/src/pages/LocalAsr.tsx b/openless-all/app/src/pages/LocalAsr.tsx index bf238def..a0ba8bdc 100644 --- a/openless-all/app/src/pages/LocalAsr.tsx +++ b/openless-all/app/src/pages/LocalAsr.tsx @@ -976,8 +976,11 @@ export function LocalAsr({ embedded = false }: LocalAsrProps = {}) { if (!sherpaAvailable) return const modelAlias = selectedSherpaAlias const remoteSize = sherpaRemoteSizes[modelAlias] + const model = sherpaCatalog.find((item) => item.alias === modelAlias) const initialDownloaded = - sherpaDownloadProgress[modelAlias]?.bytesDownloaded ?? 0 + sherpaDownloadProgress[modelAlias]?.bytesDownloaded ?? + model?.downloadedBytes ?? + 0 setSherpaBusy("download") setSherpaDownloadCancelRequested(false) setSherpaDownloadProgress((prev) => ({ @@ -1236,21 +1239,44 @@ export function LocalAsr({ embedded = false }: LocalAsrProps = {}) { const selectedSherpaRemoteSize = sherpaRemoteSizes[selectedSherpaAlias] const selectedSherpaDownloadProgress = sherpaDownloadProgress[selectedSherpaAlias] + const selectedSherpaDownloadedBytes = + selectedSherpaCatalog?.downloadedBytes ?? 0 + const selectedSherpaProgressBytes = + selectedSherpaDownloadProgress?.bytesDownloaded ?? 0 + const selectedSherpaPartialBytes = Math.max( + selectedSherpaProgressBytes, + selectedSherpaDownloadedBytes, + ) const isSherpaDownloading = selectedSherpaDownloadProgress?.phase === "started" || selectedSherpaDownloadProgress?.phase === "progress" const hasSherpaPartial = selectedSherpaCatalog?.cached !== true && selectedSherpaDownloadProgress?.phase !== "finished" && - (selectedSherpaDownloadProgress?.bytesDownloaded ?? 0) > 0 - const canDeleteSelectedSherpa = + selectedSherpaPartialBytes > 0 + const selectedSherpaHasLocalFiles = selectedSherpaCatalog?.cached === true || - hasSherpaPartial || - (selectedSherpaCatalog?.downloadedBytes ?? 0) > 0 + selectedSherpaDownloadedBytes > 0 + const canDeleteSelectedSherpa = + selectedSherpaHasLocalFiles || hasSherpaPartial const showSherpaDownloadProgress = isSherpaDownloading || selectedSherpaDownloadProgress?.phase === "failed" || hasSherpaPartial + const selectedSherpaDownloadProgressForDisplay = + selectedSherpaDownloadProgress ?? + (hasSherpaPartial + ? { + modelId: selectedSherpaAlias, + file: "", + fileIndex: 0, + fileCount: selectedSherpaRemoteSize?.fileCount ?? 0, + bytesDownloaded: selectedSherpaDownloadedBytes, + bytesTotal: selectedSherpaRemoteSize?.totalBytes ?? 0, + phase: "progress" as const, + error: null, + } + : undefined) const selectedSherpaSizeMb = formatFoundrySizeMb( selectedSherpaCatalog?.fileSizeMb, ) @@ -2033,7 +2059,7 @@ export function LocalAsr({ embedded = false }: LocalAsrProps = {}) { {showSherpaDownloadProgress && ( @@ -2063,8 +2089,7 @@ export function LocalAsr({ embedded = false }: LocalAsrProps = {}) { size="sm" disabled={ sherpaBusy !== null || - !sherpaAvailable || - selectedSherpaCatalog?.cached !== true + !sherpaAvailable } onClick={() => void handlePrepareSherpa()} >