{"id":50917613,"url":"https://github.com/trsdn/openwritr-windows","last_synced_at":"2026-06-16T17:01:36.742Z","repository":{"id":361925175,"uuid":"1256254544","full_name":"trsdn/openwritr-windows","owner":"trsdn","description":"Native push-to-talk voice-to-text for Windows on ARM. Powered by NVIDIA Parakeet TDT v3 on the Snapdragon X Elite Hexagon NPU. Completely local.","archived":false,"fork":false,"pushed_at":"2026-06-12T12:33:45.000Z","size":691,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T14:11:27.796Z","etag":null,"topics":["hexagon-npu","onnxruntime","parakeet","qnn","qualcomm","rust","snapdragon","snapdragon-x-elite","speech-to-text","transcription","voice-to-text","windows","windows-arm64"],"latest_commit_sha":null,"homepage":"https://trsdn.github.io/openwritr-windows/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trsdn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-01T15:50:49.000Z","updated_at":"2026-06-12T12:33:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/trsdn/openwritr-windows","commit_stats":null,"previous_names":["trsdn/openwritr-windows"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/trsdn/openwritr-windows","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trsdn%2Fopenwritr-windows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trsdn%2Fopenwritr-windows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trsdn%2Fopenwritr-windows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trsdn%2Fopenwritr-windows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trsdn","download_url":"https://codeload.github.com/trsdn/openwritr-windows/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trsdn%2Fopenwritr-windows/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34415248,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hexagon-npu","onnxruntime","parakeet","qnn","qualcomm","rust","snapdragon","snapdragon-x-elite","speech-to-text","transcription","voice-to-text","windows","windows-arm64"],"created_at":"2026-06-16T17:01:35.796Z","updated_at":"2026-06-16T17:01:36.735Z","avatar_url":"https://github.com/trsdn.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenWritr for Windows (ARM64)\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Windows 11](https://img.shields.io/badge/Windows-11_24H2-0078D4?logo=windows)](https://github.com/trsdn/openwritr-windows)\n[![Rust](https://img.shields.io/badge/Rust-1.85-DEA584?logo=rust\u0026logoColor=white)](https://www.rust-lang.org)\n[![Snapdragon X Elite](https://img.shields.io/badge/Snapdragon-X_Elite-3253DC?logo=qualcomm\u0026logoColor=white)](https://www.qualcomm.com/products/mobile/snapdragon/pcs-and-tablets/snapdragon-x-elite)\n[![Hexagon NPU](https://img.shields.io/badge/Hexagon-NPU-FF2A00?logo=qualcomm\u0026logoColor=white)](https://huggingface.co/trsdn/parakeet-tdt-0.6b-v3-htp-int8-8s)\n[![Release](https://img.shields.io/github/v/release/trsdn/openwritr-windows)](https://github.com/trsdn/openwritr-windows/releases/latest)\n\nPush-to-talk voice-to-text for **Windows on ARM** (Surface Pro / Snapdragon X\nElite). Local transcription via **NVIDIA Parakeet TDT 0.6B v3** running on\nthe **Hexagon NPU**. 25 languages, ~67 ms per 8-second window on the NPU.\nOptional LLM cleanup via **GitHub Copilot** (Claude Haiku 4.5, GPT-5 Mini,\nGPT-4.1) or any OpenAI-compatible endpoint.\n\n**[Microsoft Store](https://apps.microsoft.com/detail/9MSQWR701P2Q)** · **[Website](https://trsdn.github.io/openwritr-windows/)** · **[Releases](https://github.com/trsdn/openwritr-windows/releases)** · **[NPU model on HF](https://huggingface.co/trsdn/parakeet-tdt-0.6b-v3-htp-int8-8s)** · **[macOS sibling](https://github.com/trsdn/OpenWritr)**\n\n## Quick start\n\n**Easiest: [get it from the Microsoft Store](https://apps.microsoft.com/detail/9MSQWR701P2Q).**\nOne click, it installs the right build for your CPU automatically, keeps\nitself updated, and there's no SmartScreen warning.\n\nPrefer a direct download? Pick the build for your CPU, both per-user (no\nadmin / UAC required):\n\n| Your machine | Build | Engine |\n|---|---|---|\n| **Snapdragon X** (Surface Pro 11, etc.) | `…-arm64-…` | Hexagon NPU + CPU fallback |\n| **Intel / AMD** laptop | `…-x64-…` | CPU INT8 |\n\nNot sure? Snapdragon laptops report \"ARM-based processor\" in Settings →\nSystem → About. Everything else is x64.\n\n**Installer.** Download\n`openwritr-windows-\u003carch\u003e-vX.Y.Z-setup.exe` from\n[Releases](https://github.com/trsdn/openwritr-windows/releases/latest)\nand run it. Sets up the Start Menu shortcut, an optional autostart-at-logon\nentry, and a proper uninstaller you'll find under Settings → Apps.\n\n**Portable zip.** Download `openwritr-windows-\u003carch\u003e-vX.Y.Z.zip` and unzip\nit into **any folder you like** (e.g. `C:\\Tools\\OpenWritr\\`), then run\n`openwritr.exe`. The app finds its DLLs next to the exe — the install\nlocation doesn't matter. Same binaries as the installer, just no shortcuts\nand no autostart.\n\n\u003e **Note:** user data (settings, downloaded models, logs) always lives under\n\u003e `%LOCALAPPDATA%\\OpenWritr\\` — the app creates that folder automatically on\n\u003e first run, you never need to create it yourself. `AppData` is a hidden\n\u003e folder; if you want to look inside, paste `%LOCALAPPDATA%\\OpenWritr` into\n\u003e the Explorer address bar.\n\nThe x64 build runs Parakeet on the CPU (no Hexagon NPU on Intel/AMD); the\narm64 build adds the NPU engine. Both share the same multilingual model and\nUX.\n\n\u003e **Windows SmartScreen warning.** The binaries are not code-signed (yet), so\n\u003e the first launch shows \"Windows protected your PC\". Click **More info →\n\u003e Run anyway**. To verify your download is authentic, compare its SHA-256\n\u003e against `SHA256SUMS.txt` attached to the release:\n\u003e `Get-FileHash .\\openwritr-windows-\u003carch\u003e-vX.Y.Z-setup.exe` in PowerShell.\n\nOn first launch the Parakeet model is fetched from Hugging Face into\n`%LOCALAPPDATA%\\OpenWritr\\models\\` — one-time, ~1.2 GB on the NPU engine\n(600 MB CPU INT8 + 632 MB QNN HTP context binary), ~2 minutes on a fast\nlink. A microphone icon appears in your system tray when the engine is\nready.\n\n## Usage\n\n| Combo | Action |\n|---|---|\n| **Hold Ctrl + Win** | Record. Release to transcribe and paste at the caret. |\n| **Hold Ctrl + Shift + Win** | Record + LLM cleanup (Claude Haiku 4.5 by default). |\n| **Tray right-click → Settings** | Change hotkey, engine, LLM provider. |\n\nA small dark pill appears at the bottom-center of the primary monitor while\nrecording, with white bars that breathe with your voice. Settings changes take\neffect immediately — no restart required.\n\n## Settings\n\nTray icon → right-click → **Settings**. All fields:\n\n- **Hotkey**: any combination of Ctrl / Shift / Alt / Win modifiers, plus an\n  optional trigger key (Space, Tab, Caps Lock, F13-F20, or `None` for\n  modifiers-only). Default: Ctrl+Win, no trigger.\n- **Transcription engine**: Parakeet CPU INT8, **Parakeet NPU** (default for\n  v0.3+), Whisper Large v3 Turbo NPU. The NPU engine runs the encoder on\n  the Snapdragon X Elite Hexagon HTP via a pre-compiled QAIRT context\n  binary; preprocessor and TDT decoder remain on the CPU. Falls back to\n  CPU INT8 automatically if the NPU model fails to load.\n- **Behaviour**: auto-paste at cursor, show overlay while recording, play\n  start/stop sounds.\n- **Enhance**: provider (Off / GitHub Copilot / OpenAI-compatible API), model\n  dropdown (Claude Haiku 4.5, GPT-5 Mini, GPT-4.1) or free-form custom model\n  name, base URL + API key (OpenAI-compatible only).\n\nSettings are stored at `%LOCALAPPDATA%\\OpenWritr\\settings.json`. The app polls\nthe file's mtime so external edits also take effect live.\n\n## Architecture\n\n### Native Rust app (what ships in the release zip)\n\n```\nopenwritr-windows/\n├── src/\n│   ├── main.rs              entry; dispatches `--settings` subprocess\n│   ├── app.rs               winit event loop, tray, hotkey thread, ASR dispatch\n│   ├── audio.rs             cpal WASAPI capture, multi-channel downmix\n│   ├── hotkey.rs            push-to-talk combo polling against key_hook state\n│   ├── key_hook.rs          global WH_KEYBOARD_LL hook → atomic key bitmap\n│   ├── overlay.rs           custom Win32 layered top-most window, GDI bars\n│   ├── settings.rs          serde struct + JSON load/save\n│   ├── settings_ui.rs       eframe/egui dialog (subprocess)\n│   ├── asr/                 ONNX Runtime pipeline (mel → encoder → TDT decoder)\n│   │   ├── parakeet.rs      Encoder enum {Cpu, Npu} + chunked long-audio pipeline\n│   │   └── qnn_ffi.rs       direct C-API FFI for the NPU encoder session\n│   ├── enhance.rs           Copilot / OpenAI cleanup pass\n│   ├── sounds.rs            G3/E3 tone synth (start/stop pings)\n│   └── bin/package.rs       distributable-zip builder\n└── Cargo.toml\n```\n\nKey design decisions:\n- **Global low-level keyboard hook.** Push-to-talk detection reads physical\n  key state from `WH_KEYBOARD_LL` instead of `GetAsyncKeyState`. The OS\n  synthesises key-ups during focus changes (PowerShell launched mid-recording,\n  UAC prompt, system shortcut handler), which the polling API faithfully\n  reports — and which would abort the recording. The LL hook sees only\n  physical events.\n- **Settings UI as subprocess.** The settings dialog is the same exe re-launched\n  with `--settings`. Spawning happens from a worker thread because\n  `CreateProcessW` on Windows ARM64 with Defender real-time scanning can block\n  several seconds — doing it inline would freeze the tray pump.\n- **Overlay on its own message loop.** Layered top-most window with color-key\n  transparency, painted with double-buffered GDI. Shares only two atomics\n  (`recording` + `last_rms_x10000`) with the recorder, so it cannot deadlock\n  the main app.\n- **Multi-channel downmix in the audio callback.** The Qualcomm Aqstic mic\n  array on Surface Pro exposes 4-8 interleaved channels at 48 kHz; we average\n  to mono before resampling to 16 kHz.\n\n### Python toolchain (`scripts/`)\n\nNPU model preparation lives in `scripts/`. `build_npu_encoder.py`,\n`aihub_compile_encoder.py`, `wrap_qnn_context_binary.py`, and\n`test_npu_encoder.py` are build-time tools used to produce the .bin\nhosted on HF. They are NOT invoked by the shipped `openwritr.exe` at\nruntime — the native build pulls the pre-compiled binary directly.\n\nThe Rust app does not call into Python at runtime.\n\n### Build-time Python dependency\n\nThe Rust package script (`cargo run --release --bin package`) stages Qualcomm\nQNN runtime DLLs from `pip install onnxruntime-qnn` into `target/release/`\nbefore zipping. The DLLs are required for the NPU engine option to work at\nall (even the Python path needs them). This is the only Python touch point at\nbuild time; the resulting zip is fully self-contained and Python-free.\n\n```powershell\npy -3.11-arm64 -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npip install onnxruntime-qnn\n```\n\nAfter that, build + package:\n\n```powershell\n.\\scripts\\envup.ps1        # primes vcvars arm64 + LLVM in PATH\ncargo build --release --bin openwritr\ncargo run --release --bin package\n```\n\nThe zip lands in `target/dist/`.\n\n## NPU pipeline\n\nThe encoder runs as a pre-compiled QAIRT context binary on the Hexagon HTP\nof the Snapdragon X Elite. Preprocessor (mel features) and TDT decoder\nremain on the CPU EP — they are dynamic-shape, lightweight, and not a\nbottleneck.\n\nThe compiled binary expects a fixed **8-second audio window**. For\npush-to-talk utterances ≤ 8 s the encoder is run once on a padded window.\nFor longer audio the encoder is run in chunks (8 s window with 1 s\noverlap), feature streams are stitched at the seam, and the TDT decoder\nruns once over the concatenated features. Tested up to ~23 s without\nboundary doubling.\n\n### Measured on Snapdragon X Elite (X1E80100)\n\n| Audio length | Decode (preproc + encode + TDT) | × Realtime | Chunks |\n|---|---|---|---|\n| 3 s | 128 ms | 23× | 1 |\n| 5.8 s | 221 ms | 26× | 1 |\n| 16.4 s | 375 ms | 44× | 3 |\n| 23.0 s | 626 ms | 37× | 4 |\n\nThe encoder itself is ~67 ms ± 0 ms per 8-second window, independent of\nthe actual audio length within the window.\n\n### How the binary was built\n\n1. `scripts/build_npu_encoder.py` constant-folds the encoder's\n   dynamic-shape attention mask (`Shape → Gather → Range → Expand`) against\n   a frozen `[1, 128, 801]` input — the HTP backend cannot evaluate that\n   subgraph as-is.\n2. `scripts/aihub_compile_encoder.py` submits the static-shape FP32 ONNX\n   plus FLEURS calibration samples to Qualcomm AI Hub. Quantize job uses\n   INT8 weights / INT16 activations (the standard HTP recipe for\n   transformer encoders); compile job targets `snapdragon_x_elite_crd`\n   with `--target_runtime qnn_context_binary --truncate_64bit_io`.\n3. `scripts/wrap_qnn_context_binary.py` wraps the resulting `.bin` in a\n   408-byte EPContext-node ONNX so ORT's QNN EP can consume it.\n4. `src/asr/qnn_ffi.rs` loads the wrapper via direct `ort_sys` C-API calls,\n   bypassing `ort` 2.0-rc.12's session builders (which crash inside QnnHtp\n   when consuming EPContext-wrapper ONNX).\n\n### Required helper DLLs\n\nThe QNN backend loads several sibling DLLs by name at session-create time.\n`src/bin/package.rs` stages all of them into the release zip, but if you\nhand-assemble a distribution: alongside `onnxruntime_providers_qnn.dll`\nyou need `QnnHtp.dll`, `QnnHtpPrepare.dll`, `QnnSystem.dll`, the V73/V81\nstubs (`QnnHtpV73Stub.dll`, `QnnHtpV81Stub.dll`), the per-arch skeletons\n(`libQnnHtpV73Skel.so`, `libQnnHtpV81Skel.so`), and the catalog files\n(`libqnnhtpv73.cat`, `libqnnhtpv81.cat`). Without the SKEL + .cat pair, the\nstub fails `LoadLibrary` with `ERROR_MOD_NOT_FOUND` (126) and QnnHtp later\naborts session creation with `STATUS_STACK_BUFFER_OVERRUN` (0xC0000409)\nwithout a useful error.\n\n## Models\n\n| Model | Provider | Size | License | Auto-downloaded? |\n|---|---|---|---|---|\n| Parakeet TDT 0.6B v3 (CPU INT8 ONNX + companion files) | [istupakov/parakeet-tdt-0.6b-v3-onnx](https://huggingface.co/istupakov/parakeet-tdt-0.6b-v3-onnx) | ~670 MB | CC-BY-4.0 | Yes, on first run |\n| Parakeet TDT 0.6B v3 NPU encoder (QAIRT context binary + wrapper) | [trsdn/parakeet-tdt-0.6b-v3-htp-int8-8s](https://huggingface.co/trsdn/parakeet-tdt-0.6b-v3-htp-int8-8s) | ~632 MB | CC-BY-4.0 | Yes, on first NPU launch |\n| Whisper Large v3 Turbo (QNN context binary) | [qualcomm/Whisper-Large-V3-Turbo](https://huggingface.co/qualcomm/Whisper-Large-V3-Turbo) | ~1.6 GB | Apache 2.0 + BSD-3 | Python build only |\n\nThe NPU encoder model is device-gated to Snapdragon X Elite (Hexagon V73).\nIt will not run on X Plus or any other Qualcomm chipset without\nrecompilation via AI Hub.\n\n## Licenses\n\n- **OpenWritr code**: MIT — see [`LICENSE`](LICENSE).\n- **Parakeet model**: CC-BY-4.0 (NVIDIA). Attribution preserved when the\n  model is downloaded.\n- **Qualcomm QNN runtime DLLs** (`QnnHtp.dll`, `QnnCpu.dll`, `Genie.dll`, etc.,\n  bundled in the release zip): **Qualcomm AI Engine Direct redistributable\n  license**. The full text ships inside every release zip under\n  `third-party-licenses/Qualcomm_LICENSE.pdf`, alongside Microsoft's\n  `ThirdPartyNotices.txt` for the `onnxruntime-qnn` PyPI package the DLLs\n  come from. These DLLs are redistributable as part of applications targeting\n  Qualcomm Snapdragon hardware, which is what OpenWritr does.\n- **ONNX Runtime DLLs** (`onnxruntime.dll`, `onnxruntime_providers_qnn.dll`):\n  MIT (Microsoft), bundled under their respective LICENSE files in the release\n  zip.\n\n## Repository layout\n\n```\nopenwritr-windows/\n├── src/             Rust native app (what users run)\n├── python/          Legacy v0.1 — current NPU fallback\n├── .venv/           gitignored; pip install onnxruntime-qnn happens here\n└── target/          gitignored; build output\n```\n\n`.venv` is build-time only. The shipped `openwritr.exe` does not call into\nPython at runtime.\n\n## Development\n\n```powershell\ngit clone https://github.com/trsdn/openwritr-windows.git\ncd openwritr-windows\npy -3.11-arm64 -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npip install onnxruntime-qnn\n.\\scripts\\envup.ps1\ncargo run --release --bin openwritr\n```\n\nFor the Python NPU build, additionally:\n\n```powershell\npip install -r python\\requirements.txt\npython python\\openwritr.py\n```\n\n## Releases\n\nTagged releases live at\n[github.com/trsdn/openwritr-windows/releases](https://github.com/trsdn/openwritr-windows/releases).\nEach release ships a single zip containing `openwritr.exe`, the ONNX Runtime\nDLLs, the QNN runtime DLLs, this README, the MIT LICENSE, and a\n`third-party-licenses/` folder with the Qualcomm and Microsoft licence files\nfor the bundled DLLs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrsdn%2Fopenwritr-windows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrsdn%2Fopenwritr-windows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrsdn%2Fopenwritr-windows/lists"}