Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/voicetranser/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions external_plugins/voicetranser/.zcode-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "voicetranser",
"version": "1.0.3",
"description": "Local push-to-talk voice input for macOS: hold a global hotkey, speak, release — transcription is pasted at your cursor. Fully local STT (Qwen3-ASR MLX, SenseVoice, mlx-whisper), zero external APIs. The bundled skill guides your agent through install, hotkey wiring, launchd setup and troubleshooting.",
"description_i18n": {
"en": "Local push-to-talk voice input for macOS: hold a global hotkey, speak, release — transcription is pasted at your cursor. Fully local STT (Qwen3-ASR MLX, SenseVoice, mlx-whisper), zero external APIs. The bundled skill guides your agent through install, hotkey wiring, launchd setup and troubleshooting.",
"zh-CN": "macOS 本地按住说话语音输入:按住全局热键说话、松开即转写粘贴到光标处。纯本地 STT(Qwen3-ASR MLX / SenseVoice / mlx-whisper),零外部 API。内置技能引导 agent 完成安装、热键接线、launchd 常驻与排障。"
},
"author": {
"name": "Lumos-789",
"url": "https://github.com/Lumos-789"
},
"homepage": "https://github.com/Lumos-789/VoiceTranser",
"repository": "https://github.com/Lumos-789/VoiceTranser",
"license": "MIT",
"keywords": [
"voice-input",
"speech-to-text",
"dictation",
"macos",
"push-to-talk",
"local-first",
"qwen3-asr",
"sensevoice"
],
"skills": [
"skills/voicetranser"
]
}
38 changes: 38 additions & 0 deletions external_plugins/voicetranser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# VoiceTranser

Local push-to-talk voice input for macOS: hold a global hotkey, speak, release — the transcription is pasted at your cursor. Built for talking to coding agents (and anything else you type into). Fully local, zero external APIs.

This plugin ships an **agent skill** — it does not bundle the tool itself. Once installed, you can say *"install VoiceTranser for me"* and the agent walks the whole chain: prerequisites, clone, deps, model download, launchd service, Karabiner hotkey wiring, accessibility permission, then verifies with the built-in 8-point diagnose script. It also handles ongoing troubleshooting and engine switching.

The runtime is pulled from the upstream repository, so installation needs network access and the tools listed below. The launchd step generates a plist from the current checkout path with `install_launchd.py`; the repository ships no plist snapshot to copy, so the generated one is the only source.

## What you get

- 🎙️ **Push-to-talk** — Karabiner `right_option` hold-to-talk (or Raycast/Hammerspoon hitting `/toggle`)
- 🧠 **Local STT, three engines** — Qwen3-ASR 0.6B 4bit on MLX/Metal (default, RTF 0.012–0.021, excellent Chinese with punctuation, strong zh-en code-switching) → SenseVoice Small int8 (CPU fallback) → mlx-whisper large-v3 (English/exotic languages)
- 📋 **Auto-paste** at the cursor, macOS notifications at each stage
- 🔧 **Mis-recognition wordlist** (`corrections.json`) — add a line, restart, fixed
- 🛡️ **Self-healing** — launchd KeepAlive + CoreAudio watchdog

## Requirements

macOS **Apple Silicon** (the default engine needs MLX/Metal; Intel Macs can force the CPU engine), Python 3.11+, [uv](https://docs.astral.sh/uv/). Optional but recommended: [Karabiner-Elements](https://karabiner-elements.pqrs.org/).

## Example prompts

- "Install VoiceTranser and wire my right Option key for push-to-talk"
- "语音输入装一下,右 Option 按住说话"
- "Transcription pasted nothing — diagnose VoiceTranser"
- "把 VoiceTranser 切到 CPU 引擎"

## Side effects (disclosed)

Installing/configuring VoiceTranser via this skill will, on your machine:

- **Network**: clone the GitHub repo, install Python deps via uv, download STT models (~230 MB SenseVoice from hf-mirror; ~500 MB Qwen3-ASR auto-fetched on first run). No audio or transcripts ever leaves the machine.
- **Files**: clone the repo, write model files and `~/.cache/huggingface` entries, install a launchd plist into `~/Library/LaunchAgents/`, write logs to `~/Library/Logs/`.
- **Commands**: run `uv`, `launchctl`, `curl` against `localhost:9877`, and the repo's diagnose script. May ask you to grant **Accessibility** permission to your terminal (required for auto-paste) and to add a Karabiner rule (the skill asks before editing Karabiner config or installing brew packages).

## Source & license

Upstream project: https://github.com/Lumos-789/VoiceTranser — MIT.
38 changes: 38 additions & 0 deletions external_plugins/voicetranser/README_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# VoiceTranser

macOS 本地按住说话语音输入:按住全局热键说话、松开即转写粘贴到光标处。为「跟编程助手对话」以及一切打字场景而生。完全本地运行,零外部 API。

本插件提供的是 **agent 技能**,不内嵌工具本体。安装后对 agent 说「帮我装 VoiceTranser」,它就会走完整条链:前置检查、clone、依赖、模型下载、launchd 常驻服务、Karabiner 热键接线、辅助功能权限,最后用内置 8 项自检脚本验证收工(音频项有 3 秒硬超时、不会弹麦克风授权;无权限时明确报「未授权」并计为未完整通过,可用 `--skip-audio` 跳过)。日常排障与引擎切换也由它接管。

工具本体从上游仓库拉取,因此安装需要网络和下面列出的依赖。launchd 步骤会用 `install_launchd.py` 按当前 checkout 路径生成 plist;仓库不再保存 plist 快照,生成出来的那份就是唯一来源。

## 你会得到什么

- 🎙️ **按住说话** — Karabiner `right_option` 按住录音松开出稿(也可用 Raycast/Hammerspoon 触发 `/toggle`)
- 🧠 **本地 STT,三引擎** — Qwen3-ASR 0.6B 4bit MLX/Metal(默认,RTF 0.012–0.021,中文近完美自带标点、中英夹杂强)→ SenseVoice Small int8(CPU fallback)→ mlx-whisper large-v3(英文/小语种)
- 📋 **自动粘贴**到光标处,各阶段 macOS 通知反馈
- 🔧 **误识词表**(`corrections.json`)— 发现误识加一行重启即生效
- 🛡️ **自愈守护** — launchd KeepAlive + CoreAudio 死锁看门狗

## 环境要求

macOS **Apple Silicon**(默认引擎需要 MLX/Metal;Intel 机型可强制走 CPU 引擎)、Python 3.11+、[uv](https://docs.astral.sh/uv/)。推荐装 [Karabiner-Elements](https://karabiner-elements.pqrs.org/)。

## 示例指令

- "Install VoiceTranser and wire my right Option key for push-to-talk"
- "语音输入装一下,右 Option 按住说话"
- "Transcription pasted nothing — diagnose VoiceTranser"
- "把 VoiceTranser 切到 CPU 引擎"

## 副作用披露

通过本技能安装/配置 VoiceTranser 会在你的机器上:

- **网络**:clone GitHub 仓库、uv 安装 Python 依赖、下载 STT 模型(SenseVoice ~230MB 走 hf-mirror;Qwen3-ASR ~500MB 首次运行自动拉取)。音频与转写文本永不离开本机。
- **文件**:clone 仓库、写模型文件与 `~/.cache/huggingface` 缓存、安装 launchd plist 到 `~/Library/LaunchAgents/`、日志写到 `~/Library/Logs/`。
- **命令**:运行 `uv`、`launchctl`、对 `localhost:9877` 的 `curl`、仓库自检脚本;可能需要你为终端授予**辅助功能**权限(自动粘贴必需),并添加一条 Karabiner 规则(改 Karabiner 配置或装 brew 包之前技能会先征询)。

## 源码与许可

上游项目:https://github.com/Lumos-789/VoiceTranser — MIT。
70 changes: 70 additions & 0 deletions external_plugins/voicetranser/skills/voicetranser/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
name: voicetranser
description: Install, configure and troubleshoot VoiceTranser — a fully local macOS push-to-talk voice input tool (hold a global hotkey, speak, release to transcribe-and-paste into any app). Use when the user wants hands-free voice dictation for coding/agents, asks to install VoiceTranser, wire its Karabiner hotkey / launchd service, switch STT engines, or fix transcription/paste/recording issues.
---

# VoiceTranser — local push-to-talk voice input for macOS

Hold a global hotkey, speak, release → transcription is pasted at the cursor.
Fully local (zero external APIs). Repo: https://github.com/Lumos-789/VoiceTranser

## Facts you need before touching anything

- Target: macOS **Apple Silicon** (the default engine needs MLX/Metal; Intel Macs fall back to the CPU engine).
- Stack: Python 3.11+ managed by **uv**; HTTP server (stdlib); launchd service; Karabiner-Elements hotkey.
- Engines (`STT_ENGINE`): `qwen3-mlx` (default, Qwen3-ASR 0.6B 4bit via mlx-audio, RTF≈0.015, best zh quality, punctuated) → `sensevoice` (CPU fallback, RTF≈0.03) → `mlx-whisper` (en/exotic languages).
- Port: **9877** is the single default (`config.DEFAULT_SERVER_PORT`; `server.py`, `install_launchd.py` and diagnose all derive from it). `SERVER_PORT` and the installed launchd plist override it. Diagnose resolves `--port` > env > launchd plist > `.env` > default and prints a WARNING when the plist disagrees with the default. If the mic is off-limits, use `--skip-audio`.
- Model files: SenseVoice 228 MB via `download_model.py` (hf-mirror); Qwen3-ASR ~500 MB auto-fetched on first run (respects `HF_ENDPOINT`).

## Install flow (do these in order, verify each step)

1. **Preflight**: `uname -m` (expect arm64), `command -v uv` (if missing: `brew install uv` — ask before installing anything).
2. **Clone & deps**:
```
git clone https://github.com/Lumos-789/VoiceTranser.git ~/VoiceTranser && cd ~/VoiceTranser
uv sync # if PyPI crawls: UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple uv sync
uv run python download_model.py
```
3. **First-run check**: `uv run python -m voicetranser --config` must print config without error.
4. **Service (recommended)**:
```
uv run python install_launchd.py
curl -s localhost:9877/status # expect {"status": "idle"}; model preloads in background
```
`install_launchd.py` writes a per-user plist whose `ProgramArguments` and
`WorkingDirectory` point at this checkout, then loads it — the repo ships no
plist snapshot, so there is nothing to copy. Use `--port`, `--engine`, or
`--no-load` when needed.
5. **Hotkey — Karabiner-Elements** complex modification (user must have Karabiner installed; add to `~/.config/karabiner/karabiner.json` → `profiles[].complex_modifications.rules`, then enable in the Karabiner UI):
```json
{
"description": "VoiceTranser: right_option push-to-talk",
"manipulators": [
{ "type": "basic", "from": { "key_code": "right_option" },
"to": [{ "shell_command": "curl -s localhost:9877/start > /dev/null" }],
"to_after_key_up": [{ "shell_command": "curl -s localhost:9877/stop > /dev/null" }] }
]
}
```
No Karabiner? Raycast/Hammerspoon hitting `/toggle` works too.
6. **Accessibility permission** (paste step needs it, grant once): System Settings → Privacy & Security → Accessibility → enable the terminal app. Then `.venv/bin/python tests/diagnose.py` — it must return a verdict within seconds: all 8 checks pass. The audio probe is bounded (3 s) and never prompts for the microphone; without permission it reports `microphone permission not granted`. A skipped check (e.g. `--skip-audio`) counts as *not fully verified* and keeps the exit code non-zero, so it can never masquerade as green.

## Troubleshoot (in order of likelihood)

- **Nothing pastes** → accessibility permission missing (step 6); re-run diagnose.
- **Hotkey does nothing** → `curl -s localhost:9877/status`; if refused, `launchctl kickstart -k gui/$(id -u)/com.voicetranser-sense` and check `~/Library/Logs/VoiceTranser-sense.log`.
- **Slow first transcription after boot** → model preload still running (cold load can take ~75 s); it is one-time per service start.
- **Bad quality on specific words** → append a mapping to `corrections.json` (whole-word replace, applied post-transcription), restart service.
- **GPU/memory concerns** → engine already caps MLX buffer cache at 1 GB; to fully avoid GPU use switch: `STT_ENGINE=sensevoice` (edit plist/`.env`, restart).
- **Generic health** → `.venv/bin/python tests/diagnose.py` (8 checks: deps, models, mic, clipboard, service, logs…). Fix whatever it flags before guessing.
- **Microphone off-limits / permission prompt risk** → never let a diagnostic wait on a TCC dialog: run `.venv/bin/python tests/diagnose.py --skip-audio`. The audio check only opens a stream after a non-prompting TCC status read reports *authorized*, and the probe itself is killed after 3 s.

## Switch engines

Edit `STT_ENGINE` in `~/Library/LaunchAgents/com.voicetranser-sense.plist` (overrides `.env`), then `launchctl bootout gui/$(id -u)/com.voicetranser-sense && launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.voicetranser-sense.plist`.

## Hard rules

- Never send audio or transcripts anywhere — the whole point is local-only operation.
- Don't install brew packages or modify Karabiner config without asking first.
- After any config change, verify with `diagnose.py` + one real `curl /status` before declaring done.
87 changes: 74 additions & 13 deletions marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
"url": "https://z.ai"
},
"unlistedPlugins": [
{ "name": "openpencil", "source": "./external_plugins/openpencil" }
{
"name": "openpencil",
"source": "./external_plugins/openpencil"
}
],
"plugins": [
{
Expand Down Expand Up @@ -827,7 +830,9 @@
},
{
"name": "excalidraw",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "Excalidraw",
"displayName_i18n": {
"en": "Excalidraw",
Expand All @@ -850,7 +855,9 @@
"name": "photocraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/photocraft/icon.png",
"source": "./external_plugins/photocraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "PhotoCraft",
"displayName_i18n": {
"en": "PhotoCraft",
Expand All @@ -877,7 +884,9 @@
"name": "vectorcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/vectorcraft/icon.png",
"source": "./external_plugins/vectorcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "VectorCraft",
"displayName_i18n": {
"en": "VectorCraft",
Expand All @@ -904,7 +913,9 @@
"name": "pdfcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/pdfcraft/icon.png",
"source": "./external_plugins/pdfcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "PdfCraft",
"displayName_i18n": {
"en": "PdfCraft",
Expand All @@ -931,7 +942,9 @@
"name": "designcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/designcraft/icon.png",
"source": "./external_plugins/designcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "DesignCraft",
"displayName_i18n": {
"en": "DesignCraft",
Expand All @@ -958,7 +971,9 @@
"name": "wordcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/wordcraft/icon.png",
"source": "./external_plugins/wordcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "WordCraft",
"displayName_i18n": {
"en": "WordCraft",
Expand All @@ -985,7 +1000,9 @@
"name": "gridcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/gridcraft/icon.png",
"source": "./external_plugins/gridcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "GridCraft",
"displayName_i18n": {
"en": "GridCraft",
Expand All @@ -1012,7 +1029,9 @@
"name": "deckcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/deckcraft/icon.png",
"source": "./external_plugins/deckcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "DeckCraft",
"displayName_i18n": {
"en": "DeckCraft",
Expand All @@ -1039,7 +1058,9 @@
"name": "cadcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/cadcraft/icon.png",
"source": "./external_plugins/cadcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "CADCraft",
"displayName_i18n": {
"en": "CADCraft",
Expand All @@ -1066,7 +1087,9 @@
"name": "soundcraft",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/soundcraft/icon.png",
"source": "./external_plugins/soundcraft",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "SoundCraft",
"displayName_i18n": {
"en": "SoundCraft",
Expand Down Expand Up @@ -1149,7 +1172,9 @@
},
"category": "developer-tools",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/kicad/icon.png",
"componentTypes": ["ui"],
"componentTypes": [
"ui"
],
"displayName": "KiCad",
"displayName_i18n": {
"en": "KiCad",
Expand Down Expand Up @@ -1443,6 +1468,42 @@
"mcp",
"verification"
]
},
{
"name": "voicetranser",
"source": "./external_plugins/voicetranser",
"icon": "https://cdn-zcode.z.ai/zcode/official-plugin/assets/voicetranser/icon.png",
"description": "Local push-to-talk voice input for macOS: hold a global hotkey, speak, release — transcription is pasted at your cursor. Fully local STT (Qwen3-ASR MLX, SenseVoice, mlx-whisper), zero external APIs. The bundled skill guides your agent through install, hotkey wiring, launchd setup and troubleshooting.",
"description_i18n": {
"en": "Local push-to-talk voice input for macOS: hold a global hotkey, speak, release — transcription is pasted at your cursor. Fully local STT (Qwen3-ASR MLX, SenseVoice, mlx-whisper), zero external APIs. The bundled skill guides your agent through install, hotkey wiring, launchd setup and troubleshooting.",
"zh-CN": "macOS 本地按住说话语音输入:按住全局热键说话、松开即转写粘贴到光标处。纯本地 STT(Qwen3-ASR MLX / SenseVoice / mlx-whisper),零外部 API。内置技能引导 agent 完成安装、热键接线、launchd 常驻与排障。"
},
"version": "1.0.3",
"author": {
"name": "Lumos-789",
"url": "https://github.com/Lumos-789"
},
"category": "productivity",
"keywords": [
"voice-input",
"speech-to-text",
"dictation",
"macos",
"push-to-talk",
"local-first",
"qwen3-asr",
"sensevoice"
],
"examplePrompts": [
"Install VoiceTranser and wire my right Option key for push-to-talk",
"语音输入装一下,右 Option 按住说话"
],
"examplePrompts_i18n": {
"zh-CN": [
"语音输入装一下,右 Option 按住说话",
"转写没粘贴出来,帮我排查 VoiceTranser"
]
}
}
]
}
}