Skip to content

feat: add models settings page with filtering and management#478

Merged
cjpais merged 26 commits intocjpais:mainfrom
VirenMohindra:vm/model-settings-page
Feb 8, 2026
Merged

feat: add models settings page with filtering and management#478
cjpais merged 26 commits intocjpais:mainfrom
VirenMohindra:vm/model-settings-page

Conversation

@VirenMohindra
Copy link
Contributor

@VirenMohindra VirenMohindra commented Dec 20, 2025

Before Submitting This PR

Please confirm you have done the following:

Description

adds a dedicated models settings page accessible from the sidebar, allowing users to view, download, switch, and delete transcription models without going through onboarding.

changes:

  • add models settings page in sidebar with filter buttons (all/multi-language/translation)
  • reuse ModelCard component from onboarding for consistent UI
  • add model deletion with native confirmation dialog using tauri-plugin-dialog
  • consolidate all model event listeners into useModels hook (removes duplicates from ModelSelector, LanguageSelector, TranslateToEnglish)
  • gate AccessibilityPermissions component to macOS only (was rendering on all platforms)
  • add is_recommended field to model registry for featured models
  • remove unused get_recommended_first_model rust command (dead code)
  • add translations for all 9 supported languages

Related Issues/Discussions

Testing

  • verified model download/switch/delete works from new settings page
  • verified filter buttons correctly filter models by capability
  • verified delete confirmation dialog appears (native macOS dialog)
  • verified no duplicate event listeners (checked via code review)
  • verified lint passes
  • verified all translations present in 9 languages

Screenshots/Videos (if applicable)

n/a - UI reuses existing ModelCard component

state demo
Model Section models-section
Model dropdown models-dropdown
Dropdown downloading models-dropdown-downloading
Model Section "Extracting..." model-section-extracting
Model auto switch after downloading model-auto-switch-after-downloading
Delete confirmation model-delete-confirm
whisper parakeet
parakeet whisper

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch 5 times, most recently from f42e1f9 to 4d0b790 Compare December 20, 2025 12:09
@cjpais
Copy link
Owner

cjpais commented Dec 20, 2025

From first glance I'm digging this, I'd like to review around how model specific settings potentially overlap with this as well

@dannysmith
Copy link
Collaborator

Love this at first glance.

(Observation on looking screenshots: It might look nicer if the download/delete buttons on the ModelCards were to the left of the accuracy/speed bars. The bars are always present so should be consistently positioned?)

@VirenMohindra
Copy link
Contributor Author

I'd like to review around how model specific settings potentially overlap with this as well

can you expand on that a bit? is there anything on the roadmap that could build on this? my goal was to put a solid foundation in place for future models -- things like tagging, filtering for now, and eventually search once the list grows

if there’s something that makes sense to support now while i’m already working in this area, happy to add it

It might look nicer if the download/delete buttons on the ModelCards were to the left of the accuracy/speed bars

yeah, i experimented with that briefly, and i think you’re pointing out that downloading a model causes the accuracy / speed bars to shift, which isn’t ideal

at the same time, i was trying to keep things consistent between the model dropdown and the model selection tab, and we generally place destructive actions on the far right

open to alternative layouts if you have something specific in mind

@cjpais
Copy link
Owner

cjpais commented Dec 22, 2025

@VirenMohindra regarding

can you expand on that a bit? is there anything on the roadmap that could build on this?

Yeah definitely. Right now there's a bit of awkwardness in that whisper supports translation built in as well as language selection. But parakeet the language is always "auto" and there's no translation built in. So it's just trying to disambiguate this in the UI since I think it could be confusing for some users. I think we just disable those settings for parakeet, which is okay but it's not super obvious why they are disabled

I was considering making them invisible to the UI for parakeet, but just curious about feedback or other potential UX ideas around this

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch 5 times, most recently from bd76eb5 to 41df068 Compare December 27, 2025 13:26
@VirenMohindra
Copy link
Contributor Author

VirenMohindra commented Dec 27, 2025

@cjpais that makes sense. current state: settings are disabled with explanatory text, but that can feel clunky

i went ahead and implemented a contextual approach in this PR — there's now a "model settings" card in general settings that adapts based on the current model:

  • whisper models show language selector + translation toggle (when supported)
  • parakeet models show "this model works automatically with no configuration needed"

this way users only see settings that apply to their model, no more confusing disabled / grayed out options. let me know if you'd prefer a different approach or want any adjustments

whisper parakeet
parakeet whisper

@cjpais
Copy link
Owner

cjpais commented Dec 29, 2025

Wow this is much nicer. Thank you @VirenMohindra

I don't think I'll be able to review this for a bit but I think we should try and have this be part of a v0.7.0 release

I don't know how reasonable it would be, but it would be very cool to have some filtering on language or something like that in the model page too. So you could pick your specific language and make sure the model you're using supports that language. Mainly I know some people have had problems in the past creating issues for example that Parakeet doesn't support their language well

@VirenMohindra
Copy link
Contributor Author

VirenMohindra commented Dec 29, 2025

Wow this is much nicer. Thank you @VirenMohindra

❤️❤️

I don't think I'll be able to review this for a bit but I think we should try and have this be part of a v0.7.0 release

no worries. def would love a couple more eyes on this since it's a thicc one

I don't know how reasonable it would be, but it would be very cool to have some filtering on language or something like that in the model page too. So you could pick your specific language and make sure the model you're using supports that language. Mainly I know some people have had problems in the past creating issues for example that Parakeet doesn't support their language well

Great idea -- I actually played around with this but didn't want to blow out scope since we're already crossed a thousand lines of code. happy to take a peek and add it back in, or have a quick follow up PR

what do you think?

@cjpais
Copy link
Owner

cjpais commented Dec 29, 2025

Since it's already large, I'm happy to just do a full review of the feature as a whole here I think. I pretty much know I'm going to have to sit down with it already so a couple hundred lines more of code will probably be best now rather than later. I'll probably have some more detailed feedback at some point as well

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch 2 times, most recently from 308f19f to ed6317c Compare January 1, 2026 17:21
@VirenMohindra
Copy link
Contributor Author

VirenMohindra commented Jan 1, 2026

done! added the ability to filter by language. opted to keep it on the frontend since we already had access to LANGUAGES. still relies on the BE via supports_language_selection flag

all languages simplified chinese filtered
Screenshot 2026-01-01 at 10 59 10 PM Screenshot 2026-01-01 at 10 59 13 PM

cc @cjpais for vis

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch 4 times, most recently from 879125d to 643b2f9 Compare January 6, 2026 18:30
@cjpais
Copy link
Owner

cjpais commented Jan 7, 2026

Thank you for the continued work on this. I'm quite excited to bring this in. I really need to play with it myself. It's been a long time and I don't want to let this get too stale. I'm really busy, but maybe within the next week or two I can make some more concrete decisions. It is quite a a big change, so it probably will take a bit longer for me to ensure this, but I'm liking generally where it's at and I can probably make some tweaks myself to clean anything else up.

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch from 15db8a4 to 57779e0 Compare January 9, 2026 11:56
@VirenMohindra
Copy link
Contributor Author

@cjpais thanks for the update! no rush at all - take the time you need to review thoroughly. the feature is working well and we've addressed the cancel functionality issues mentioned here. happy to make any adjustments based on your feedback when you get a chance to test it out

@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch 2 times, most recently from 0c14578 to 30fdbc9 Compare January 10, 2026 14:33
VirenMohindra and others added 12 commits February 7, 2026 19:51
- 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
- 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
…vanced

settings are now only in ModelSettingsCard, not duplicated in their old locations
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.
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).
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.
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.
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
add post-processing hotkey translations to all 15 locales and
backfill 29 missing keys for korean locale added in main.
@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch from 3a73103 to ef6757f Compare February 8, 2026 00:56
@VirenMohindra VirenMohindra force-pushed the vm/model-settings-page branch from 8aeafef to 90341ef Compare February 8, 2026 01:32
@cjpais
Copy link
Owner

cjpais commented Feb 8, 2026

I just want to say a huge shout out for all this work! Thank you for bearing with me and getting this merged, but I think it's good to go. Super excited to get this in. I think this improves a bunch of UI and leaves a lot more room for future improvements as well. Thank you!

@cjpais cjpais merged commit ef24cfe into cjpais:main Feb 8, 2026
4 checks passed
CJHwong added a commit to CJHwong/Handy that referenced this pull request Feb 8, 2026
Brings in PR cjpais#478 (models settings page), Breeze ASR model,
paste delay setting, download cancellation, and other changes
from main. Resolves conflicts keeping custom model discovery
functionality while adopting main's new model UI.
CJHwong added a commit to CJHwong/Handy that referenced this pull request Feb 8, 2026
…w 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 cjpais#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
cjpais added a commit that referenced this pull request Feb 9, 2026
* 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>
@VirenMohindra VirenMohindra deleted the vm/model-settings-page branch March 16, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants