Commit graph

50 commits

Author SHA1 Message Date
Ivan Zhuravlev
f8bbcd791c
Migrate to transcribe-rs-0.3.1 and add Canary support (#1023)
* refactor: migrate transcribe-rs from v0.2.8 to v0.3.0

Breaking API migration:
- engines::* → onnx::* module paths, whisper_cpp::* for Whisper
- TranscriptionEngine trait → SpeechModel trait
- Two-step new()+load_model() → one-step Model::load()
- transcribe_samples(Vec<f32>) → transcribe(&[f32])
- Explicit unload_model() → RAII drop
- Canary engine now from transcribe-rs instead of local crate

Removes canary-engine local crate dependency.
Uses path dependency to local transcribe-rs clone (temporary).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: upgrade transcribe-rs to v0.3.1, add Canary models

Update transcribe-rs dependency from v0.2.8 to v0.3.1 with
restructured features (whisper + onnx). Add Canary 180M Flash
(4 languages, 146MB) and Canary 1B v2 (25 EU languages, 692MB)
with translation support. Add i18n translations for all 17 locales.

Languages verified against HuggingFace model cards:
- Canary 180M Flash: en, de, es, fr
- Canary 1B v2: bg, hr, cs, da, nl, en, et, fi, fr, de, el, hu,
  it, lv, lt, mt, pl, pt, ro, sk, sl, es, sv, ru, uk

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* make sure when changing models the language changes with it

* format

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: CJ Pais <cj@cjpais.com>
2026-03-16 16:31:44 +08:00
Fero
a6e8fc8651
fix: keep Windows microphone guidance Windows-only (#1032)
* fix windows-only mic permission guidance

* don't hardcode error strings in rust

* format

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-03-15 22:44:48 +08:00
CJ Pais
30a940629a
be able to change models from the tray (#1002)
* be able to change models from the tray

* persist at the right times

* fixes

* fix tests
2026-03-14 12:19:06 +08:00
CJ Pais
82297fa146
Add model loading failure notifications with i18n support (#997)
* fix: show toast notification when model fails to load with ORT error

The model loading failure (e.g. ORT error) was only shown as a small
red dot with truncated text in the footer. Now it also triggers a
toast notification, matching how recording errors are already handled.

https://claude.ai/code/session_015VfQgoDkUDV6wk63RHrwEs

* fix: add missing i18n keys for model load error toast to all locales

https://claude.ai/code/session_015VfQgoDkUDV6wk63RHrwEs

* fix: simplify model load error toast and add proper translations

Remove the unnecessary modelLoadFailed passthrough key that just
forwarded a variable. Use the error string directly with a translated
fallback. Add proper translations for all 16 locales.

https://claude.ai/code/session_015VfQgoDkUDV6wk63RHrwEs

* fix: translate recordingFailed string in all locales

This was previously left untranslated (English) in all non-English
locale files.

https://claude.ai/code/session_015VfQgoDkUDV6wk63RHrwEs

* cleanup

* format

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-11 14:43:16 +08:00
Alexander Yastrebov
22d2e96942
Improve Russian translation (#996) 2026-03-11 09:11:59 +08:00
Fero
785c3317e4
Handle microphone init failure without aborting (#945)
* Handle microphone start failures without aborting

Return recorder init errors instead of panicking/aborting in the worker thread and reset UI state when recording start fails.

Refs #436

* prop errors to ui

* format

* Add missing recording error translation keys

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-03-10 13:07:21 +08:00
Giovanni Donisi
f8c74e9449
Fix Italian translation (#973) 2026-03-06 20:10:41 +08:00
albanobattistella
5ff3c896b2
Update translation.json (#961) 2026-03-05 09:49:21 +08:00
CJ Pais
51ef6f5755 Merge branch 'main' of github.com:cjpais/Handy 2026-03-01 20:58:27 +07:00
CJ Pais
b0aa2343d0 Update translation.json 2026-03-01 20:55:05 +07:00
pantafive
ff8612297b
feat: add GigaAM v3 for Russian speech recognition (#913)
* feat: add GigaAM v3 model for Russian speech recognition

Add GigaAM v3 e2e_ctc as a new transcription engine using
transcribe-rs 0.2.7 gigaam feature. Russian speech recognition
with punctuation, Latin characters and digit support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: cargo fmt formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Keep the file name of the model download the same as the file on the
blob website.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: CJ Pais <cj@cjpais.com>
2026-03-01 20:53:48 +07:00
fotiecodes
86263578dc
Translated section "keyboardImplementation" translations for the languages i know and could help with (FR, PT, ES, TR) (#910) 2026-02-28 08:02:00 +08:00
CJ Pais
e624a45264 toast if exists 2026-02-19 17:26:14 +08:00
CJ Pais
2cf5effef3 add translations + fix bindings 2026-02-19 17:09:22 +08:00
Pierre Carru
b90077b228
Add "external script" paste method (#638)
* feat(linux): add "external script" paste method

* feat(i18n): external script translation for fr, de, it
2026-02-19 17:07:16 +08:00
CJ Pais
83e6f5c492
support moonshine v2 (#837)
* support moonshine v2

* format

* add translations for models
2026-02-17 11:44:10 +08:00
Brandon Chen
cc477a310a
feat(i18n): add Traditional Chinese (zh-TW) locale (#796)
* feat(i18n): add Traditional Chinese (zh-TW) locale

* style(i18n): clarify zh as Simplified Chinese and format languages.ts

* tweak

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-12 18:19:28 +08:00
Phuoc Thinh Vu
b02873dab5
feat(linux): Add option to select typing tool (#760)
* feat(linux): Add option to select typing tool

 - Added a Linux-only typing tool setting shown for direct paste, with a new dropdown in advanced settings.
 - Wired new typing tool setting through settings store, bindings, and Tauri commands.
 - Added typing tool enum/defaults and selection handling in Linux clipboard direct typing.
 - Added translations for the new typing tool setting across locales.

* fix compilation on macos

* format

* only list available tools

* format

---------

Co-authored-by: Thinh Vu <phuocthinhvu@gmail.com>
Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-11 15:00:29 +08:00
sasha
bf2a59f5ef
feat: add configurable auto-submit after transcription paste (#765)
* feat: add configurable auto-submit after transcription paste

Add an Advanced output setting that can send Enter, Ctrl+Enter, or Cmd+Enter after text insertion so Handy works smoothly with different editor and agent submit shortcuts. This keeps the behavior opt-in, persists it in settings, and adds focused Rust tests for defaults and paste auto-submit decision logic.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: simplify auto submit configuration UX

Replace the auto-submit toggle and key dropdown with a single dropdown that includes an Off state, so output behavior is clearer and faster to configure. Clarify Meta-key behavior by showing Cmd+Enter on macOS and Super+Enter on Windows/Linux, with matching localized copy.

Co-authored-by: Cursor <cursoragent@cursor.com>

* use bindings generated on macos

* and translations.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-11 10:55:31 +08:00
Victor Navarro
f2c306eab6
Add show tray icon setting (#667)
* feat: add show tray icon setting

Allow hiding system tray icon via Settings > Advanced.
When hidden, closing window quits app instead of hiding.

* i8n

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-10 10:39:35 +08:00
Alex Pantechovskis
ea4b270f85
feat: add "Unload Model" in tray (#731)
* feat: add "Unload Model" in tray

* gray out "unload model" when model not loaded

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-10 09:55:46 +08:00
Anton Sotkov
82d5c759ad
Add “Processing…” overlay state when post-processing (#740)
* feat: add “Processing…” overlay state

* format

* missing translations

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-09 10:36:00 +08:00
Hoss
a4999164ae
feat(models): add opt-in custom Whisper model discovery (#622)
* feat(models): auto-discover custom Whisper models in models directory

Enable automatic discovery of custom GGML-format Whisper models (.bin files)
placed in the models directory, so users don't need to modify source code
to use their own fine-tuned models.

Backend changes:
- Add discover_custom_whisper_models() to scan for .bin files
- Generate display names from filenames (e.g., "my-model" → "My Model")
- Skip predefined model filenames to avoid duplicates
- Add 3 unit tests for discovery logic

Frontend changes:
- Split model dropdown into 3 sections: Custom, Downloaded, Downloadable
- Add collapsible section for downloadable models to reduce clutter
- Add max-height with scroll for long model lists
- Add "Custom" badge for user-provided models

* feat(models): make custom Whisper model discovery opt-in

[why] Address maintainer concern about support burden from community
models. Custom models should be a power-user feature, not enabled by
default.

[how] Add custom_models_enabled setting (default: false) in Debug
settings. Discovery only runs when enabled. Models show "Not officially
supported" messaging. Documentation updated with enable steps.

* feat(models): add is_custom field and integrate custom models with new UI

[why]
PR review requested an explicit is_custom field instead of inferring
custom status from url === null. Custom models also need proper
integration with the new models settings page from PR #478.

[how]
- Add is_custom: bool to ModelInfo struct, set true on discovered models
- Change discover_custom_whisper_models signature from &PathBuf to &Path
- Use 0.0 sentinel scores so UI hides score bars for custom models
- Add "Custom Models" section to ModelsSettings with 3-way model split
- Show "Custom" badge in ModelCard and ModelDropdown
- Hide language/translation tags when supported_languages is empty
- Remove custom models from available_models on delete instead of
  just marking as not downloaded (they have no re-download URL)
- Update tests with new fields and assertions

* chore(i18n): add custom model translation keys to all locales

[why]
Custom model feature introduces 5 new translation keys that need
to be present in all 15 non-English locales for CI to pass.

[how]
Add English placeholder values for: customModelDescription,
modelSelector.custom, settings.models.customModels,
settings.debug.customModels.label, settings.debug.customModels.description

* fix(models): keep language filter visible when no models match

[why]
The language filter was inside a conditionally rendered section
that disappeared when no downloaded models matched the selected
language, leaving the user stuck with no way to change the filter.

[how]
Always render the "Your Models" header row with the language filter,
only conditionally render the model cards below it.

* docs: fix custom models section reference in README

Model selector → Models settings page.

* fix(models): apply custom models toggle immediately without restart

[why]
Two bugs reported in PR review: (1) app breaks on restart when a
custom model was selected and the toggle is disabled — selected_model
still points to the missing model, causing "Model not found" error.
(2) Custom models remain visible in the UI after toggle-off because
the in-memory model list is never updated and no event is emitted.

[how]
- Add remove_custom_models() and add_custom_models() to ModelManager
  for runtime mutation of the available_models mutex
- On disable: reset selected_model to empty if it's a custom model,
  then remove custom models from the in-memory list
- On enable: run discover_custom_whisper_models against the mutex
- Emit model-state-changed event so the frontend refreshes immediately

* chore(i18n): remove "restart required" from custom model descriptions

Toggle now takes effect immediately, so the restart sentence
is inaccurate. Updated all 16 locales and README instructions.

* fix(models): clear stale model selection on startup

[why]
If a custom model file is deleted from disk while it's the selected
model, the app gets stuck on "Loading..." forever on next launch
because the model ID is not in available_models but
auto_select_model_if_needed only checked for empty string.

[how]
Validate that selected_model exists in available_models before
accepting it. If not found, clear the selection so auto-select
picks a valid downloaded model.

* remove toggle and clean up

* format

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-09 10:15:45 +08:00
Viren Mohindra
ef24cfefda
feat: add models settings page with filtering and management (#478)
* feat: add models settings page with filtering and management

- add dedicated models settings page in sidebar
- reuse ModelCard component from onboarding for consistent UI
- add filter buttons for all/multi-language/translation models
- add model deletion with native confirmation dialog (tauri-plugin-dialog)
- consolidate model event listeners into useModels hook (Zustand store)
- remove duplicate event listeners from ModelSelector, LanguageSelector, TranslateToEnglish
- gate AccessibilityPermissions to macOS only
- add is_recommended field to model registry for featured models
- remove unused get_recommended_first_model command
- add translations for all 9 supported languages

* feat: add language filter to models settings page

adds a searchable language dropdown filter to the models page that lets users filter models by language support. when a non-english language is selected, models that don't support multiple languages (like parakeet) are hidden.

- add searchable language dropdown (right-aligned in filter row)
- filter models using supports_language_selection capability
- add allLanguages translation key to all 10 locales

* feat: add translation consistency checker script

- add scripts/check-translations.cjs to validate all language files
- script dynamically discovers languages from directory structure
- checks that all languages have same keys as english reference
- detects missing and extra keys in each language
- add check:translations npm script
- integrate into github actions lint workflow
- validates translations on every pull request

* fix: update imports and add missing translations after rebase

- replace useModels hook with useModelStore in components
- add permission error keys to all languages
- add model settings keys to cs and tr (new languages from main)

* fix: translate english placeholders in cs and tr locale files

* refactor: simplify model dropdown and migrate store to immer

- model dropdown now only shows downloaded models (no download/delete)
- convert store to immer with record types for immutability
- remove unused translation keys (welcome, downloadPrompt, etc.)
- add missing moonshine-base model fields
- sync translations after rebase

* fix: add download cancellation support and ui improvements

- add full download cancellation with Arc<AtomicBool> flags in rust backend
- add progress event throttling (100ms) to prevent ui freeze
- add cancel button to model card in settings page
- add model-deleted event listener to refresh dropdown after deletion
- remove pink background from recommended models in settings (keep badge only)
- add cancel/cancelDownload translation keys to all 14 languages

* fix: remove duplicate language/translate settings from general and advanced

settings are now only in ModelSettingsCard, not duplicated in their old locations

* fix: prevent model dropdown from being clipped by window edge

* add languages explicitly, clean up some ui

* fix: clear bottom progress bar when download is cancelled

The ModelSelector component maintains its own local state for download
progress. When a download was cancelled, the Rust backend would update
its state but never emitted an event to notify the frontend. This caused
the bottom progress bar to remain stuck showing "Downloading X%".

Added model-download-cancelled event emission in Rust and corresponding
listener in ModelSelector to clear progress state on cancellation.

* fix: align model card content to top to prevent floating elements

Changed ModelCard flex alignment from items-center to items-start so
the accuracy/speed bars stay at the top when the card expands (e.g.,
during download with progress bar visible).

* fix: prevent model deletion from interrupting active extractions

Added extracting_models HashSet to track models currently being
extracted. The update_download_status() function now skips cleanup
of .extracting directories for models that are actively extracting,
preventing a race condition where deleting one model would interrupt
another model's extraction process.

* refactor: migrate ModelCard buttons to Button component

Added two new Button variants for common patterns:
- primary-soft: soft/tinted primary buttons (used for download)
- danger-ghost: subtle destructive actions (used for delete/cancel)

Migrated all hardcoded buttons in ModelCard to use the shared Button
component for consistency and maintainability.

* feat: separate downloaded and available models into sections

Split the models list into "Your Models" and "Available to Download"
sections for clearer visual distinction between downloaded and
downloadable models.

Also adds missing translation keys to all locales:
- modelSelector.capabilities.singleLanguage
- modelSelector.capabilities.languageOnly
- settings.models.yourModels
- settings.models.availableModels

* fix: add missing translations after rebase onto main

add post-processing hotkey translations to all 15 locales and
backfill 29 missing keys for korean locale added in main.

* fix: add label to model delete button for clearer destructive state

* check translations as typescript

* format

* better text for dropdown

* wip ui tweaks

* rounded + ui tweaks

* fix download not 0% immediately, ui tweaks

* tweak name

* block for model downloading in onboarding

* small fixes

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-08 12:18:22 +08:00
CJ Pais
db854363b4 default for post-process and revert ui changes 2026-02-06 16:46:17 +08:00
Sam
462b03b024
feat: add optional hotkey for post-processing request (#355)
* feat: add post-processing hotkey

* rewrite

* bring back toggle

* Make sure the toggle on and off propagates for the key binding.

* rename for clarity

* cleanup

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-06 16:28:14 +08:00
ryanlee-ecosy
81b90aa675
feat(i18n): Add Korean translation (#721) 2026-02-06 10:34:34 +08:00
NourEldin Osama
804c1263d5
feat(i18n): Enhance RTL support and update language direction handling (#698)
* feat(i18n): Enhance RTL support and update language direction handling

* format

* minor tweaks

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-04 17:43:16 +08:00
CJ Pais
e9a6108559
Add a paste delay setting (#694)
* Add a paste delay setting.

* format
2026-02-01 20:58:02 +08:00
NourEldin Osama
90bfa73377
feat(i18n): Add Arabic localization support (#693) 2026-02-01 20:28:52 +08:00
CJ Pais
b733ccc458
init attempt at new kb (#580)
* init attempt at new kb

* 0.1.1 handy-keys

* format

* cleanup

* support for capslock/shiftlock?

* move kb to experimental

* use hook

* fix macos bug

* attempt mouse buttons as well
2026-01-20 08:23:35 +08:00
Gabe Duarte
246fb4e7da
Fix audio playback in History tab on Linux (#617)
* Add Portuguese translations for permission error messages

Add error message translations for the permission check flow in the Portuguese locale, covering both check failures and request failures.

* Fix history audio playback on Linux

WebKitGTK cannot play audio files via the asset:// protocol (or at least
not reliably), returning MEDIA_ERR_SRC_NOT_SUPPORTED. Additionally,
convertFileSrc was double- encoding the path (/ became %2F).

Changed to read audio files directly using the fs plugin and create
blob URLs instead. Also added APPDATA to fs:scope permissions to allow
reading recordings from the app data directory.

* Fix audio playback on macOS by using asset protocol on non-Linux

The blob URL approach for audio playback works on Linux but breaks
macOS.
This reverts the blob change to use convertFileSrc with the asset
protocol on macOS/Windows while keeping the blob approach for Linux
where it's needed. Also adds proper cleanup of blob URLs to prevent
memory leaks when history entries are unmounted.
2026-01-19 12:44:50 +08:00
CJ Pais
28d1d814b7
add experimental features to ui + reorg everything (#620) 2026-01-19 10:33:04 +08:00
ja
6522944886
feat(tray): add copy last transcript action (#598) 2026-01-18 10:33:50 +08:00
Enes
031fe4f52e
feat(i18n): add Turkish language support. (#582) 2026-01-15 09:58:30 +08:00
Andre Popovitch
e1c6007f71
Add permission step to onboarding (#545)
* Add permission step to onboarding

* translations

* minor ui

* Update AccessibilityOnboarding.tsx

* claude suggestions

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-01-14 09:53:49 +08:00
Michal Zemek
dfb72993b1
feat: add Czech translation (#568) 2026-01-12 12:46:57 +08:00
Vlad Gerasimov
1b580d54e8
feat: add Moonshine Base speech recognition model (#556)
* feat: add Moonshine Base speech recognition model

Add support for the Moonshine Base ASR model, which offers:
- 5x faster transcription than Whisper
- Better accent recognition
- ~240MB model size (encoder + decoder + tokenizer)

Changes:
- Update transcribe-rs to v0.2 with moonshine feature
- Add EngineType::Moonshine variant
- Add Moonshine Base model definition (400MB, 80% accuracy, 90% speed)
- Add model loading and transcription logic
- Add i18n translation for Moonshine Base

Note: Model files must be hosted at blob.handy.computer/moonshine-base.tar.gz
Expected structure: encoder_model.onnx, decoder_model_merged.onnx, tokenizer.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update moonshine parameters.

* add translations

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: CJ Pais <cj@cjpais.com>
2026-01-10 11:22:49 +08:00
David Vital
e199ca6bfb
feat(i18n): add Portuguese language support and translations (#540) 2026-01-06 22:49:48 +08:00
Ivan Tur
c8aabdb913
feat(i18n): add Ukrainian language support and translations (#536)
Co-authored-by: Ivan Tur <49621041+buiiz@users.noreply.github.com>
2026-01-06 20:25:18 +08:00
Viren Mohindra
d3a0281062
fix: prevent crash on macos 26.x beta during startup (#473)
defer apple intelligence availability check from app initialization
to when the user actually tries to use the feature. accessing
SystemLanguageModel.default during early app startup causes SIGABRT
on macOS 26.x (tahoe) beta.

- remove availability check from default_post_process_providers()
- always include apple intelligence provider on macos arm64
- add checkAppleIntelligenceAvailable command for lazy checking
- show error message if apple intelligence unavailable when selected
- clear error on any dropdown selection for better UX
2026-01-04 07:52:06 +08:00
Скляров Артем
b55c3fddde
Add Russian language (#474)
* Add Russian language

* Add Russian language

* Clean up hidden Unicode characters in Russian translation

* add languages.ts

* add some missing translations

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2025-12-27 10:11:24 +07:00
Viren Mohindra
bfca46fcd6
feat: add tray menu localization using system locale (#446) 2025-12-18 04:14:32 -08:00
CJ Pais
7bd4a59107
Fix 'history limit' not saving to settings (#463)
* fix history limit not saving

* update the translations as well
2025-12-16 16:50:53 +07:00
CJ Pais
ffd38f4d89
stored settings for language, and also overlay is now transcribed (#465) 2025-12-16 11:01:23 +07:00
CJ Pais
57629f1374
suggestions from sem (#464) 2025-12-16 10:33:25 +07:00
giuliofoletto
f962054800
Add Italian translation (#459) 2025-12-16 10:29:33 +07:00
Rayearth
5b777dd572
Add Polish translation (#453)
* Polish language added to language list

* Polish translation added

* Corrected language code for Polish
2025-12-15 10:59:07 +07:00
Viren Mohindra
5f7ffe162b
feat: add german, japanese, and chinese translations (#444)
* feat: add german, japanese, and chinese translations

adds complete translations for:
- german (de)
- japanese (ja)
- chinese simplified (zh)

builds on the internationalization foundation added in #437.
updates CONTRIBUTING_TRANSLATIONS.md to reflect supported languages.

* fix: escape Chinese quotation marks in zh translation

* cleanup

* remove extra keys for now

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2025-12-12 21:54:23 +07:00
CJ Pais
f87051f464
Add Internationalization Support (#437)
* basic i18n

* tweak

* translate app

* add linting to make sure we have translations

* run linter on pr

* format
2025-12-12 11:16:54 +07:00