From 4d9b63aab31487aac0b82315338ea14d46be2748 Mon Sep 17 00:00:00 2001 From: H-Chris233 Date: Tue, 12 May 2026 17:48:22 +0800 Subject: [PATCH] Route qwen-asr through the organization fork Keep the submodule pinned to the reviewed commit while moving the fetch URL to Open-Less/qwen-asr, then document the review checklist future upgrades must follow.\n\nConstraint: #301 identified the personal upstream submodule URL as a supply-chain risk.\nRejected: Updating the submodule commit together with the URL change | would mix provenance hardening with unreviewed upstream code changes.\nConfidence: high\nScope-risk: narrow\nDirective: Do not point .gitmodules back to antirez/qwen-asr; sync upstream into the organization fork and review the diff first.\nTested: gh repo view Open-Less/qwen-asr; git submodule update --init --recursive openless-all/app/src-tauri/vendor/qwen-asr; git diff --check; npm run build; cargo check --manifest-path src-tauri/Cargo.toml\nNot-tested: macOS INSTALL=0 ./scripts/build-mac.sh C-link verification. --- .github/workflows/release-tauri.yml | 2 +- .gitmodules | 2 +- README.md | 4 +- README.zh.md | 4 +- docs/qwen-asr-submodule-upgrade-checklist.md | 49 +++++++++++++++++++ openless-all/README.md | 2 +- openless-all/app/src-tauri/Cargo.toml | 4 +- openless-all/app/src-tauri/build.rs | 4 +- .../app/src-tauri/src/asr/local/mod.rs | 2 +- .../src-tauri/src/asr/local/qwen_engine.rs | 4 +- .../app/src-tauri/src/asr/local/qwen_ffi.rs | 2 +- openless-all/app/src-tauri/src/persistence.rs | 2 +- openless-all/app/src/lib/localAsr.ts | 2 +- 13 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 docs/qwen-asr-submodule-upgrade-checklist.md diff --git a/.github/workflows/release-tauri.yml b/.github/workflows/release-tauri.yml index 8192bc96..5d129d5e 100644 --- a/.github/workflows/release-tauri.yml +++ b/.github/workflows/release-tauri.yml @@ -59,7 +59,7 @@ jobs: - uses: actions/checkout@v4 with: # vendor/qwen-asr 是 macOS 上 build.rs 必须的 git submodule(cc-rs 编译 - # antirez/qwen-asr 的 C 源),不拉就会在 mac 端 cargo build 阶段挂掉。 + # Open-Less/qwen-asr fork 的 C 源),不拉就会在 mac 端 cargo build 阶段挂掉。 submodules: recursive - uses: actions/setup-node@v4 diff --git a/.gitmodules b/.gitmodules index 4bceb1ad..1c75230a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "openless-all/app/src-tauri/vendor/qwen-asr"] path = openless-all/app/src-tauri/vendor/qwen-asr - url = https://github.com/antirez/qwen-asr.git + url = https://github.com/Open-Less/qwen-asr.git diff --git a/README.md b/README.md index 722d914b..61f9f631 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ OpenLess does one thing: **turn speech into usable written text (especially AI p - Tauri 2 + Rust backend + React/TS frontend. macOS 12+, Windows 10+. - **Toggle and push-to-talk** recording modes. `Esc` cancels at any phase, including polish/insert. - **Cloud ASR**: Volcengine streaming ASR, OpenAI Whisper-compatible batch ASR, Apple Speech (macOS). -- **Local ASR**: bundled Qwen3-ASR (0.6B / 1.7B) via vendored `antirez/qwen-asr`; Windows Foundry Local Whisper variants. +- **Local ASR**: bundled Qwen3-ASR (0.6B / 1.7B) via vendored `Open-Less/qwen-asr`; Windows Foundry Local Whisper variants. - **Polish providers**: Ark / DeepSeek / OpenAI / Doubao / Anthropic-compatible chat-completions, plus any OpenAI-compatible endpoint you bring. - 4 output modes: raw, light polish, structured (**AI prompt mode**), formal. Plus a **translation hotkey** that converts speech directly into the configured target language ([#43](../../issues/43)). - **Selection-ask QA panel** — separate hotkey opens a floating panel that runs voice Q&A against the highlighted text in any app ([#118](../../issues/118)). @@ -189,7 +189,7 @@ Full end-user walkthrough: [USAGE.md](USAGE.md). ## Build from source (developers) -The active codebase is in `openless-all/app/` (Tauri 2 + Rust + React/TS). The macOS build links a vendored C ASR engine ([`antirez/qwen-asr`](https://github.com/antirez/qwen-asr)) pulled in as a git submodule under `src-tauri/vendor/qwen-asr/`, so initialize submodules on first clone. +The active codebase is in `openless-all/app/` (Tauri 2 + Rust + React/TS). The macOS build links a vendored C ASR engine ([`Open-Less/qwen-asr`](https://github.com/Open-Less/qwen-asr), forked from `antirez/qwen-asr`) pulled in as a git submodule under `src-tauri/vendor/qwen-asr/`, so initialize submodules on first clone. ```bash # First clone only — pull in vendored submodules diff --git a/README.zh.md b/README.zh.md index 10165f02..d1737e31 100644 --- a/README.zh.md +++ b/README.zh.md @@ -141,7 +141,7 @@ OpenLess 只做一件事:**把语音变成可用的书面文字(尤其是 AI - Tauri 2 + Rust 后端 + React/TS 前端;macOS 12+,Windows 10+。 - **切换式 + 按住说话** 双模式录音;任意阶段按 `Esc` 都能取消(包括润色 / 插入中)。 - **云端 ASR**:火山引擎流式 ASR、OpenAI Whisper 兼容批式 ASR、Apple Speech(macOS)。 -- **本地 ASR**:内置 Qwen3-ASR(0.6B / 1.7B),通过 vendored `antirez/qwen-asr` 链接;Windows 端支持 Foundry Local Whisper。 +- **本地 ASR**:内置 Qwen3-ASR(0.6B / 1.7B),通过 vendored `Open-Less/qwen-asr` 链接;Windows 端支持 Foundry Local Whisper。 - **润色 Provider**:Ark / DeepSeek / OpenAI / Doubao / Anthropic 兼容的 Chat Completions,以及任意 OpenAI 兼容的自定义 endpoint。 - 4 种输出模式:原文、轻度润色、清晰结构(**AI prompt 模式**)、正式表达。另含**翻译热键**——按下后说一段话直接转成目标语言插入([#43](../../issues/43))。 - **划词语音问答(QA)面板** — 独立热键打开浮窗,对当前选中文本发起语音 Q&A([#118](../../issues/118))。 @@ -192,7 +192,7 @@ OpenLess 只做一件事:**把语音变成可用的书面文字(尤其是 AI ## 从源码构建(开发者) -当前活跃代码库在 `openless-all/app/`(Tauri 2 + Rust + React/TS)。macOS 构建会链接一份 vendored 的本地 ASR 引擎([`antirez/qwen-asr`](https://github.com/antirez/qwen-asr)),以 git submodule 形式挂在 `src-tauri/vendor/qwen-asr/`,首次 clone 后必须先拉子模块。 +当前活跃代码库在 `openless-all/app/`(Tauri 2 + Rust + React/TS)。macOS 构建会链接一份 vendored 的本地 ASR 引擎([`Open-Less/qwen-asr`](https://github.com/Open-Less/qwen-asr),fork 自 `antirez/qwen-asr`),以 git submodule 形式挂在 `src-tauri/vendor/qwen-asr/`,首次 clone 后必须先拉子模块。 ```bash # 首次 clone 后拉取子模块 diff --git a/docs/qwen-asr-submodule-upgrade-checklist.md b/docs/qwen-asr-submodule-upgrade-checklist.md new file mode 100644 index 00000000..3c414f66 --- /dev/null +++ b/docs/qwen-asr-submodule-upgrade-checklist.md @@ -0,0 +1,49 @@ +# qwen-asr submodule 升级检查清单 + +`openless-all/app/src-tauri/vendor/qwen-asr` 是 macOS 本地 Qwen3-ASR 的 C 引擎来源。OpenLess 只从组织 fork `https://github.com/Open-Less/qwen-asr.git` 拉取 submodule;`antirez/qwen-asr` 只作为上游同步来源,不直接进入主仓构建链路。 + +## 升级原则 + +- 不直接把 `.gitmodules` 改回个人上游仓库。 +- 不在未审查 upstream diff 的情况下推进 submodule commit。 +- 每次升级只推进 submodule 指针;除非编译或 FFI 必需,不混入 OpenLess 主项目逻辑改动。 +- 保留当前锁定 commit 的可回滚性,必要时能 `git checkout -- openless-all/app/src-tauri/vendor/qwen-asr` 回退。 + +## 操作步骤 + +1. 在 `Open-Less/qwen-asr` fork 中同步 upstream。 +2. 审查 fork 中待引入 commit: + - C 源码:`qwen_asr*.c`、`qwen_asr*.h` + - 构建脚本 / 模型下载脚本 + - 新增二进制、大文件、网络下载地址或 shell 命令 + - FFI API 是否改变:`qwen_load`、`qwen_free`、`qwen_set_token_callback`、`qwen_transcribe_audio`、`qwen_transcribe_stream` +3. 在 OpenLess 主仓更新 submodule: + ```bash + git submodule sync --recursive openless-all/app/src-tauri/vendor/qwen-asr + git submodule update --init --recursive openless-all/app/src-tauri/vendor/qwen-asr + cd openless-all/app/src-tauri/vendor/qwen-asr + git fetch origin + git checkout + cd - + ``` +4. 验证 submodule 来源仍是组织 fork: + ```bash + git config --file .gitmodules --get submodule.openless-all/app/src-tauri/vendor/qwen-asr.url + git -C openless-all/app/src-tauri/vendor/qwen-asr remote get-url origin + git submodule status openless-all/app/src-tauri/vendor/qwen-asr + git diff --submodule=log -- openless-all/app/src-tauri/vendor/qwen-asr + ``` +5. 至少运行: + ```bash + cd openless-all/app + npm run build + cargo check --manifest-path src-tauri/Cargo.toml + ``` + macOS 发布前还要用 `INSTALL=0 ./scripts/build-mac.sh` 验证 C 源编译和链接。 + +## PR / commit 说明必须包含 + +- 旧 submodule commit 和新 submodule commit。 +- 已审查的 upstream commit 范围。 +- 是否有 FFI API、模型文件结构、下载脚本或构建参数变化。 +- 已运行的验证命令和未覆盖的平台。 diff --git a/openless-all/README.md b/openless-all/README.md index 06911fe0..20606710 100644 --- a/openless-all/README.md +++ b/openless-all/README.md @@ -4,7 +4,7 @@ This is the current cross-platform OpenLess workspace. ## App Directory -The runnable Tauri app lives in `app/`. The macOS build links a vendored C ASR engine (`antirez/qwen-asr`) tracked as a git submodule under `app/src-tauri/vendor/qwen-asr/`, so initialize submodules on first clone. +The runnable Tauri app lives in `app/`. The macOS build links a vendored C ASR engine (`Open-Less/qwen-asr`, forked from `antirez/qwen-asr`) tracked as a git submodule under `app/src-tauri/vendor/qwen-asr/`, so initialize submodules on first clone. ```bash # First clone only — pull in vendored submodules diff --git a/openless-all/app/src-tauri/Cargo.toml b/openless-all/app/src-tauri/Cargo.toml index ddde8db4..3815e46b 100644 --- a/openless-all/app/src-tauri/Cargo.toml +++ b/openless-all/app/src-tauri/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] tauri-build = { version = "2", features = [] } -# Compile antirez/qwen-asr C sources for the local ASR engine on macOS. +# Compile vendored Open-Less/qwen-asr C sources for the local ASR engine on macOS. cc = "1.1" [dependencies] @@ -74,7 +74,7 @@ core-graphics = "0.24" objc2 = "0.5" objc2-foundation = "0.2" objc2-app-kit = "0.2" -# antirez/qwen-asr 用 malloc 分配返回字符串,必须用 C `free()` 释放。 +# qwen-asr 用 malloc 分配返回字符串,必须用 C `free()` 释放。 libc = "0.2" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/openless-all/app/src-tauri/build.rs b/openless-all/app/src-tauri/build.rs index 23219128..2c97b041 100644 --- a/openless-all/app/src-tauri/build.rs +++ b/openless-all/app/src-tauri/build.rs @@ -5,7 +5,7 @@ fn main() { tauri_build::build(); } -/// 编译 antirez/qwen-asr 的 C 源(仅 macOS)。 +/// 编译 vendored Open-Less/qwen-asr 的 C 源(仅 macOS)。 /// /// 上游 Makefile `make blas` 等价配置:BLAS 加速通过 Accelerate framework, /// `USE_BLAS` + `ACCELERATE_NEW_LAPACK` 是必要宏。 @@ -34,7 +34,7 @@ fn build_qwen_asr_macos() { .define("ACCELERATE_NEW_LAPACK", None) .flag("-O3") .flag("-ffast-math") - // 上游开 `-Wall -Wextra`;我们把 antirez 的代码当三方依赖,把无关警告压成静默 + // 上游开 `-Wall -Wextra`;我们把 qwen-asr 的代码当三方依赖,把无关警告压成静默 // 避免 build log 噪音淹没我们自己的告警。 .flag("-Wno-unused-parameter") .flag("-Wno-unused-variable") diff --git a/openless-all/app/src-tauri/src/asr/local/mod.rs b/openless-all/app/src-tauri/src/asr/local/mod.rs index 723d0054..9832d406 100644 --- a/openless-all/app/src-tauri/src/asr/local/mod.rs +++ b/openless-all/app/src-tauri/src/asr/local/mod.rs @@ -1,6 +1,6 @@ //! 本地 ASR 引擎入口。 //! -//! 当前只在 macOS 编入 antirez/qwen-asr (纯 C + Accelerate);Windows 端 +//! 当前只在 macOS 编入 vendored Open-Less/qwen-asr (纯 C + Accelerate);Windows 端 //! 的本地推理路径见 issue #256,本期不实现。 pub mod cache; diff --git a/openless-all/app/src-tauri/src/asr/local/qwen_engine.rs b/openless-all/app/src-tauri/src/asr/local/qwen_engine.rs index a6f3242e..eb6f565a 100644 --- a/openless-all/app/src-tauri/src/asr/local/qwen_engine.rs +++ b/openless-all/app/src-tauri/src/asr/local/qwen_engine.rs @@ -1,4 +1,4 @@ -//! antirez/qwen-asr 的安全 Rust 包装。 +//! vendored Open-Less/qwen-asr 的安全 Rust 包装。 //! //! 当前只暴露**最小可用面**:`load` / `transcribe_audio` / `transcribe_stream` //! + token 回调。后续接 coordinator 时再扩 prompt/language 设置。 @@ -35,7 +35,7 @@ unsafe impl Sync for QwenAsrEngine {} impl QwenAsrEngine { /// 从模型目录加载(目录里需含 `config.json` / `model.safetensors*` / - /// `vocab.json` / `merges.txt`,结构见 antirez `download_model.sh`)。 + /// `vocab.json` / `merges.txt`,结构见 qwen-asr `download_model.sh`)。 pub fn load(model_dir: &Path) -> Result { let dir_str = model_dir .to_str() diff --git a/openless-all/app/src-tauri/src/asr/local/qwen_ffi.rs b/openless-all/app/src-tauri/src/asr/local/qwen_ffi.rs index ae9def7d..a6d0feab 100644 --- a/openless-all/app/src-tauri/src/asr/local/qwen_ffi.rs +++ b/openless-all/app/src-tauri/src/asr/local/qwen_ffi.rs @@ -1,4 +1,4 @@ -//! 对 antirez/qwen-asr 公共 C API 的最小 FFI 声明。 +//! 对 vendored Open-Less/qwen-asr 公共 C API 的最小 FFI 声明。 //! //! 头文件见 `vendor/qwen-asr/qwen_asr.h`。这里**不**复刻 `qwen_ctx_t` //! 内部布局——保持不透明指针即可,避免 pthread/对齐相关的脆弱假设。 diff --git a/openless-all/app/src-tauri/src/persistence.rs b/openless-all/app/src-tauri/src/persistence.rs index 43f45e7d..961af7d8 100644 --- a/openless-all/app/src-tauri/src/persistence.rs +++ b/openless-all/app/src-tauri/src/persistence.rs @@ -125,7 +125,7 @@ fn ensure_dir(dir: &Path) -> Result<()> { } /// 本地 ASR 模型根目录:`/models/qwen3-asr/`。 -/// 子目录 = 模型 id(如 `qwen3-asr-0.6b`),存 antirez `download_model.sh` +/// 子目录 = 模型 id(如 `qwen3-asr-0.6b`),存 qwen-asr `download_model.sh` /// 列出的 5–7 个文件。 pub fn local_models_root() -> Result { let dir = data_dir()?.join("models").join("qwen3-asr"); diff --git a/openless-all/app/src/lib/localAsr.ts b/openless-all/app/src/lib/localAsr.ts index 63f5b2df..e7f5f650 100644 --- a/openless-all/app/src/lib/localAsr.ts +++ b/openless-all/app/src/lib/localAsr.ts @@ -14,7 +14,7 @@ export interface LocalAsrSettings { providerId: string; activeModel: string; mirror: string; - /** macOS 才编入 antirez/qwen-asr 引擎;Win 端 UI 据此把"开始"按钮灰掉。 */ + /** macOS 才编入 vendored Open-Less/qwen-asr 引擎;Win 端 UI 据此把"开始"按钮灰掉。 */ engineAvailable: boolean; }