2.2 KiB
2.2 KiB
Transui design
- Linux is a GTK3 desktop recorder. It supports hosted transcription with an optional local fallback and can type at the cursor or copy to the clipboard.
- macOS is a SwiftUI menu bar recorder targeting macOS 15. It supports the same hosted-first, local-fallback behavior as Linux, a global recording hotkey, launch at login, cursor typing, and clipboard output. When hosted-first is off, use local only. Its compact floating recorder uses teal level bars for recording feedback.
- Android is remote-only. It provides an Android
RecognitionService, a voice-only input method, and a floating recognition activity. Do not add a local llama.cpp path to Android. - All clients upload 16 kHz mono, 32 kbps MP3 to OpenAI-compatible
/v1/audio/transcriptionsendpoints and clean only the Qwen3-ASRlanguage …<astext>orlanguage …<asr_text>prefix. - MP3 encoding uses the
third_party/shinesubmodule pinned toab5e3526b64af1a2eaa43aa6f441a7312e013519(3.1.1-59-gab5e352). - Generate the macOS Xcode project from
macos/project.ymlwith XcodeGen. Treat the spec as the source of truth and leavemacos/Transui.xcodeprojuntracked. - The Android voice UI is an opaque, compact system surface. Teal is the recording signal.
PushToTalkButtondraws the Apps and Stop Circle glyphs with Canvas because the target device dropsImageButtonimage layers. Keep the glyphs drawn above the button background.
llama.cpp local endpoint
The Linux and macOS local fallback uses this multipart request. response_format=json
is required; prompt is optional and may request transcription or translation.
curl -s -X POST -F response_format=json http://localhost:8080/v1/audio/transcriptions \
-F file="@test.mp3" \
-F 'prompt=Transcribe the following speech segment in English, and translate them into chinese.'
llama.cpp may return an event envelope instead of a bare OpenAI response:
{"type":"transcript.text.done","text":"这是个测试。你能听到什么?我希望这很好。","usage":{"type":"tokens","input_tokens":241,"output_tokens":516,"total_tokens":757,"input_tokens_details":{"cached_tokens":0}}}
Use text as the transcript. Accept transcript.text.done; do not require a
bare { "text": "…" } response.