{"id":51217775,"url":"https://github.com/appautomaton/tnt-asr","last_synced_at":"2026-06-28T05:03:13.469Z","repository":{"id":338511344,"uuid":"1157979774","full_name":"appautomaton/tnt-asr","owner":"appautomaton","description":"Terminal voice-to-text TUI — Qwen3-ASR-1.7B on the Apple GPU via MLX (mlx-speech). Fully local, no PyTorch, transcribes in ~1s. macOS Apple Silicon.","archived":false,"fork":false,"pushed_at":"2026-06-22T17:41:48.000Z","size":367,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-06-22T19:24:02.890Z","etag":null,"topics":["apple-silicon","asr","dictation","macos","mlx","on-device-ai","python","qwen","speech-recognition","speech-to-text","terminal","tui","voice-to-text","whisper-alternative"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/automaton-tnt/","language":"Python","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/appautomaton.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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-14T15:56:37.000Z","updated_at":"2026-06-22T17:41:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/appautomaton/tnt-asr","commit_stats":null,"previous_names":["appautomaton/vox-asr-tui"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/appautomaton/tnt-asr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appautomaton%2Ftnt-asr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appautomaton%2Ftnt-asr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appautomaton%2Ftnt-asr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appautomaton%2Ftnt-asr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appautomaton","download_url":"https://codeload.github.com/appautomaton/tnt-asr/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appautomaton%2Ftnt-asr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34877472,"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-28T02:00:05.809Z","response_time":54,"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":["apple-silicon","asr","dictation","macos","mlx","on-device-ai","python","qwen","speech-recognition","speech-to-text","terminal","tui","voice-to-text","whisper-alternative"],"created_at":"2026-06-28T05:03:12.575Z","updated_at":"2026-06-28T05:03:13.464Z","avatar_url":"https://github.com/appautomaton.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TNT 🧨\n\n[![Website](https://img.shields.io/badge/website-appautomaton.github.io-ff4fd8?logo=github\u0026logoColor=white)](https://appautomaton.github.io/tnt-asr/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![PyPI](https://img.shields.io/badge/PyPI-automaton--tnt-3775A9?logo=pypi\u0026logoColor=white)](https://pypi.org/project/automaton-tnt/)\n[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)\n[![Platform](https://img.shields.io/badge/platform-Apple%20Silicon-black?logo=apple)](https://developer.apple.com/documentation/apple-silicon)\n\n**🌐 [appautomaton.github.io/tnt-asr](https://appautomaton.github.io/tnt-asr/)** — the project landing page.\n\nTerminal voice-to-text. Tap \u003ckbd\u003eSpace\u003c/kbd\u003e, speak, tap \u003ckbd\u003eSpace\u003c/kbd\u003e — your words land in the transcript and on the clipboard.\n\nQwen3-ASR-1.7B runs in-process on the Apple GPU via [mlx-speech](https://github.com/appautomaton/mlx-speech) as an 8-bit (int8) quantized checkpoint — ~2.5 GB resident: the model loads once, stays resident, and transcribes a short take in a fraction of a second. Fully local — no cloud, no runtime network calls. The microphone is captured natively through AVFoundation by a small Swift helper process, so a misbehaving audio stack can never trap the mic: TNT just kills the helper and macOS releases it.\n\n\u003e [!NOTE]\n\u003e Using Termux on Android? Use the preserved\n\u003e `legacy/android-termux-qwen0.6b` branch instead of `master`.\n\u003e It is a legacy proot setup and may need device-specific fixes; validate it\n\u003e locally and adapt it with your own tools or agentic AI workflow.\n\u003e\n\u003e ```bash\n\u003e git fetch origin\n\u003e git switch --track origin/legacy/android-termux-qwen0.6b\n\u003e ```\n\n## Features\n\n- **In-process GPU inference** — pure MLX, no PyTorch\n- **8-bit quantized** — int8 weights (~2.5 GB), about half the memory of BF16 with a faster decode\n- **Resident model** — loads once in the background at startup; every take is warm\n- **Native mic capture** — AVFoundation via an isolated Swift helper process; the mic can always be reclaimed\n- **English, Chinese, and mixed speech** — language auto-detected, or forced via env var\n- **Live braille oscilloscope** — real audio levels while you record\n- **Clipboard-first** — new transcriptions auto-copy; click any past entry to copy it again\n- **Responsive TUI** — side-rail layout on wide terminals, stacked on narrow ones\n\n## Setup\n\n\u003e [!IMPORTANT]\n\u003e Requires an Apple Silicon Mac (M1 or later), Python 3.13+,\n\u003e [uv](https://docs.astral.sh/uv/), and the Xcode command line tools\n\u003e (`xcode-select --install`) — the mic capture helper is compiled from Swift\n\u003e on first launch and cached.\n\n```bash\ngit clone https://github.com/appautomaton/tnt-asr.git\ncd tnt-asr\nuv sync\n./bootstrap-mlx-asr.sh        # downloads + links the int8 checkpoint (~2.5 GB, cached by Hugging Face)\nuv run tnt\n```\n\nOr install from PyPI ([`automaton-tnt`](https://pypi.org/project/automaton-tnt/)):\n\n```bash\nuv tool install automaton-tnt\nTNT_MLX_MODEL=/path/to/qwen3-asr-1.7b-int8-mlx tnt\n```\n\n(Instead of exporting `TNT_MLX_MODEL`, you can symlink the checkpoint at\n`~/.local/share/tnt/qwen3-asr-mlx`.)\n\n### Model checkpoint\n\nTNT expects a converted Qwen3-ASR-1.7B MLX checkpoint. A ready-to-use int8\nbuild (~2.5 GB) is published at\n[appautomaton/qwen3-asr-1.7b-int8-mlx](https://huggingface.co/appautomaton/qwen3-asr-1.7b-int8-mlx).\nThe bootstrap script takes three forms:\n\n```bash\n./bootstrap-mlx-asr.sh                       # download the int8 build from Hugging Face, then link it\n./bootstrap-mlx-asr.sh \u003chf-repo-id\u003e          # download a specific Hugging Face repo\n./bootstrap-mlx-asr.sh /path/to/checkpoint   # link a checkpoint you already have (no download)\n```\n\nDownloads use `huggingface_hub` (already installed via mlx-speech) and land in\nthe shared Hugging Face cache (`~/.cache/huggingface`); the script symlinks\n`bin/qwen3-asr-mlx` to the cached snapshot. It is idempotent — if the model is\nalready cached, or you pass a local path, nothing is re-downloaded, so you\nnever keep two copies of the 2.5 GB weights. BF16 and mxfp8 builds work too —\nmlx-speech reads the quantization from the checkpoint's `config.json`, so\nswitching is just a relink. Alternatively, convert the upstream\n[Qwen/Qwen3-ASR-1.7B](https://huggingface.co/Qwen/Qwen3-ASR-1.7B) weights\nyourself with [mlx-speech](https://github.com/appautomaton/mlx-speech)'s\n`scripts/convert/qwen3_asr.py`.\n\n## Configuration\n\n| Environment variable | Default | Description |\n|----------------------|---------|-------------|\n| `TNT_MLX_MODEL` | `bin/qwen3-asr-mlx`, else `~/.local/share/tnt/qwen3-asr-mlx` | Path to the converted MLX checkpoint |\n| `TNT_MLX_LANGUAGE` | `auto` | `Chinese`, `English`, or `auto`. Use `Chinese` to keep mixed Chinese/English speech from being translated to English |\n| `TNT_INPUT_DEVICE` | system default | Microphone, by index or name |\n| `TNT_CAPTURE_BACKEND` | `auto` | macOS always uses native AVFoundation (needs the Xcode command line tools: `xcode-select --install`); other platforms use PortAudio. `portaudio` is rejected on macOS |\n\n## Keybindings\n\n| Key | Action |\n|-----|--------|\n| \u003ckbd\u003eSpace\u003c/kbd\u003e | Start / stop recording, or hold to record until release; cancels during transcription |\n| \u003ckbd\u003ec\u003c/kbd\u003e | Copy the last transcript entry |\n| mouse click | Copy the clicked transcript entry |\n| \u003ckbd\u003ex\u003c/kbd\u003e | Clear the transcript |\n| \u003ckbd\u003eq\u003c/kbd\u003e | Quit |\n\n## Project structure\n\n```text\nsrc/tnt/\n├── app.py             # Textual TUI, state machine, keybindings\n├── audio.py           # Recorder protocol, backend selection, PortAudio (non-macOS)\n├── avf_audio.py       # Native AVFoundation capture via helper process (macOS)\n├── mic_helper.swift   # AVFoundation helper source, compiled on demand\n├── async_threads.py   # Daemon-thread helpers for blocking work\n├── transcriber.py     # In-process MLX Qwen3-ASR transcription\n└── widgets/\n    ├── transcript.py  # Scrollable transcript log\n    └── status.py      # Braille oscilloscope + state rail\nbin/\n└── qwen3-asr-mlx      # Symlink to converted MLX checkpoint (gitignored)\n```\n\n\u003e [!TIP]\n\u003e The inference path expects 16 kHz mono PCM WAV; the recorder produces exactly\n\u003e that. Cancelling a transcription abandons its result — the in-process\n\u003e generation cannot be killed mid-flight and quietly finishes in the background.\n\n## Related projects\n\n- [mlx-speech](https://github.com/appautomaton/mlx-speech) — our MLX-native speech runtime that powers TNT ([PyPI](https://pypi.org/project/mlx-speech/))\n- [qwen3-asr-1.7b-int8-mlx](https://huggingface.co/appautomaton/qwen3-asr-1.7b-int8-mlx) — our int8 MLX checkpoint that TNT runs (converted from Qwen3-ASR-1.7B)\n\n## More from appautomaton\n\n- 🌐 [appautomaton.github.io](https://appautomaton.github.io) — our site\n- 🤗 [huggingface.co/appautomaton](https://huggingface.co/appautomaton) — our models and checkpoints on Hugging Face\n- 🐙 [github.com/appautomaton](https://github.com/appautomaton) — our open-source projects\n\n## License\n\nMIT. See [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappautomaton%2Ftnt-asr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappautomaton%2Ftnt-asr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappautomaton%2Ftnt-asr/lists"}