Feature/custom dictionary - #768
Conversation
…ript correction
Add a custom dictionary that replaces commonly misheard phrases with the
intended term in the final transcript (e.g. 'super base' -> 'Supabase').
- New dictionary_corrector module: case-insensitive whole-word phrase
replacement, longest-phrase-first, regex metacharacters escaped
- New text_injection.custom_dictionary config key (list of
{spoken, replacement} pairs)
- Corrections applied in SpeechRecognitionManager._process_audio_buffer
after voice-command processing, so injected text and Test Dictation
both show corrected output; config re-read per segment so Settings
changes apply without a restart
- Settings dialog: 'Custom Dictionary' group on the dictation page with
add fields (Heard as / Replace with), a removal list, and empty state
- Tests for the corrector, config round-trip, recognition integration,
and the settings dialog UI
The dictation page is already wrapped in a vertical ScrolledWindow, so the dictionary group's inner scroller (min 48 / max 160 px, copied from the auto-pause editor) created a nested scroll area that hid entries behind its own scrollbar once more than ~2 corrections were added. Pack the Gtk.ListBox directly into the group and let the page scroller handle overflow, matching the existing no-inner-ScrolledWindow precedent elsewhere in the dialog.
✅ Deploy Preview for voca-linux canceled.
|
|
Thanks @abishekmuthian. A maintainer will review it. |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
| Filename | Overview |
|---|---|
| src/vocalinux/speech_recognition/dictionary_corrector.py | Adds disk-backed dictionary loading and regex-based phrase correction; the broad exception handler violates repository guidance. |
| src/vocalinux/speech_recognition/recognition_manager.py | Integrates corrections after command processing, allowing command-like misrecognitions to be consumed before correction. |
| src/vocalinux/ui/settings_dialog.py | Adds dictionary editing controls, but failed persistence is presented from in-memory state as successful and new callbacks lack required annotations. |
| src/vocalinux/ui/config_manager.py | Adds the empty custom_dictionary default under text_injection without changing existing configuration semantics. |
| tests/test_dictionary_corrector.py | Covers phrase matching, boundaries, malformed entries, and disk-loading behavior. |
| tests/test_speech_recognition.py | Covers correction integration with commands enabled and disabled, but not command-phrase collisions. |
| tests/test_settings_dialog.py | Covers dictionary UI structure and helper behavior, but not failed persistence. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Speech engine transcript] --> B{Voice commands enabled?}
B -- Yes --> C[CommandProcessor]
B -- No --> D[Trim transcript]
C --> E[Load custom dictionary]
D --> E
F[Settings dictionary editor] --> G[Save config.json]
G --> E
E --> H[Apply phrase corrections]
H --> I[Text callbacks]
C --> J[Action callbacks]
Reviews (1): Last reviewed commit: "docs(agents): document custom dictionary..." | Re-trigger Greptile
| dictionary_entries = load_custom_dictionary() | ||
| if dictionary_entries: | ||
| processed_text = apply_dictionary(processed_text, dictionary_entries) |
There was a problem hiding this comment.
Commands Run Before Corrections
When voice commands are enabled and a dictionary phrase overlaps a command such as delete that, period, or capitalize, CommandProcessor consumes or transforms the uncorrected phrase before apply_dictionary runs. The configured correction is therefore skipped, and action phrases can dispatch unintended operations such as deleting previously typed text.
| self.config_manager.set("text_injection", "custom_dictionary", entries) | ||
| self.config_manager.save_config() | ||
| self._refresh_custom_dictionary_list() |
There was a problem hiding this comment.
Failed Saves Appear Successful
When writing config.json fails, this code ignores save_config() returning False and refreshes the list from already-mutated in-memory state. The dialog shows and logs the dictionary edit as successful, but recognition reloads entries from disk, so it does not apply the change and the edit disappears after restart.
| except Exception as e: | ||
| logger.debug(f"Could not read {CONFIG_KEY} setting: {e}") | ||
| return [] |
There was a problem hiding this comment.
Dictionary Errors Are Overcaught
The new loader catches every Exception, so programming defects during path resolution or configuration traversal are silently treated as an unreadable dictionary. This also accompanies new add/remove callback signatures without the parameter and return annotations required by AGENTS.md; narrow the expected file/JSON exceptions and annotate those callbacks.
Context Used: AGENTS.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Description
When the model incorrectly transcripts a word, there's currently no mechanism to fix the word for the next use. This PR implements a simple dictionary where the incorrect words can be replaced during post processing. It also adds a dictionary section to the dictation tab of the GUI.
Related Issue
Partly fixes #408, #475
Type of Change
Checklist
Screenshots (if applicable)
Additional Notes
It just adds the dictionary to the
config.json, words can be added in the UI and the text is replaced during post-processing.Discussion : #483