mirror of
https://github.com/techieyann/frame-voice.git
synced 2026-10-18 02:01:31 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2163df4d0 | ||
|
|
1ad2604a74 | ||
|
|
f3fbfb4c5e | ||
|
|
5439c4ec6d |
No files matched your search
Generated
+1
-1
@@ -66,7 +66,7 @@ checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
|
||||
|
||||
[[package]]
|
||||
name = "frame-voice"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cc",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "frame-voice"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
description = "Controller-triggered Steam Frame dictation"
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
Voice dictation for Steam Frame. Speak into a text field using your controllers,
|
||||
without a keyboard or an always-on microphone.
|
||||
|
||||
Works in the Desktop app and standalone desktop apps while Steam is in gamepad
|
||||
mode. Dictation is unavailable in the Steam interface and VR games.
|
||||
**Desktop** is the Frame's built-in desktop session. **Standalone apps**, such as
|
||||
Firefox launched directly from Steam, run outside Desktop. Frame Voice types
|
||||
into both; accented and non-Latin text currently requires a standalone app.
|
||||
Dictation is unavailable inside Steam menus and VR games.
|
||||
|
||||
## Install on your Frame
|
||||
|
||||
@@ -20,75 +22,50 @@ mode. Dictation is unavailable in the Steam interface and VR games.
|
||||
curl -fsSL https://raw.githubusercontent.com/techieyann/frame-voice/main/get.sh | sh
|
||||
```
|
||||
|
||||
3. Follow setup to choose how your speech is transcribed. If asked, enter your
|
||||
SteamOS administrator password to allow text input. If you have never set
|
||||
3. The GUI installer opens in Desktop. Choose how your speech is transcribed.
|
||||
If asked, enter your SteamOS administrator password to allow text input. If you have never set
|
||||
that password, run `passwd` in Konsole first.
|
||||
4. Find the Frame Voice microphone icon in the Desktop tray.
|
||||
|
||||
## Choose transcription and language
|
||||
|
||||
| Option | What you need | Why choose it |
|
||||
| --- | --- | --- |
|
||||
| **Groq · Cloud** | Internet and a [Groq API key](https://console.groq.com/keys) | Speech is sent to Groq for transcription; no local model download |
|
||||
| **Local · Fast** | A model download of about 142 MiB | Transcription runs on your Frame and works offline after setup |
|
||||
| **Local · Balanced** | A model download of about 466 MiB | Favors accuracy over speed and works offline after setup |
|
||||
| Transcription option | Speed | Internet needed | Requirements |
|
||||
| --- | --- | --- | --- |
|
||||
| **Groq · Cloud** | Fastest | Every dictation | [API key](https://console.groq.com/keys) |
|
||||
| **Local · Fast** | Fast | Initial download only | ~142MiB |
|
||||
| **Local · Balanced** | Slow | Initial download only | ~466MiB |
|
||||
|
||||
The local options process speech on your Frame; the larger model favors accuracy.
|
||||
|
||||
Choose **Language** in the Transcription tab, or **Automatic detection** if you
|
||||
use more than one language. Local setup downloads the appropriate English or
|
||||
multilingual model. Groq needs no language-specific download.
|
||||
|
||||
For accented characters or non-Latin scripts, use a standalone app such as
|
||||
Firefox. These characters are not yet supported inside the nested Desktop.
|
||||
|
||||
## Try your first dictation
|
||||
|
||||
1. Open an app and focus the text field you want to fill.
|
||||
1. Open Firefox, start a new tab, and click its address bar.
|
||||
2. Briefly touch either joystick cap, lift your thumb, then touch it again and hold.
|
||||
3. Wait for the start tone and microphone badge, then speak.
|
||||
4. Lift your thumb to finish. Wait for the transcription to appear.
|
||||
|
||||
Click the joystick during recording to cancel. After text appears, **A** submits
|
||||
and releasing **B** clears; the left D-pad right/left do the same. Submit and clear are
|
||||
and releasing **X** clears; the left D-pad right/left do the same. These actions are
|
||||
available briefly after dictation and stop when you change focus. Nothing submits
|
||||
automatically.
|
||||
|
||||
Open **Configure…** in the tray to customize Frame Voice. See the
|
||||
[settings guide](docs/SETTINGS.md) for the General, Transcription, and Controllers tabs.
|
||||
|
||||
## Updates
|
||||

|
||||
|
||||
Use **Configure… → General → Check for updates**. Updates preserve saved settings,
|
||||
API keys, and downloaded models. See [updating Frame Voice](docs/SETTINGS.md#updates).
|
||||
*The configuration window: choose a transcription path and language, then save.*
|
||||
|
||||
## If something does not work
|
||||
|
||||
- **No tone or microphone badge:** focus an app's text field, check that dictation
|
||||
is running in the tray, and try Restart dictation. A plain hold does not trigger
|
||||
recording; it must be tap, release, then hold.
|
||||
- **Groq produces no text:** check your internet connection and API key.
|
||||
- **Local setup fails:** check free storage and internet access for the first download.
|
||||
- **Need more detail:** choose View recent logs in the tray, or see
|
||||
[troubleshooting and configuration](docs/CONFIGURATION.md).
|
||||
Check that dictation is running in the tray and that an app's text field is
|
||||
focused. Use **View recent logs** in the tray for more detail, or follow the
|
||||
[troubleshooting guide](docs/TROUBLESHOOTING.md).
|
||||
|
||||
## For developers and agents
|
||||
|
||||
The installer provides `./install-gui.sh` for GUI setup, `--gui` for Desktop
|
||||
setup, and `--tui` for a terminal menu. Agents can use explicit flags without
|
||||
interactive dialogs:
|
||||
|
||||
```sh
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray \
|
||||
--non-interactive --backend local-fast --language auto
|
||||
```
|
||||
|
||||
For Groq, use `--backend groq --language en --groq-key-file /path/to/key`.
|
||||
Noninteractive setup requires input permissions to be configured already.
|
||||
|
||||
`frame-voice --version` shows the version and build revision.
|
||||
`frame-voice --check-updates --json` returns update status; use
|
||||
`~/.local/share/frame-voice/update.sh --tui` for a guided terminal update.
|
||||
See the [configuration reference](docs/CONFIGURATION.md) for advanced settings.
|
||||
|
||||
[Installation and removal](docs/INSTALLATION.md) ·
|
||||
[Settings by tab](docs/SETTINGS.md) ·
|
||||
[Builds and release channels](docs/DISTRIBUTION.md) · [MIT license](LICENSE)
|
||||
[Settings](docs/SETTINGS.md) · [Troubleshooting](docs/TROUBLESHOOTING.md) ·
|
||||
[Release notes](docs/RELEASE-NOTES.md) · [Developer guide](docs/DEVELOPMENT.md) ·
|
||||
[License](LICENSE)
|
||||
@@ -12,7 +12,7 @@
|
||||
{ "inputs": { "click": { "output": "/actions/voicedict/in/submit" } },
|
||||
"mode": "button", "path": "/user/hand/right/input/a" },
|
||||
{ "inputs": { "click": { "output": "/actions/voicedict/in/clear" } },
|
||||
"mode": "button", "path": "/user/hand/right/input/b" },
|
||||
"mode": "button", "path": "/user/hand/right/input/x" },
|
||||
{ "inputs": { "click": { "output": "/actions/voicedict/in/submit" } },
|
||||
"mode": "button", "path": "/user/hand/left/input/dpad_right" },
|
||||
{ "inputs": { "click": { "output": "/actions/voicedict/in/clear" } },
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" color="#FFFFFF"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M14 58V14H58" stroke="#FFFFFF" stroke-width="4"/><g transform="translate(40 40) rotate(-45) scale(1.45) translate(-43 -43)" stroke-width="2.8"><rect x="39" y="31" width="8" height="14" rx="4"/><path d="M34 39v3a9 9 0 0 0 18 0v-3M43 51v5M39 56h8"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" color="#FFFFFF"><defs><mask id="cut"><rect width="72" height="72" fill="white"/><path d="M22.6 57.4L57.4 22.6" fill="none" stroke="black" stroke-width="9.425" stroke-linecap="round"/></mask></defs><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M14 58V14H58" stroke="#FFFFFF" stroke-width="4"/><g mask="url(#cut)"><g transform="translate(40 40) rotate(-45) scale(1.45) translate(-43 -43)" stroke-width="2.8"><rect x="39" y="31" width="8" height="14" rx="4"/><path d="M34 39v3a9 9 0 0 0 18 0v-3M43 51v5M39 56h8"/></g></g><path d="M22.6 57.4L57.4 22.6" stroke-width="4.35"/></g></svg>
|
||||
|
After Width: | Height: | Size: 688 B |
+19
-115
@@ -1,71 +1,41 @@
|
||||
# Configuration reference
|
||||
# Advanced configuration reference
|
||||
|
||||
For the configuration window, read [Settings by tab](SETTINGS.md). This reference
|
||||
covers terminal configuration, advanced options, and diagnostics.
|
||||
For the GUI, read [Settings by tab](SETTINGS.md). This page is for developers and
|
||||
agents editing `~/.config/frame-voice/env`. Use literal `KEY=VALUE` entries, not
|
||||
shell commands; keep configuration/key files mode 600. Restart dictation after
|
||||
editing the file.
|
||||
|
||||
You can also edit
|
||||
`~/.config/frame-voice/env`. Settings are literal `KEY=VALUE`, never shell commands.
|
||||
Restart `frame-voice` after changing them. Configuration and key files should be
|
||||
mode 600.
|
||||
|
||||
## Backend
|
||||
|
||||
First-run setup offers three choices:
|
||||
|
||||
| Choice | Use | What setup does |
|
||||
| --- | --- | --- |
|
||||
| Groq — Cloud | Fast online transcription | Requests your [Groq API key](https://console.groq.com/keys) |
|
||||
| Local — Fast | Offline transcription, favoring speed | Downloads and verifies `base.en` or multilingual `base` (~142 MiB) |
|
||||
| Local — Balanced | Offline transcription, more detail with more processing | Downloads and verifies `small.en` or multilingual `small` (~466 MiB) |
|
||||
|
||||
Local choices need no Groq key and work offline after the download. The Whisper
|
||||
engine is included. Existing verified models are reused. The key is saved only
|
||||
in your mode-600 config and is never printed. Updates preserve your current choice.
|
||||
Switch in the Transcription tab, or rerun the installer with `--backend groq`, `--backend local-fast` or
|
||||
`--backend local-balanced`. `--groq-key-file PATH` reads a key without placing it
|
||||
in command arguments. Local English presets select `VOICE_LANG=en`.
|
||||
|
||||
The searchable Language menu offers automatic detection and 99 named languages.
|
||||
English uses the `.en` local model; other languages and automatic detection use
|
||||
multilingual models. Set `--language CODE` during installation or `VOICE_LANG`
|
||||
in configuration (`en`, `es`, `fr`, `ja`, etc.; `auto` for detection). Groq omits
|
||||
its optional language parameter for automatic detection; whisper-cli receives
|
||||
`-l auto`. Cleanup is instructed to preserve the original language and script.
|
||||
[Groq language parameters](https://console.groq.com/docs/speech-to-text) ·
|
||||
[Whisper model variants and checksums](https://github.com/ggml-org/whisper.cpp/blob/v1.9.4/models/README.md).
|
||||
|
||||
Non-ASCII transcripts use clipboard paste automatically in standalone apps with
|
||||
a known window class. Nested Desktop's classless target still cannot safely
|
||||
receive Unicode through keyboard injection; that path refuses Unicode instead
|
||||
of typing corrupted text. Spoken action aliases remain English; A/B and D-pad
|
||||
controls work independently of transcription language. Models for both variants
|
||||
appear separately in Downloaded models and can be deleted when unused.
|
||||
|
||||
Configuration loads from the compatible `~/.config/voice-prompt/env`, then
|
||||
Values load from the compatible `~/.config/voice-prompt/env`, then
|
||||
`~/.config/frame-voice/env`, then process environment; later values win.
|
||||
|
||||
## Controls
|
||||
|
||||
Tap a joystick cap, release, then touch it again and hold to record. Release ends
|
||||
recording. A plain hold does nothing. Click the stick during recording to cancel.
|
||||
The blue microphone grows during startup; the spinning gear indicates processing;
|
||||
In the headset, the blue microphone grows during startup; the spinning gear indicates processing;
|
||||
the red crossed-out mic indicates cancellation or insufficient speech.
|
||||
|
||||
After successful dictation, A submits and B clears after the button is released; the left D-pad right/left
|
||||
After successful dictation, A submits and X clears after the button is released; the left D-pad right/left
|
||||
provide submit/clear. These actions expire after ten seconds or a focus change.
|
||||
Unknown targets refuse clear rather than guessing. Speech commands match exact
|
||||
whole utterances: "submit", "send", "enter"; "scratch that", "clear", "undo";
|
||||
and "cancel" or "never mind". Ordinary phrases remain text.
|
||||
|
||||
|
||||
The Desktop tray is separate: white microphone when running, white crossed-out
|
||||
microphone when disabled.
|
||||
## Common settings
|
||||
|
||||
| Setting | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `VOICE_BACKEND` | `groq` | `groq` or `local`; setup selects the local model |
|
||||
| `VOICE_LANG` | `en` | Language code or `auto` for automatic detection |
|
||||
| `VOICE_MODEL` | Set by local setup | Verified local model file selected by the installer |
|
||||
| `VOICE_INJECT` | `type` | `type` or clipboard `paste` |
|
||||
| `VOICE_PASTE_CHUNK` | `0` | Maximum characters per paste; 0 disables splitting |
|
||||
| `VOICE_TRAILING` | `space` | Separator after dictation (`space` or `none`) |
|
||||
| `VOICE_BEEP` | `1` | Feedback tones |
|
||||
| `VOICE_NOTIFY` | `1` | Headset badge and usage warnings |
|
||||
| `VOICE_NOTIFY` | `1` | Headset microphone badges |
|
||||
| `VOICE_CLEANUP` | `1` | Optional Groq text cleanup |
|
||||
| `VOICE_SLASH` | `0` | Optional interpretation of spoken "slash" as `/` during cleanup |
|
||||
| `GROQ_USAGE_NOTIFY` | `1` | Groq usage/limit notifications; separate from microphone badges |
|
||||
@@ -87,74 +57,8 @@ Per-hand mappings: `VRBTN_DICTATE_LEFT/RIGHT`, `VRBTN_SUBMIT_LEFT/RIGHT`,
|
||||
the controller binding on service restart. More settings and validation are in
|
||||
`src/config.rs` and the installer-generated config template.
|
||||
|
||||
## Groq prompt customization
|
||||
|
||||
**Edit cleanup prompt…** under Groq opens the built-in editor. Apply your draft,
|
||||
then use the shared Save settings button to write
|
||||
`~/.config/frame-voice/groq-prompt.txt`. Reset to default restores the shipped
|
||||
text in the editor; canceling discards the editor draft. The shipped template is
|
||||
[`assets/groq-prompt.txt`](../assets/groq-prompt.txt): neutral dictation cleanup,
|
||||
original-language preservation, and no invented content. It is loaded for each
|
||||
cleanup request, so edits apply to the next dictation. `GROQ_PROMPT_FILE` can
|
||||
override its location. An absent file uses the neutral embedded default.
|
||||
|
||||
Feedback keeps one PulseAudio-compatible speaker stream warm for the current
|
||||
dictation job, instead of opening a player per cue. It releases the stream when
|
||||
the job and final cue finish; the microphone is still gesture-controlled.
|
||||
The small activation badge waits for capture and speaker startup before growing.
|
||||
Its growth and start cue then share a clock, accounting for a cold first stream
|
||||
without adding a fixed delay to already-warm recordings. With tones disabled,
|
||||
only capture readiness is required.
|
||||
`PAPLAY_BIN` retains the external-player override/fallback behavior.
|
||||
|
||||
Silence detection combines an adaptive volume floor, cue-tone rejection, and
|
||||
WebRTC voice activity detection from SteamOS's existing
|
||||
`libwebrtc-audio-processing-2` library. Voice and volume evidence must agree on
|
||||
the same audio for `VOICE_MIN_SPEECH_MS`; a cue followed by unrelated noise cannot
|
||||
satisfy the two checks independently. No extra speech model is downloaded.
|
||||
If the optional system library is unavailable, the portable volume/cue gate remains
|
||||
active. `VRBTN_DEBUG=1` logs the gate decision and VAD result without transcripts.
|
||||
No ordinary phrase such as “Yeah,” “you,” or “Thank you” is blocked by text.
|
||||
Groq's [detailed response](https://console.groq.com/docs/speech-to-text) provides
|
||||
`avg_logprob` and `no_speech_prob`. After the local gate, Frame Voice cancels if
|
||||
every returned segment has a decoding score below `GROQ_ASR_MIN_LOGPROB` or a
|
||||
no-speech probability above `GROQ_ASR_MAX_NO_SPEECH`. These are diagnostic scores,
|
||||
not calibrated accuracy percentages. Missing scores retain the local audio gate.
|
||||
Debug logging includes numeric scores and decisions, never transcript text.
|
||||
|
||||
Desktop clear counts the trailing separator too. For right-hand B with the default
|
||||
Steam layout, it also counts the space B itself types into Desktop. Other bindings
|
||||
and spoken Clear do not add that character. Set `VRBTN_CLEAR_B_SPACE=0` if your
|
||||
custom Steam B mapping does not type a space. Its count belongs to the
|
||||
running daemon, so a service restart resets that history. Test clear using a
|
||||
fresh dictation after changing settings or restarting the service.
|
||||
|
||||
Spoken-slash conversion is an optional toggle and is off by default; personal
|
||||
preferences belong in user configuration. ASR hints are separate and remain empty
|
||||
by default (`VOICE_PROMPT_TEXT`). API keys, personalized prompt files, and model
|
||||
downloads are excluded from release packaging.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```sh
|
||||
~/.local/bin/frame-voice --check
|
||||
systemctl --user status frame-voice frame-voice-tray-session
|
||||
journalctl --user -u frame-voice -n 50 --no-pager
|
||||
```
|
||||
|
||||
`--check` validates configuration and compiled OpenVR support, not credentials,
|
||||
network access or headset health. Focus changes cancel pending results; text
|
||||
already delivered cannot be recalled. Silence makes no transcription request.
|
||||
|
||||
## Version and updates
|
||||
|
||||
`frame-voice --version` and `--build-info` report the package version, source
|
||||
revision, dirty-source marker, and compiled OpenVR capability. Release metadata
|
||||
is trusted only when its source commit matches the binary. Unpackaged/local
|
||||
builds are shown as development versions.
|
||||
|
||||
Use General → Check for updates, or `frame-voice --check-updates --json`.
|
||||
Checks compare stable release versions; they neither select experimental releases
|
||||
nor downgrade newer versions. The GUI's Update action opens the transactional
|
||||
installer after settings are saved. `~/.local/share/frame-voice/update.sh --tui`
|
||||
provides the terminal path. No background polling or automatic update is enabled.
|
||||
Backend flags are documented in the [developer guide](DEVELOPMENT.md).
|
||||
For signal gating, prompt handling, and text delivery internals, see
|
||||
[design notes](DESIGN.md). Diagnostics are maintained in
|
||||
[troubleshooting](TROUBLESHOOTING.md#diagnostics).
|
||||
@@ -0,0 +1,70 @@
|
||||
# Frame Voice design notes
|
||||
|
||||
This is an implementation reference. End users should start with
|
||||
[settings](SETTINGS.md) or [troubleshooting](TROUBLESHOOTING.md).
|
||||
|
||||
## Capture and feedback
|
||||
|
||||
The accepted leading tap prearms microphone capture and a PulseAudio-compatible
|
||||
speaker stream. The activation badge waits for capture/output readiness before
|
||||
spending its growth interval. The start cue and animation use that clock, with a
|
||||
playback lead. Speaker writes provide pacing; an additional per-write sleep would
|
||||
cause underruns. The stream closes when the job and final cue finish.
|
||||
`PAPLAY_BIN` retains the external-player override/fallback.
|
||||
|
||||
Headset feedback uses a growing blue microphone, a processing gear, and a red
|
||||
crossed-out microphone for cancellation or insufficient speech. The Desktop tray
|
||||
uses separate white running/disabled vectors, with the Frame corner mark.
|
||||
|
||||
## Speech evidence and ASR confidence
|
||||
|
||||
The local gate combines DC-free energy, an adaptive ambient floor, cue-frequency
|
||||
rejection, and optional WebRTC VAD from SteamOS's
|
||||
`libwebrtc-audio-processing-2`. Volume and VAD must agree on the same audio run
|
||||
for `VOICE_MIN_SPEECH_MS`. A cue followed by unrelated noise cannot supply the
|
||||
two kinds of evidence independently. No additional VAD model is downloaded.
|
||||
Without the optional system library, the portable energy/cue gate remains.
|
||||
|
||||
Groq's [verbose response](https://console.groq.com/docs/speech-to-text) exposes
|
||||
`avg_logprob` and `no_speech_prob`. A result is cancelled when every segment
|
||||
reports a decoding score below `GROQ_ASR_MIN_LOGPROB` or no-speech probability
|
||||
above `GROQ_ASR_MAX_NO_SPEECH`. These scores are not calibrated accuracy
|
||||
percentages. Missing metadata retains the local audio gate. Debug logs include
|
||||
numeric scores and decisions, never transcripts or keys.
|
||||
|
||||
No ordinary phrase, including “Yeah,” “you,” or “Thank you,” is banned by text.
|
||||
Detection and transcription can still mistake environmental sounds for voice.
|
||||
|
||||
## Prompt handling
|
||||
|
||||
The managed custom prompt is `~/.config/frame-voice/groq-prompt.txt`; the shipped
|
||||
neutral template is [assets/groq-prompt.txt](../assets/groq-prompt.txt).
|
||||
`GROQ_PROMPT_FILE` can override its location. An absent file uses the embedded
|
||||
neutral default. Cleanup loads the prompt for each request and preserves the
|
||||
original language/script. ASR hints are separate (`VOICE_PROMPT_TEXT`).
|
||||
User keys, custom prompts, and model downloads are excluded from releases.
|
||||
|
||||
## Context and delivery
|
||||
|
||||
Context observes the outer gamescope/X11 app focus. The built-in Desktop is a
|
||||
nested Plasma session; an inner app/field change may not change that outer
|
||||
context. ASCII text follows keyboard focus through uinput. Unicode uses a
|
||||
clipboard helper for supported standalone apps with a known window class;
|
||||
unsupported Desktop Unicode is refused rather than corrupted.
|
||||
|
||||
Desktop Clear backspaces the tracked insertion, including its separator.
|
||||
Default right X adds no controller character. If right B is explicitly selected,
|
||||
optional native-space accounting is scoped to its action origin and Desktop.
|
||||
Controller Clear waits for release and a short settle interval. Changed context,
|
||||
unavailable input, and expired pending actions cancel it.
|
||||
|
||||
The count belongs to the current process and resets at restart. Cursor movement
|
||||
or unobserved inner-field edits can invalidate ownership. It is not a persistent
|
||||
text-selection or accessibility model.
|
||||
|
||||
## Installer architecture
|
||||
|
||||
See [installer internals](INSTALLER.md) for transactional replacement, input
|
||||
permissions, helper migration, and rollback. Packaging uses an explicit allowlist
|
||||
and records checksums/source commit; release versions are documented in
|
||||
[distribution](DISTRIBUTION.md).
|
||||
@@ -0,0 +1,67 @@
|
||||
# Developer and agent guide
|
||||
|
||||
End-user setup is in the [README](../README.md). GUI settings and common failures
|
||||
are covered by [Settings](SETTINGS.md) and [Troubleshooting](TROUBLESHOOTING.md).
|
||||
|
||||
## Guided and automated installation
|
||||
|
||||
The default downloader selects the GUI when Desktop is open, including a
|
||||
Desktop session discovered from SSH. Without Desktop it opens the terminal menu.
|
||||
Use `--tui` to explicitly select a terminal menu. Explicit backend flags use the
|
||||
scripted path; `--non-interactive` forbids prompts.
|
||||
|
||||
From an extracted bundle or native build:
|
||||
|
||||
```sh
|
||||
./install-gui.sh
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --gui
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --tui
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray \
|
||||
--non-interactive --backend local-fast --language auto
|
||||
```
|
||||
|
||||
For **Groq · Cloud**, use `--backend groq --language en --groq-key-file /path/to/key`.
|
||||
The local flags are `local-fast` (**Local · Fast**) and `local-balanced`
|
||||
(**Local · Balanced**). Configure input permissions interactively before unattended
|
||||
setup. Noninteractive mode never opens administrator/key-selection dialogs.
|
||||
Models need their initial download; verified cached files are reused.
|
||||
|
||||
## Version and updates
|
||||
|
||||
```sh
|
||||
frame-voice --version
|
||||
frame-voice --check-updates --json
|
||||
~/.local/share/frame-voice/update.sh --tui
|
||||
```
|
||||
|
||||
Build info includes package version, source revision, dirty marker, and compiled
|
||||
capability. Installed release metadata is trusted only when its commit matches
|
||||
the binary. Unpackaged builds are displayed as development versions.
|
||||
|
||||
## Terminal rollback and removal
|
||||
|
||||
From a checkout or extracted release:
|
||||
|
||||
```sh
|
||||
./rollback.sh
|
||||
./uninstall.sh
|
||||
./uninstall.sh --remove-config --remove-models
|
||||
```
|
||||
|
||||
Removal keeps configuration/models by default; `--remove-config` and
|
||||
`--remove-models` control them separately. GUI removal is documented in
|
||||
[Uninstall](UNINSTALL.md). Rollback restores the last managed snapshot and service
|
||||
state, preserving files modified after installation.
|
||||
|
||||
## Build and architecture references
|
||||
|
||||
- [Installer internals and legacy migration](INSTALLER.md)
|
||||
- [Advanced configuration variables](CONFIGURATION.md)
|
||||
- [Capture, speech gating, prompts, and delivery](DESIGN.md)
|
||||
- [ARM64 builds and release channels](DISTRIBUTION.md)
|
||||
- [Canonical diagnostic commands](TROUBLESHOOTING.md#diagnostics)
|
||||
|
||||
Use current stable Rust and native ARM64 Linux with C/C++, CMake, pkg-config,
|
||||
libpulse headers, scdoc, and the pinned OpenVR headers. `./build-local.sh` builds
|
||||
the application/tray. `./tools/build-runtime.sh` builds bundled helpers from pinned
|
||||
sources under `.build/`. The distribution workflow creates a glibc bundle.
|
||||
+4
-123
@@ -1,124 +1,5 @@
|
||||
# Installation
|
||||
# Installation documentation
|
||||
|
||||
The release bundle includes Frame Voice, its tray and clipboard helper, ydotool/
|
||||
ydotoold, an audio-only FFmpeg build, the Whisper engine, and microphone setup.
|
||||
SteamOS supplies the SteamVR/PipeWire/ALSA runtime, Python, playback tools and
|
||||
Desktop dialogs. Users do not install compilers or fetch these helpers separately.
|
||||
|
||||
## First install
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/techieyann/frame-voice/main/get.sh | sh
|
||||
```
|
||||
|
||||
Setup offers [Groq — Cloud, Local — Fast or Local — Balanced](CONFIGURATION.md#backend).
|
||||
Groq requires a key from [Groq's console](https://console.groq.com/keys). Local
|
||||
choices download and verify their models automatically. Input-device permissions
|
||||
may require an administrator password once. Setup then starts dictation and the
|
||||
Desktop tray. Run the installer as your normal user, not with sudo.
|
||||
|
||||
### GUI, terminal, and automated setup
|
||||
|
||||
The installer selects the GUI when Desktop is available and a terminal menu
|
||||
otherwise. Explicit `--backend` flags keep the scripted setup path. For the new
|
||||
release, choose a frontend explicitly:
|
||||
|
||||
```sh
|
||||
./install-gui.sh
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --gui
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --tui
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray \
|
||||
--non-interactive --backend local-fast --language auto
|
||||
```
|
||||
|
||||
The GUI and TUI offer transcription, language, general settings, and controller
|
||||
mappings. For cloud automation, use `--backend groq --language en
|
||||
--groq-key-file /path/to/key`. Noninteractive setup never opens selection/key
|
||||
dialogs or administrator prompts; configure input permissions interactively first.
|
||||
Canceling interactive setup restores the prior installation and service state.
|
||||
Models downloaded before a failed/canceled setup may remain cached.
|
||||
|
||||
These frontend and language options are included in stable v0.1.0 and later.
|
||||
|
||||
Installation verifies archive and file checksums, channel and architecture before
|
||||
replacement. Helpers live under `~/.local/share/frame-voice/bin`; existing shared
|
||||
ydotool/Whisper installations and their services are untouched. Updates preserve
|
||||
configuration and models, snapshot all managed files, and restore service state.
|
||||
New snapshots never copy an existing config containing your API key.
|
||||
|
||||
When upgrading the old voice setup, add `--replace-legacy-helpers` to stop and
|
||||
disable `ydotoold.service` and `voice-mixer.service` in favor of the bundled
|
||||
helpers. Use this only if other applications no longer need those services.
|
||||
Their files remain, and rollback or uninstall restores their previous service
|
||||
state. For an extracted release:
|
||||
|
||||
```sh
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --setup --enable-tray --replace-legacy-helpers
|
||||
```
|
||||
|
||||
The keyboard-only input service clears `DISPLAY` because ydotoold's optional
|
||||
[X11 setup](https://github.com/ReimuNotMoe/ydotool/blob/v1.0.4/Daemon/ydotoold.c#L333-L349)
|
||||
only adjusts mouse acceleration. This avoids xinput/Xwayland warnings without
|
||||
changing keyboard injection.
|
||||
|
||||
## Channels and noninteractive setup
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/techieyann/frame-voice/main/get.sh | sh -s -- --channel experimental
|
||||
```
|
||||
|
||||
For unattended use, add `--backend local-fast`, `--backend local-balanced`, or
|
||||
`--backend groq --groq-key-file /path/to/key`. Models must download on the first
|
||||
local installation; cached verified models need no connection. A terminal or
|
||||
Desktop dialog is required if no backend/key is supplied.
|
||||
|
||||
## Tray
|
||||
|
||||
Open Desktop for status, Pause/Resume, Restart, configuration and logs. The tray
|
||||
runs on Plasma's private bus; service controls use the outer user bus. Hiding the
|
||||
tray leaves dictation running. Configuration changes restart dictation.
|
||||
|
||||
## Rollback and removal
|
||||
|
||||
From a source checkout or extracted release directory:
|
||||
|
||||
```sh
|
||||
./rollback.sh
|
||||
./uninstall.sh
|
||||
# To also remove Frame Voice settings and API keys:
|
||||
./uninstall.sh --remove-config
|
||||
# Also remove downloaded models (a full removal):
|
||||
./uninstall.sh --remove-config --remove-models
|
||||
```
|
||||
|
||||
Rollback restores the complete last snapshot and prior service state. Modified
|
||||
managed files are not overwritten. Uninstall removes application files, units,
|
||||
app data, and installation snapshots. Configuration/keys and model downloads are
|
||||
retained by default, controlled independently by `--remove-config` and
|
||||
`--remove-models`. Models downloaded by this tool are under
|
||||
`~/.local/share/frame-voice/models`; older shared Whisper models are not deleted.
|
||||
|
||||
The tray's **Configure… → General → Uninstall…** action provides confirmation and two retention
|
||||
checkboxes, both on by default. Unchecking both also removes
|
||||
`~/.config/frame-voice`, downloaded models, and this installer's input permission
|
||||
and module-loading rules if present. Removing administrator files requires
|
||||
administrator authentication; cancellation leaves the app installed. Modified
|
||||
administrator rules require manual removal. Older voice tools and their files
|
||||
remain untouched.
|
||||
|
||||
## Building
|
||||
|
||||
Use the native ARM64 [distribution workflow](DISTRIBUTION.md) for a complete
|
||||
bundle. Development builds need current stable Rust, C/C++, CMake, pkg-config,
|
||||
libpulse headers, scdoc and matching OpenVR headers. The workflow checks out
|
||||
pinned helper sources under `.build/`; run `./build-local.sh` and
|
||||
`./tools/build-runtime.sh`, then `./install.sh --setup`. Production builds use
|
||||
glibc. The installer can read built helpers from `.build/runtime/bin`.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
```sh
|
||||
~/.local/bin/frame-voice --check
|
||||
systemctl --user status frame-voice frame-voice-input frame-voice-mixer frame-voice-tray-session
|
||||
journalctl --user -u frame-voice -n 50 --no-pager
|
||||
```
|
||||
For user installation, see the [README](../README.md#install-on-your-frame).
|
||||
For removal, see [Uninstall Frame Voice](UNINSTALL.md).
|
||||
Developer details moved to [Installer internals](INSTALLER.md).
|
||||
@@ -0,0 +1,65 @@
|
||||
# Installer internals
|
||||
|
||||
The release bundle includes Frame Voice, its tray and clipboard helper, ydotool/
|
||||
ydotoold, an audio-only FFmpeg build, the Whisper engine, and microphone setup.
|
||||
SteamOS supplies the SteamVR/PipeWire/ALSA runtime, Python, playback tools and
|
||||
Desktop dialogs. Users do not install compilers or fetch these helpers separately.
|
||||
|
||||
## Entry points
|
||||
|
||||
User installation is documented in the [README](../README.md); GUI/terminal/agent
|
||||
entry points are in [Development](DEVELOPMENT.md). The default downloader opens
|
||||
the GUI when Desktop is available and the terminal menu otherwise. Explicit
|
||||
backend flags retain the scripted setup path.
|
||||
|
||||
Canceling interactive setup restores the previous installation/service state.
|
||||
Models downloaded before a failed/canceled setup may remain cached.
|
||||
|
||||
Installation verifies archive and file checksums, channel and architecture before
|
||||
replacement. Helpers live under `~/.local/share/frame-voice/bin`; existing shared
|
||||
ydotool/Whisper installations and their services are untouched. Updates preserve
|
||||
configuration and models, snapshot all managed files, and restore service state.
|
||||
New snapshots never copy an existing config containing your API key.
|
||||
|
||||
When upgrading the old voice setup, add `--replace-legacy-helpers` to stop and
|
||||
disable `ydotoold.service` and `voice-mixer.service` in favor of the bundled
|
||||
helpers. Use this only if other applications no longer need those services.
|
||||
Their files remain, and rollback or uninstall restores their previous service
|
||||
state. For an extracted release:
|
||||
|
||||
```sh
|
||||
./install.sh ./bin/frame-voice --tray-binary ./bin/frame-voice-tray --setup --enable-tray --replace-legacy-helpers
|
||||
```
|
||||
|
||||
The keyboard-only input service clears `DISPLAY` because ydotoold's optional
|
||||
[X11 setup](https://github.com/ReimuNotMoe/ydotool/blob/v1.0.4/Daemon/ydotoold.c#L333-L349)
|
||||
only adjusts mouse acceleration. This avoids xinput/Xwayland warnings without
|
||||
changing keyboard injection.
|
||||
|
||||
## Tray
|
||||
|
||||
Open Desktop for status, Pause/Resume, Restart, configuration and logs. The tray
|
||||
runs on Plasma's private bus; service controls use the outer user bus. Hiding the
|
||||
tray leaves dictation running. Configuration changes restart dictation.
|
||||
|
||||
## Rollback and removal
|
||||
|
||||
User-facing retention choices are in [Uninstall](UNINSTALL.md); terminal flags
|
||||
are in [Development](DEVELOPMENT.md#terminal-rollback-and-removal).
|
||||
Rollback restores the last snapshot and previous service state while preserving
|
||||
modified files. Removal deletes managed application data, units, and snapshots.
|
||||
Configuration and managed model downloads are independently retained by default.
|
||||
Older/shared tools and their model directories are not removed.
|
||||
|
||||
## Building
|
||||
|
||||
Use the native ARM64 [distribution workflow](DISTRIBUTION.md) for a complete
|
||||
bundle. Development builds need current stable Rust, C/C++, CMake, pkg-config,
|
||||
libpulse headers, scdoc and matching OpenVR headers. The workflow checks out
|
||||
pinned helper sources under `.build/`; run `./build-local.sh` and
|
||||
`./tools/build-runtime.sh`, then `./install.sh --setup`. Production builds use
|
||||
glibc. The installer can read built helpers from `.build/runtime/bin`.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Use the [canonical diagnostic commands](TROUBLESHOOTING.md#diagnostics).
|
||||
@@ -0,0 +1,11 @@
|
||||
# Release notes
|
||||
|
||||
Current defaults are **right X** for Clear and a **white tray microphone**
|
||||
(white crossed-out microphone when disabled). Blue/red headset feedback is
|
||||
separate from tray status.
|
||||
|
||||
- [v0.1.1: white tray icons and X Clear default](releases/v0.1.1.md)
|
||||
- [v0.1.0: initial stable release](releases/v0.1.0.md)
|
||||
|
||||
Installers and update checks select the latest stable release. Existing saved
|
||||
button choices are preserved; use Controllers to change an older B binding to X.
|
||||
+16
-13
@@ -16,7 +16,7 @@ settings and restarts dictation, so finish any recording first.
|
||||
| **Separator after dictation** | Space keeps consecutive dictations from running together. None adds no separator. |
|
||||
| **Maximum recording seconds** | Limits each recording; the default is 30 seconds. |
|
||||
|
||||
The tray shows a blue microphone while dictation runs and a red crossed-out
|
||||
The tray shows a white microphone while dictation runs and a white crossed-out
|
||||
microphone when paused. Use the tray's start/resume or pause options to control it.
|
||||
In the headset, the small microphone waits for audio startup, then grows toward
|
||||
the start tone. Wait for the tone before speaking. Release the joystick cap to
|
||||
@@ -53,11 +53,13 @@ installed voice tools and their models are left alone.
|
||||
|
||||
### Transcription path
|
||||
|
||||
| Choice | What you need | What to expect |
|
||||
| --- | --- | --- |
|
||||
| **Groq · Cloud** | Internet and a [Groq API key](https://console.groq.com/keys). | Speech is sent to Groq; no local model download is needed. |
|
||||
| **Local · Fast** | About 142 MiB for a model download. | Runs on your Frame and favors speed. |
|
||||
| **Local · Balanced** | About 466 MiB for a model download. | Runs on your Frame and favors accuracy over speed. |
|
||||
| Transcription option | Speed | Internet needed | Requirements |
|
||||
| --- | --- | --- | --- |
|
||||
| **Groq · Cloud** | Fastest | Every dictation | [API key](https://console.groq.com/keys) |
|
||||
| **Local · Fast** | Fast | Initial download only | ~142MiB |
|
||||
| **Local · Balanced** | Slow | Initial download only | ~466MiB |
|
||||
|
||||
The local options process speech on your Frame; the larger model favors accuracy.
|
||||
|
||||
Select a path, then **Save settings**. Local transcription works offline after
|
||||
its initial download. Switching to local retains your saved Groq API key so you
|
||||
@@ -74,7 +76,7 @@ other languages and automatic detection use a multilingual model. Changing this
|
||||
selection may require another download.
|
||||
|
||||
For accented characters and non-Latin scripts, use a clipboard-compatible
|
||||
standalone app such as Firefox. Nested Desktop typing currently supports ASCII.
|
||||
standalone app such as Firefox. Typing inside Desktop currently supports ASCII.
|
||||
Controller buttons work independently of the transcription language; spoken
|
||||
submit/clear command aliases remain English.
|
||||
|
||||
@@ -121,15 +123,16 @@ Choose **None** to disable a particular action. Save to apply new bindings.
|
||||
| **Either joystick cap** | Touch briefly, release, then touch and hold to record. |
|
||||
| **Joystick click during recording** | Cancel the recording. |
|
||||
| **Right A / left D-pad Right** | Submit after text appears. |
|
||||
| **Right B / left D-pad Left** | Clear after text appears, when the button is released. |
|
||||
| **Right X / left D-pad Left** | Clear after text appears, when the button is released. |
|
||||
|
||||
Submit and clear are available for ten seconds after successful dictation and
|
||||
stop when focus changes. A plain joystick hold does not start recording.
|
||||
|
||||
### B's Desktop space
|
||||
|
||||
In Steam's default Desktop layout, B also types a space. Leave **B also types a
|
||||
space in Desktop** enabled to include that extra character when clearing.
|
||||
The default Clear button is X, which does not type an extra character. If you
|
||||
choose B instead, Steam's default Desktop layout also types a space. Leave
|
||||
**B also types a space in Desktop** enabled to include that extra character when clearing.
|
||||
Disable it if your custom Steam B mapping does not type a space. This adjustment
|
||||
applies to right-hand B in Desktop; spoken Clear and other bindings keep their
|
||||
own behavior.
|
||||
@@ -141,6 +144,6 @@ editing the text yourself can also invalidate the tracked count.
|
||||
|
||||
## More detail
|
||||
|
||||
See [installation and removal](INSTALLATION.md) for installer and rollback
|
||||
instructions, or the [configuration reference](CONFIGURATION.md) for terminal
|
||||
commands, advanced settings, and troubleshooting.
|
||||
See [troubleshooting](TROUBLESHOOTING.md) if dictation is not working, or
|
||||
[uninstalling Frame Voice](UNINSTALL.md) for removal and retention choices.
|
||||
Advanced configuration belongs in the [developer guide](DEVELOPMENT.md).
|
||||
@@ -0,0 +1,78 @@
|
||||
# Troubleshooting
|
||||
|
||||
Start in Desktop and focus an app's text field. A new Firefox tab's address bar
|
||||
is a useful first test.
|
||||
|
||||
## No microphone badge or tone
|
||||
|
||||
1. Check the tray: a white microphone means running; a white crossed-out
|
||||
microphone means disabled. Choose **Start / resume dictation** if needed.
|
||||
2. Touch the joystick cap briefly, release, then touch it again and hold.
|
||||
A plain hold does not start recording.
|
||||
3. Wait for the growing **blue headset badge** and start tone before speaking.
|
||||
If tones are disabled in General, the badge still indicates readiness.
|
||||
4. Try **Restart dictation** in the tray, then repeat in a focused text field.
|
||||
|
||||
Frame Voice does not dictate into Steam menus or VR games.
|
||||
|
||||
## Groq produces no text
|
||||
|
||||
Check internet access and the key under Transcription → Groq. The
|
||||
[API-key page](https://console.groq.com/keys) lets you create a key. Check Groq's
|
||||
usage/limit notifications and **View recent logs** for failed requests.
|
||||
Quiet or uncertain recordings can cancel instead of inserting text. Try a clear
|
||||
sentence in a quieter room. Environmental sounds can still be misidentified.
|
||||
|
||||
## Local setup fails
|
||||
|
||||
Check free storage and the internet connection needed for the first download.
|
||||
Setup verifies downloads and retains the current transcription path if
|
||||
preparation fails. Reopen Configure and try saving again.
|
||||
Delete unused models in Transcription to recover storage; first switch and save
|
||||
another path to unlock deletion of an active model.
|
||||
|
||||
## Clear leaves text or removes the wrong text
|
||||
|
||||
Default Clear is **right X** or **left D-pad Left**, after text appears. Release
|
||||
the button to clear. Updates preserve existing button choices; use Controllers
|
||||
to switch an older B binding to X.
|
||||
|
||||
Start with an empty field and use a fresh dictation after an update, settings
|
||||
save, or service restart. Desktop tracks text inserted by the running process;
|
||||
restarting resets that history. Cursor movement and manual edits can invalidate
|
||||
that count. If using B, see [B's Desktop space](SETTINGS.md#bs-desktop-space).
|
||||
|
||||
## Accented or non-Latin text does not appear
|
||||
|
||||
Use a standalone app launched directly from Steam. Typing inside Desktop
|
||||
currently supports ASCII; supported standalone apps use clipboard paste for
|
||||
other scripts.
|
||||
|
||||
## Update check cannot find a release
|
||||
|
||||
Check internet access and try again. **Open releases** shows the release page.
|
||||
The automatic check reads public stable releases; a private repository or an
|
||||
unpublished release will not appear. Experimental versions are not selected.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
First use **View recent logs** in the tray. If you need to inspect services,
|
||||
open Konsole and run:
|
||||
|
||||
```sh
|
||||
~/.local/bin/frame-voice --check
|
||||
systemctl --user status frame-voice frame-voice-input frame-voice-mixer frame-voice-tray-session
|
||||
journalctl --user -u frame-voice -n 50 --no-pager
|
||||
```
|
||||
|
||||
The four services handle dictation, keyboard input, microphone setup, and the
|
||||
Desktop tray. `--check` validates settings and compiled support; it does not test
|
||||
your API key, internet connection, or headset health.
|
||||
|
||||
When reporting a problem, include the app/text field, transcription option,
|
||||
selected language, installed version, and relevant errors. Do not include API keys.
|
||||
|
||||
## Remove Frame Voice
|
||||
|
||||
See [uninstall instructions](UNINSTALL.md). You can retain settings and models
|
||||
independently, or remove both.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Uninstall Frame Voice
|
||||
|
||||
1. Open the tray icon and choose **Configure…**.
|
||||
2. Select **General** and click **Uninstall…** at the bottom.
|
||||
3. Choose what to retain in the confirmation, then confirm uninstall.
|
||||
|
||||
| Option | Keep checked to retain | Uncheck to remove |
|
||||
| --- | --- | --- |
|
||||
| **Keep current configuration** | Settings, saved API keys, and the managed custom prompt. | Those saved values and files. |
|
||||
| **Keep downloaded models** | Models downloaded by Frame Voice. | Those model downloads. |
|
||||
|
||||
Both options are checked initially. Uncheck both for a full removal of Frame
|
||||
Voice's settings, keys, models, app data, and installation backups.
|
||||
Separately installed voice tools and their models are not removed.
|
||||
Removing administrator-installed input rules can require your SteamOS password.
|
||||
Cancelling authentication leaves the app installed.
|
||||
|
||||
To recover model space while keeping the app, see
|
||||
[Downloaded models](SETTINGS.md#downloaded-models-and-storage).
|
||||
For terminal removal or rollback, use the [developer guide](DEVELOPMENT.md).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -1,5 +1,8 @@
|
||||
# Frame Voice v0.1.0
|
||||
|
||||
> These notes describe v0.1.0. Current versions default to X for Clear and white
|
||||
> tray icons; see [v0.1.1](v0.1.1.md). Existing saved bindings are preserved.
|
||||
|
||||
First stable release of controller-driven dictation for Steam Frame.
|
||||
|
||||
- Tap, release, then hold a joystick cap to dictate into Desktop or standalone apps. Click during recording to cancel; use A to submit and release B to clear.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Frame Voice v0.1.1
|
||||
|
||||
- The tray uses a white microphone with the Frame corner mark. Disabled dictation uses the same white icon with its existing cross. Headset recording/cancellation colours are unchanged.
|
||||
- New installations use right-controller **X** for Clear, matching left D-pad Left. This avoids B's native Desktop space. Existing configured button choices are retained; select X in Controllers to change them.
|
||||
- Default X clears exactly the tracked dictation and its separator, without an extra controller Backspace. Optional native-space handling applies only when B is explicitly selected.
|
||||
- User docs now separate settings, troubleshooting, removal, and developer references, with a configuration screenshot and a concise transcription comparison.
|
||||
|
||||
Updates preserve saved settings, API keys, and downloaded models. Open Configure → General → Check for updates.
|
||||
+14
-4
@@ -95,7 +95,7 @@ struct PendingClear {
|
||||
fn controller_clear_chars(c: &Config, hand: Option<usize>, target: &Snapshot) -> usize {
|
||||
usize::from(
|
||||
hand == Some(1)
|
||||
&& c.get("VRBTN_CLEAR_RIGHT", "b")
|
||||
&& c.get("VRBTN_CLEAR_RIGHT", "x")
|
||||
.trim()
|
||||
.eq_ignore_ascii_case("b")
|
||||
&& c.boolean("VRBTN_CLEAR_B_SPACE", true).unwrap_or(true)
|
||||
@@ -263,7 +263,7 @@ fn write_controller_binding(c: &Config, manifest: &str) -> Result<()> {
|
||||
if let Some(name) = pick("VRBTN_SUBMIT_RIGHT", "a", &right_buttons) {
|
||||
sources.push(button("right", &name, "/actions/voicedict/in/submit"));
|
||||
}
|
||||
if let Some(name) = pick("VRBTN_CLEAR_RIGHT", "b", &right_buttons) {
|
||||
if let Some(name) = pick("VRBTN_CLEAR_RIGHT", "x", &right_buttons) {
|
||||
sources.push(button("right", &name, "/actions/voicedict/in/clear"));
|
||||
}
|
||||
let doc = serde_json::json!({
|
||||
@@ -391,7 +391,7 @@ fn daemon(c: Config) -> Result<()> {
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
eprintln!("OpenVR controller bindings active");
|
||||
eprintln!("frame-voice ready: cap tap then hold; A submit; B clear");
|
||||
eprintln!("frame-voice ready: cap tap then hold; A submit; X clear");
|
||||
while !SHUTDOWN.load(Ordering::SeqCst) {
|
||||
retired.retain(|j| !j.worker.is_finished());
|
||||
// Deliver usage warnings through OpenVR so they appear in the headset /
|
||||
@@ -713,7 +713,15 @@ fn daemon(c: Config) -> Result<()> {
|
||||
// The same B press reaches the Desktop too. Inject
|
||||
// only after release so its first Backspace isn't
|
||||
// consumed by controller/keyboard focus switching.
|
||||
let hand = vr.clear_hand();
|
||||
let hand = if c
|
||||
.get("VRBTN_CLEAR_RIGHT", "x")
|
||||
.trim()
|
||||
.eq_ignore_ascii_case("b")
|
||||
{
|
||||
vr.clear_hand()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let controller_chars = controller_clear_chars(&c, hand, &now);
|
||||
if debug {
|
||||
eprintln!("controller clear prepared: hand={hand:?}; native_chars={controller_chars}");
|
||||
@@ -1065,6 +1073,8 @@ mod tests {
|
||||
class: String::new(),
|
||||
}),
|
||||
};
|
||||
assert_eq!(controller_clear_chars(&config, Some(1), &target), 0);
|
||||
config.values.insert("VRBTN_CLEAR_RIGHT".into(), "b".into());
|
||||
assert_eq!(controller_clear_chars(&config, Some(1), &target), 1);
|
||||
assert_eq!(controller_clear_chars(&config, Some(0), &target), 0);
|
||||
assert_eq!(controller_clear_chars(&config, None, &target), 0);
|
||||
|
||||
+9
-1
@@ -236,10 +236,18 @@ fn desktop_clear_counts_the_appended_separator() {
|
||||
assert!(fs::read_to_string(&arguments)
|
||||
.unwrap()
|
||||
.ends_with("hello \n"));
|
||||
inject::send(&c, &Output::Clear, Some(&focus)).unwrap();
|
||||
inject::send_controller_clear_guarded(&c, Some(&focus), 0, || true).unwrap();
|
||||
let keys = fs::read_to_string(&arguments).unwrap();
|
||||
assert_eq!(keys.lines().filter(|&line| line == "14:1").count(), 6);
|
||||
assert_eq!(keys.lines().filter(|&line| line == "14:0").count(), 6);
|
||||
// With no separator, default X must remove exactly the five typed letters.
|
||||
c.values.insert("VOICE_TRAILING".into(), "none".into());
|
||||
inject::send(&c, &Output::Text("hello".into()), Some(&focus)).unwrap();
|
||||
inject::send_controller_clear_guarded(&c, Some(&focus), 0, || true).unwrap();
|
||||
let keys = fs::read_to_string(&arguments).unwrap();
|
||||
assert_eq!(keys.lines().filter(|&line| line == "14:1").count(), 5);
|
||||
assert_eq!(keys.lines().filter(|&line| line == "14:0").count(), 5);
|
||||
c.values.remove("VOICE_TRAILING");
|
||||
// Default Desktop B inserts an additional space before triggering Clear.
|
||||
inject::send(&c, &Output::Text("hello".into()), Some(&focus)).unwrap();
|
||||
inject::send_controller_clear_guarded(&c, Some(&focus), 1, || true).unwrap();
|
||||
|
||||
@@ -147,6 +147,10 @@ class ConfigApp(Adw.Application):
|
||||
for widget in self.fields:
|
||||
signal = 'notify::active' if widget.kind == 'bool' else 'notify::selected' if widget.kind == 'enum' else 'notify::text'
|
||||
widget.connect(signal, self.update_dirty)
|
||||
controls = {widget.key: widget for widget in self.fields}
|
||||
if 'VRBTN_CLEAR_RIGHT' in controls:
|
||||
controls['VRBTN_CLEAR_RIGHT'].connect('notify::selected', self.update_controller_options)
|
||||
self.update_controller_options()
|
||||
for widget in (self.backend_choice, self.language_choice):
|
||||
widget.connect('notify::selected', self.update_dirty)
|
||||
self.update_dirty()
|
||||
@@ -177,6 +181,13 @@ class ConfigApp(Adw.Application):
|
||||
self.fields.append(widget)
|
||||
return widget
|
||||
|
||||
def update_controller_options(self, *_):
|
||||
controls = {widget.key: widget for widget in self.fields}
|
||||
choice = controls.get('VRBTN_CLEAR_RIGHT')
|
||||
row = controls.get('VRBTN_CLEAR_B_SPACE')
|
||||
if choice is not None and row is not None:
|
||||
row.set_visible(choice.options[choice.get_selected()] == 'b')
|
||||
|
||||
def transcription_page(self, page):
|
||||
choices = Adw.PreferencesGroup(title='Transcription', description='Choose where your speech is transcribed.')
|
||||
self.backend_modes = ['groq', 'local-fast', 'local-balanced']
|
||||
|
||||
@@ -143,8 +143,8 @@ def payload(project, binary, tray, include_tray, home):
|
||||
add(project / 'tools/config-gui.py', '.local/share/frame-voice/config-gui.py', 0o755)
|
||||
add(project / 'tools/config-gui-zenity.sh', '.local/share/frame-voice/config-gui-zenity.sh', 0o755)
|
||||
add(project / 'systemd/frame-voice-tray-session.service', '.config/systemd/user/frame-voice-tray-session.service')
|
||||
for name, state in [('microphone.svg', 'active'), ('cancelled-microphone.svg', 'stopped'),
|
||||
('gear.svg', 'processing'), ('cancelled-microphone.svg', 'failed')]:
|
||||
for name, state in [('tray-microphone.svg', 'active'), ('tray-muted-microphone.svg', 'stopped'),
|
||||
('tray-microphone.svg', 'processing'), ('tray-muted-microphone.svg', 'failed')]:
|
||||
add(project / 'assets/icons' / name, f'.local/share/frame-voice/tray-icons/frame-voice-{state}.svg')
|
||||
if not (home / CONFIG).exists():
|
||||
files[CONFIG] = (EXAMPLE, 0o600)
|
||||
|
||||
@@ -37,7 +37,7 @@ def files(project, binaries, tray, sdk_license, runtime=None):
|
||||
source['tools/' + name] = project / 'tools' / name
|
||||
for name in ('actions.json', 'frame_controller_binding.json', 'groq-prompt.txt'):
|
||||
source['assets/' + name] = project / 'assets' / name
|
||||
for name in ('microphone.svg', 'cancelled-microphone.svg', 'gear.svg'):
|
||||
for name in ('microphone.svg', 'cancelled-microphone.svg', 'gear.svg', 'tray-microphone.svg', 'tray-muted-microphone.svg'):
|
||||
source['assets/icons/' + name] = project / 'assets/icons' / name
|
||||
for name in ('frame-voice.service', 'frame-voice-tray-session.service', 'frame-voice-input.service', 'frame-voice-mixer.service'):
|
||||
source['systemd/' + name] = project / 'systemd' / name
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Developer helper: render existing tray vectors as embedded 64px ARGB pixmaps."""
|
||||
from pathlib import Path
|
||||
import gi
|
||||
|
||||
gi.require_version('GdkPixbuf', '2.0')
|
||||
from gi.repository import GdkPixbuf
|
||||
|
||||
root = Path(__file__).resolve().parent.parent/'assets/icons'
|
||||
for source, target in (('tray-microphone.svg', 'frame-voice-active.argb'),
|
||||
('tray-muted-microphone.svg', 'frame-voice-stopped.argb')):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(str(root/source), 64, 64)
|
||||
assert pixbuf.get_width() == pixbuf.get_height() == 64
|
||||
rgba = pixbuf.get_pixels()
|
||||
stride, channels = pixbuf.get_rowstride(), pixbuf.get_n_channels()
|
||||
pixels = bytearray()
|
||||
for y in range(64):
|
||||
for x in range(64):
|
||||
i = y*stride + x*channels
|
||||
r, g, b = rgba[i:i+3]
|
||||
a = rgba[i+3] if channels == 4 else 255
|
||||
pixels.extend((a, r, g, b))
|
||||
(root/target).write_bytes(pixels)
|
||||
@@ -134,7 +134,7 @@ SETTINGS = {
|
||||
'controllers': [
|
||||
('VRBTN_DICTATE_RIGHT', 'Right hand dictation', 'bool', None, True),
|
||||
('VRBTN_SUBMIT_RIGHT', 'Right submit button', 'enum', ['a', 'b', 'x', 'y', 'none'], 'a'),
|
||||
('VRBTN_CLEAR_RIGHT', 'Right clear button', 'enum', ['a', 'b', 'x', 'y', 'none'], 'b'),
|
||||
('VRBTN_CLEAR_RIGHT', 'Right clear button', 'enum', ['a', 'b', 'x', 'y', 'none'], 'x'),
|
||||
('VRBTN_CLEAR_B_SPACE', 'B also types a space in Desktop', 'bool', None, True),
|
||||
('VRBTN_DICTATE_LEFT', 'Left hand dictation', 'bool', None, True),
|
||||
('VRBTN_SUBMIT_LEFT', 'Left submit button', 'enum', ['dpad_up', 'dpad_down', 'dpad_left', 'dpad_right', 'none'], 'dpad_right'),
|
||||
|
||||
Generated
+1
-1
@@ -137,7 +137,7 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "frame-voice-tray"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"ksni",
|
||||
]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "frame-voice-tray"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
description = "Nested SteamOS Desktop status and controls for Frame Voice"
|
||||
|
||||
+2
-3
@@ -64,9 +64,8 @@ mod desktop {
|
||||
}
|
||||
fn icon_pixmap(&self) -> Vec<ksni::Icon> {
|
||||
let data: &[u8] = match self.state.active.as_str() {
|
||||
"active" => include_bytes!("../../assets/icons/frame-voice-active.argb"),
|
||||
"activating" | "reloading" => {
|
||||
include_bytes!("../../assets/icons/frame-voice-processing.argb")
|
||||
"active" | "activating" | "reloading" => {
|
||||
include_bytes!("../../assets/icons/frame-voice-active.argb")
|
||||
}
|
||||
_ => include_bytes!("../../assets/icons/frame-voice-stopped.argb"),
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user