diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2c55c88..fca0d20 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" @@ -823,9 +823,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "clipboard-win" @@ -892,9 +892,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" @@ -1777,8 +1777,8 @@ dependencies = [ "clap", "ferrous-opencc-compiler", "fst", - "phf 0.13.1", - "phf_codegen 0.13.1", + "phf 0.11.3", + "phf_codegen 0.11.3", "serde", "serde_json", "tempfile", @@ -4246,17 +4246,6 @@ dependencies = [ "phf_shared 0.11.3", ] -[[package]] -name = "phf" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" -dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", - "serde", -] - [[package]] name = "phf_codegen" version = "0.8.0" @@ -4277,16 +4266,6 @@ dependencies = [ "phf_shared 0.11.3", ] -[[package]] -name = "phf_codegen" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" -dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - [[package]] name = "phf_generator" version = "0.8.0" @@ -4317,16 +4296,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "phf_generator" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" -dependencies = [ - "fastrand", - "phf_shared 0.13.1", -] - [[package]] name = "phf_macros" version = "0.10.0" @@ -4354,19 +4323,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "phf_macros" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" -dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "phf_shared" version = "0.8.0" @@ -4394,15 +4350,6 @@ dependencies = [ "siphasher 1.0.2", ] -[[package]] -name = "phf_shared" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" -dependencies = [ - "siphasher 1.0.2", -] - [[package]] name = "pin-project-lite" version = "0.2.16" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 34878cd..2e98450 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -87,6 +87,7 @@ tauri-plugin-single-instance = "2.3.2" tauri-plugin-updater = "2.10.0" [target.'cfg(windows)'.dependencies] +transcribe-rs = { version = "0.3.1", features = ["ort-directml"] } windows = { version = "0.61.3", features = [ "Win32_Media_Audio_Endpoints", "Win32_System_Com_StructuredStorage", diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 92ba93f..d02df67 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -156,6 +156,9 @@ fn initialize_core_logic(app_handle: &AppHandle) { let history_manager = Arc::new(HistoryManager::new(app_handle).expect("Failed to initialize history manager")); + // Apply accelerator preferences before any model loads + managers::transcription::apply_accelerator_settings(app_handle); + // Add managers to Tauri's managed state app_handle.manage(recording_manager.clone()); app_handle.manage(model_manager.clone()); @@ -360,6 +363,9 @@ pub fn run(cli_args: CliArgs) { shortcut::change_keyboard_implementation_setting, shortcut::get_keyboard_implementation, shortcut::change_show_tray_icon_setting, + shortcut::change_whisper_accelerator_setting, + shortcut::change_ort_accelerator_setting, + shortcut::get_available_accelerators, shortcut::handy_keys::start_handy_keys_recording, shortcut::handy_keys::stop_handy_keys_recording, trigger_update_check, diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index 90010de..7f6e7ac 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -1,9 +1,12 @@ use crate::audio_toolkit::{apply_custom_words, filter_transcription_output}; use crate::managers::model::{EngineType, ModelManager}; -use crate::settings::{get_settings, ModelUnloadTimeout}; +use crate::settings::{ + get_settings, ModelUnloadTimeout, OrtAcceleratorSetting, WhisperAcceleratorSetting, +}; use anyhow::Result; use log::{debug, error, info, warn}; use serde::Serialize; +use specta::Type; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Condvar, Mutex, MutexGuard}; @@ -717,6 +720,55 @@ impl TranscriptionManager { } } +/// Apply the user's accelerator preferences to the transcribe-rs global atomics. +/// Called on startup and whenever the user changes the setting. +pub fn apply_accelerator_settings(app: &tauri::AppHandle) { + use transcribe_rs::accel; + + let settings = get_settings(app); + + let whisper_pref = match settings.whisper_accelerator { + WhisperAcceleratorSetting::Auto => accel::WhisperAccelerator::Auto, + WhisperAcceleratorSetting::Cpu => accel::WhisperAccelerator::CpuOnly, + WhisperAcceleratorSetting::Gpu => accel::WhisperAccelerator::Gpu, + }; + accel::set_whisper_accelerator(whisper_pref); + info!("Whisper accelerator set to: {}", whisper_pref); + + let ort_pref = match settings.ort_accelerator { + OrtAcceleratorSetting::Auto => accel::OrtAccelerator::Auto, + OrtAcceleratorSetting::Cpu => accel::OrtAccelerator::CpuOnly, + OrtAcceleratorSetting::Cuda => accel::OrtAccelerator::Cuda, + OrtAcceleratorSetting::DirectMl => accel::OrtAccelerator::DirectMl, + OrtAcceleratorSetting::Rocm => accel::OrtAccelerator::Rocm, + }; + accel::set_ort_accelerator(ort_pref); + info!("ORT accelerator set to: {}", ort_pref); +} + +#[derive(Serialize, Clone, Debug, Type)] +pub struct AvailableAccelerators { + pub whisper: Vec, + pub ort: Vec, +} + +/// Return which accelerators are compiled into this build. +pub fn get_available_accelerators() -> AvailableAccelerators { + use transcribe_rs::accel::OrtAccelerator; + + let ort_options: Vec = OrtAccelerator::available() + .into_iter() + .map(|a| a.to_string()) + .collect(); + + let whisper_options = vec!["auto".to_string(), "cpu".to_string(), "gpu".to_string()]; + + AvailableAccelerators { + whisper: whisper_options, + ort: ort_options, + } +} + impl Drop for TranscriptionManager { fn drop(&mut self) { debug!("Shutting down TranscriptionManager"); diff --git a/src-tauri/src/managers/transcription_mock.rs b/src-tauri/src/managers/transcription_mock.rs index 4976105..7dcdf2a 100644 --- a/src-tauri/src/managers/transcription_mock.rs +++ b/src-tauri/src/managers/transcription_mock.rs @@ -5,6 +5,7 @@ use crate::managers::model::ModelManager; use anyhow::Result; use serde::Serialize; +use specta::Type; use std::sync::Arc; use tauri::AppHandle; @@ -60,3 +61,20 @@ impl TranscriptionManager { Ok(String::new()) } } + +/// No-op in CI mock. +pub fn apply_accelerator_settings(_app: &tauri::AppHandle) {} + +#[derive(Serialize, Clone, Debug, Type)] +pub struct AvailableAccelerators { + pub whisper: Vec, + pub ort: Vec, +} + +/// Returns empty lists in CI mock. +pub fn get_available_accelerators() -> AvailableAccelerators { + AvailableAccelerators { + whisper: vec![], + ort: vec![], + } +} diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 7e7403f..9532168 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -273,6 +273,37 @@ impl Default for TypingTool { } } +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Type)] +#[serde(rename_all = "snake_case")] +pub enum WhisperAcceleratorSetting { + Auto, + Cpu, + Gpu, +} + +impl Default for WhisperAcceleratorSetting { + fn default() -> Self { + WhisperAcceleratorSetting::Auto + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Type)] +#[serde(rename_all = "snake_case")] +pub enum OrtAcceleratorSetting { + Auto, + Cpu, + Cuda, + #[serde(rename = "directml")] + DirectMl, + Rocm, +} + +impl Default for OrtAcceleratorSetting { + fn default() -> Self { + OrtAcceleratorSetting::Auto + } +} + /* still handy for composing the initial JSON in the store ------------- */ #[derive(Serialize, Deserialize, Debug, Clone, Type)] pub struct AppSettings { @@ -360,6 +391,10 @@ pub struct AppSettings { pub external_script_path: Option, #[serde(default)] pub custom_filler_words: Option>, + #[serde(default)] + pub whisper_accelerator: WhisperAcceleratorSetting, + #[serde(default)] + pub ort_accelerator: OrtAcceleratorSetting, } fn default_model() -> String { @@ -725,6 +760,8 @@ pub fn get_default_settings() -> AppSettings { typing_tool: default_typing_tool(), external_script_path: None, custom_filler_words: None, + whisper_accelerator: WhisperAcceleratorSetting::default(), + ort_accelerator: OrtAcceleratorSetting::default(), } } diff --git a/src-tauri/src/shortcut/mod.rs b/src-tauri/src/shortcut/mod.rs index 5d1315a..5e95d46 100644 --- a/src-tauri/src/shortcut/mod.rs +++ b/src-tauri/src/shortcut/mod.rs @@ -1067,3 +1067,48 @@ pub fn change_show_tray_icon_setting(app: AppHandle, enabled: bool) -> Result<() Ok(()) } + +/// Save accelerator settings, re-apply globals, and unload the model so it +/// reloads with the new backend on next transcription. +fn apply_and_reload_accelerator(app: &AppHandle, s: settings::AppSettings) { + settings::write_settings(app, s); + crate::managers::transcription::apply_accelerator_settings(app); + + let tm = app.state::>(); + if tm.is_model_loaded() { + if let Err(e) = tm.unload_model() { + log::warn!("Failed to unload model after accelerator change: {e}"); + } + } +} + +#[tauri::command] +#[specta::specta] +pub fn change_whisper_accelerator_setting( + app: AppHandle, + accelerator: settings::WhisperAcceleratorSetting, +) -> Result<(), String> { + let mut s = settings::get_settings(&app); + s.whisper_accelerator = accelerator; + apply_and_reload_accelerator(&app, s); + Ok(()) +} + +#[tauri::command] +#[specta::specta] +pub fn change_ort_accelerator_setting( + app: AppHandle, + accelerator: settings::OrtAcceleratorSetting, +) -> Result<(), String> { + let mut s = settings::get_settings(&app); + s.ort_accelerator = accelerator; + apply_and_reload_accelerator(&app, s); + Ok(()) +} + +/// Return which ORT accelerators are compiled into this build. +#[tauri::command] +#[specta::specta] +pub fn get_available_accelerators() -> crate::managers::transcription::AvailableAccelerators { + crate::managers::transcription::get_available_accelerators() +} diff --git a/src/bindings.ts b/src/bindings.ts index 1f89f3e..35abc27 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -339,6 +339,28 @@ async changeShowTrayIconSetting(enabled: boolean) : Promise else return { status: "error", error: e as any }; } }, +async changeWhisperAcceleratorSetting(accelerator: WhisperAcceleratorSetting) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("change_whisper_accelerator_setting", { accelerator }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async changeOrtAcceleratorSetting(accelerator: OrtAcceleratorSetting) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("change_ort_accelerator_setting", { accelerator }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +/** + * Return which ORT accelerators are compiled into this build. + */ +async getAvailableAccelerators() : Promise { + return await TAURI_INVOKE("get_available_accelerators"); +}, /** * Start key recording mode */ @@ -757,9 +779,10 @@ async isLaptop() : Promise> { /** user-defined types **/ -export type AppSettings = { bindings: Partial<{ [key in string]: ShortcutBinding }>; push_to_talk: boolean; audio_feedback: boolean; audio_feedback_volume?: number; sound_theme?: SoundTheme; start_hidden?: boolean; autostart_enabled?: boolean; update_checks_enabled?: boolean; selected_model?: string; always_on_microphone?: boolean; selected_microphone?: string | null; clamshell_microphone?: string | null; selected_output_device?: string | null; translate_to_english?: boolean; selected_language?: string; overlay_position?: OverlayPosition; debug_mode?: boolean; log_level?: LogLevel; custom_words?: string[]; model_unload_timeout?: ModelUnloadTimeout; word_correction_threshold?: number; history_limit?: number; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; auto_submit?: boolean; auto_submit_key?: AutoSubmitKey; post_process_enabled?: boolean; post_process_provider_id?: string; post_process_providers?: PostProcessProvider[]; post_process_api_keys?: Partial<{ [key in string]: string }>; post_process_models?: Partial<{ [key in string]: string }>; post_process_prompts?: LLMPrompt[]; post_process_selected_prompt_id?: string | null; mute_while_recording?: boolean; append_trailing_space?: boolean; app_language?: string; experimental_enabled?: boolean; keyboard_implementation?: KeyboardImplementation; show_tray_icon?: boolean; paste_delay_ms?: number; typing_tool?: TypingTool; external_script_path: string | null; custom_filler_words?: string[] | null } +export type AppSettings = { bindings: Partial<{ [key in string]: ShortcutBinding }>; push_to_talk: boolean; audio_feedback: boolean; audio_feedback_volume?: number; sound_theme?: SoundTheme; start_hidden?: boolean; autostart_enabled?: boolean; update_checks_enabled?: boolean; selected_model?: string; always_on_microphone?: boolean; selected_microphone?: string | null; clamshell_microphone?: string | null; selected_output_device?: string | null; translate_to_english?: boolean; selected_language?: string; overlay_position?: OverlayPosition; debug_mode?: boolean; log_level?: LogLevel; custom_words?: string[]; model_unload_timeout?: ModelUnloadTimeout; word_correction_threshold?: number; history_limit?: number; recording_retention_period?: RecordingRetentionPeriod; paste_method?: PasteMethod; clipboard_handling?: ClipboardHandling; auto_submit?: boolean; auto_submit_key?: AutoSubmitKey; post_process_enabled?: boolean; post_process_provider_id?: string; post_process_providers?: PostProcessProvider[]; post_process_api_keys?: Partial<{ [key in string]: string }>; post_process_models?: Partial<{ [key in string]: string }>; post_process_prompts?: LLMPrompt[]; post_process_selected_prompt_id?: string | null; mute_while_recording?: boolean; append_trailing_space?: boolean; app_language?: string; experimental_enabled?: boolean; keyboard_implementation?: KeyboardImplementation; show_tray_icon?: boolean; paste_delay_ms?: number; typing_tool?: TypingTool; external_script_path: string | null; custom_filler_words?: string[] | null; whisper_accelerator?: WhisperAcceleratorSetting; ort_accelerator?: OrtAcceleratorSetting } export type AudioDevice = { index: string; name: string; is_default: boolean } export type AutoSubmitKey = "enter" | "ctrl_enter" | "cmd_enter" +export type AvailableAccelerators = { whisper: string[]; ort: string[] } export type BindingResponse = { success: boolean; binding: ShortcutBinding | null; error: string | null } export type ClipboardHandling = "dont_modify" | "copy_to_clipboard" export type CustomSounds = { start: boolean; stop: boolean } @@ -779,6 +802,7 @@ export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" export type ModelInfo = { id: string; name: string; description: string; filename: string; url: string | null; size_mb: number; is_downloaded: boolean; is_downloading: boolean; partial_size: number; is_directory: boolean; engine_type: EngineType; accuracy_score: number; speed_score: number; supports_translation: boolean; is_recommended: boolean; supported_languages: string[]; supports_language_selection: boolean; is_custom: boolean } export type ModelLoadStatus = { is_loaded: boolean; current_model: string | null } export type ModelUnloadTimeout = "never" | "immediately" | "min_2" | "min_5" | "min_10" | "min_15" | "hour_1" | "sec_5" +export type OrtAcceleratorSetting = "auto" | "cpu" | "cuda" | "directml" | "rocm" export type OverlayPosition = "none" | "top" | "bottom" export type PasteMethod = "ctrl_v" | "direct" | "none" | "shift_insert" | "ctrl_shift_v" | "external_script" export type PermissionAccess = "allowed" | "denied" | "unknown" @@ -787,6 +811,7 @@ export type RecordingRetentionPeriod = "never" | "preserve_limit" | "days_3" | " export type ShortcutBinding = { id: string; name: string; description: string; default_binding: string; current_binding: string } export type SoundTheme = "marimba" | "pop" | "custom" export type TypingTool = "auto" | "wtype" | "kwtype" | "dotool" | "ydotool" | "xdotool" +export type WhisperAcceleratorSetting = "auto" | "cpu" | "gpu" export type WindowsMicrophonePermissionStatus = { supported: boolean; overall_access: PermissionAccess; device_access: PermissionAccess; app_access: PermissionAccess; desktop_app_access: PermissionAccess } /** tauri-specta globals **/ diff --git a/src/components/settings/AccelerationSelector.tsx b/src/components/settings/AccelerationSelector.tsx new file mode 100644 index 0000000..888777d --- /dev/null +++ b/src/components/settings/AccelerationSelector.tsx @@ -0,0 +1,106 @@ +import { type FC, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { SettingContainer } from "../ui/SettingContainer"; +import { Dropdown, type DropdownOption } from "../ui/Dropdown"; +import { useSettings } from "../../hooks/useSettings"; +import { commands } from "@/bindings"; +import type { + WhisperAcceleratorSetting, + OrtAcceleratorSetting, +} from "@/bindings"; + +const WHISPER_LABELS: Record = { + auto: "Auto", + cpu: "CPU", + gpu: "GPU", +}; + +const ORT_LABELS: Record = { + auto: "Auto", + cpu: "CPU", + cuda: "CUDA", + directml: "DirectML", + rocm: "ROCm", +}; + +interface AccelerationSelectorProps { + descriptionMode?: "tooltip" | "inline"; + grouped?: boolean; +} + +export const AccelerationSelector: FC = ({ + descriptionMode = "tooltip", + grouped = false, +}) => { + const { t } = useTranslation(); + const { getSetting, updateSetting, isUpdating } = useSettings(); + + const [whisperOptions, setWhisperOptions] = useState([]); + const [ortOptions, setOrtOptions] = useState([]); + + useEffect(() => { + commands.getAvailableAccelerators().then((available) => { + setWhisperOptions( + available.whisper.map((v) => ({ + value: v, + label: WHISPER_LABELS[v as WhisperAcceleratorSetting] ?? v, + })), + ); + // Always include "auto" for ORT even though available() only returns compiled-in backends + const ortVals = available.ort.includes("auto") + ? available.ort + : ["auto", ...available.ort]; + setOrtOptions( + ortVals.map((v) => ({ + value: v, + label: ORT_LABELS[v as OrtAcceleratorSetting] ?? v, + })), + ); + }); + }, []); + + const currentWhisper = getSetting("whisper_accelerator") ?? "auto"; + const currentOrt = getSetting("ort_accelerator") ?? "auto"; + + return ( + <> + + + updateSetting( + "whisper_accelerator", + value as WhisperAcceleratorSetting, + ) + } + disabled={isUpdating("whisper_accelerator")} + /> + + {ortOptions.length > 2 && ( + + + updateSetting("ort_accelerator", value as OrtAcceleratorSetting) + } + disabled={isUpdating("ort_accelerator")} + /> + + )} + + ); +}; diff --git a/src/components/settings/advanced/AdvancedSettings.tsx b/src/components/settings/advanced/AdvancedSettings.tsx index 6b7bc3a..be3980f 100644 --- a/src/components/settings/advanced/AdvancedSettings.tsx +++ b/src/components/settings/advanced/AdvancedSettings.tsx @@ -18,6 +18,7 @@ import { RecordingRetentionPeriodSelector } from "../RecordingRetentionPeriod"; import { ExperimentalToggle } from "../ExperimentalToggle"; import { useSettings } from "../../../hooks/useSettings"; import { KeyboardImplementationSelector } from "../debug/KeyboardImplementationSelector"; +import { AccelerationSelector } from "../AccelerationSelector"; export const AdvancedSettings: React.FC = () => { const { t } = useTranslation(); @@ -62,6 +63,7 @@ export const AdvancedSettings: React.FC = () => { descriptionMode="tooltip" grouped={true} /> + )} diff --git a/src/i18n/locales/ar/translation.json b/src/i18n/locales/ar/translation.json index 251ee29..2da0536 100644 --- a/src/i18n/locales/ar/translation.json +++ b/src/i18n/locales/ar/translation.json @@ -223,6 +223,16 @@ "label": "الميزات التجريبية", "description": ".تمكين الميزات التجريبية التي لا تزال قيد التطوير" }, + "acceleration": { + "whisper": { + "title": "تسريع Whisper", + "description": "تسريع الأجهزة لنماذج Whisper. الوضع التلقائي يستخدم GPU إن توفر (Metal على macOS، Vulkan على Windows/Linux)." + }, + "ort": { + "title": "تسريع ONNX", + "description": "تسريع الأجهزة لنماذج ONNX (Parakeet، Canary، Moonshine، إلخ). DirectML على Windows تجريبي. قد تفشل النماذج في النسخ." + } + }, "startHidden": { "label": "بدء مخفي", "description": ".التشغيل في صينية النظام دون فتح النافذة" diff --git a/src/i18n/locales/cs/translation.json b/src/i18n/locales/cs/translation.json index b671318..2d95c1f 100644 --- a/src/i18n/locales/cs/translation.json +++ b/src/i18n/locales/cs/translation.json @@ -245,6 +245,16 @@ "label": "Experimentální funkce", "description": "Povolit experimentální funkce, které jsou stále ve vývoji." }, + "acceleration": { + "whisper": { + "title": "Akcelerace Whisper", + "description": "Hardwarová akcelerace pro modely Whisper. Automatický režim používá GPU, pokud je k dispozici (Metal na macOS, Vulkan na Windows/Linux)." + }, + "ort": { + "title": "Akcelerace ONNX", + "description": "Hardwarová akcelerace pro modely ONNX (Parakeet, Canary, Moonshine atd.). DirectML na Windows je experimentální. Modely nemusí správně přepisovat." + } + }, "startHidden": { "label": "Spouštět skrytě", "description": "Spustit do systémové lišty bez otevření okna." diff --git a/src/i18n/locales/de/translation.json b/src/i18n/locales/de/translation.json index 5451c49..b4223fd 100644 --- a/src/i18n/locales/de/translation.json +++ b/src/i18n/locales/de/translation.json @@ -245,6 +245,16 @@ "label": "Experimentelle Funktionen", "description": "Experimentelle Funktionen aktivieren, die sich noch in Entwicklung befinden." }, + "acceleration": { + "whisper": { + "title": "Whisper-Beschleunigung", + "description": "Hardwarebeschleunigung für Whisper-Modelle. Automatisch nutzt GPU falls verfügbar (Metal auf macOS, Vulkan auf Windows/Linux)." + }, + "ort": { + "title": "ONNX-Beschleunigung", + "description": "Hardwarebeschleunigung für ONNX-Modelle (Parakeet, Canary, Moonshine usw.). DirectML unter Windows ist experimentell. Modelle können bei der Transkription fehlschlagen." + } + }, "startHidden": { "label": "Versteckt starten", "description": "In den Systembereich starten, ohne das Fenster zu öffnen." diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index 66bfa24..5739244 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -245,6 +245,16 @@ "label": "Experimental Features", "description": "Enable experimental features that are still in development." }, + "acceleration": { + "whisper": { + "title": "Whisper Acceleration", + "description": "Hardware acceleration for Whisper models. Auto uses GPU if available (Metal on macOS, Vulkan on Windows/Linux)." + }, + "ort": { + "title": "ONNX Acceleration", + "description": "Hardware acceleration for ONNX models (Parakeet, Canary, Moonshine, etc.). DirectML on Windows is experimental. Models may fail to transcribe." + } + }, "startHidden": { "label": "Start Hidden", "description": "Launch to system tray without opening the window." diff --git a/src/i18n/locales/es/translation.json b/src/i18n/locales/es/translation.json index 18fae60..0624495 100644 --- a/src/i18n/locales/es/translation.json +++ b/src/i18n/locales/es/translation.json @@ -245,6 +245,16 @@ "label": "Funciones Experimentales", "description": "Habilitar funciones experimentales que aún están en desarrollo." }, + "acceleration": { + "whisper": { + "title": "Aceleración de Whisper", + "description": "Aceleración por hardware para modelos Whisper. Auto usa GPU si está disponible (Metal en macOS, Vulkan en Windows/Linux)." + }, + "ort": { + "title": "Aceleración de ONNX", + "description": "Aceleración por hardware para modelos ONNX (Parakeet, Canary, Moonshine, etc.). DirectML en Windows es experimental. Los modelos pueden fallar al transcribir." + } + }, "startHidden": { "label": "Iniciar Oculto", "description": "Lanzar en la bandeja del sistema sin abrir la ventana." diff --git a/src/i18n/locales/fr/translation.json b/src/i18n/locales/fr/translation.json index 2fa70e8..dca4d1d 100644 --- a/src/i18n/locales/fr/translation.json +++ b/src/i18n/locales/fr/translation.json @@ -245,6 +245,16 @@ "label": "Fonctionnalités Expérimentales", "description": "Activer les fonctionnalités expérimentales encore en développement." }, + "acceleration": { + "whisper": { + "title": "Accélération Whisper", + "description": "Accélération matérielle pour les modèles Whisper. Auto utilise le GPU si disponible (Metal sur macOS, Vulkan sur Windows/Linux)." + }, + "ort": { + "title": "Accélération ONNX", + "description": "Accélération matérielle pour les modèles ONNX (Parakeet, Canary, Moonshine, etc.). DirectML sur Windows est expérimental. Les modèles peuvent échouer à transcrire." + } + }, "startHidden": { "label": "Démarrer masqué", "description": "Lancer dans la barre système sans ouvrir la fenêtre." diff --git a/src/i18n/locales/it/translation.json b/src/i18n/locales/it/translation.json index 7cde7dc..3d920bf 100644 --- a/src/i18n/locales/it/translation.json +++ b/src/i18n/locales/it/translation.json @@ -245,6 +245,16 @@ "label": "Funzionalità Sperimentali", "description": "Abilita le funzionalità sperimentali ancora in fase di sviluppo." }, + "acceleration": { + "whisper": { + "title": "Accelerazione Whisper", + "description": "Accelerazione hardware per i modelli Whisper. Auto utilizza la GPU se disponibile (Metal su macOS, Vulkan su Windows/Linux)." + }, + "ort": { + "title": "Accelerazione ONNX", + "description": "Accelerazione hardware per i modelli ONNX (Parakeet, Canary, Moonshine, ecc.). DirectML su Windows è sperimentale. I modelli potrebbero non riuscire a trascrivere." + } + }, "startHidden": { "label": "Avvia in Background", "description": "Avvia l'applicazione in background senza aprire la finestra." diff --git a/src/i18n/locales/ja/translation.json b/src/i18n/locales/ja/translation.json index 4b1f953..fc9c055 100644 --- a/src/i18n/locales/ja/translation.json +++ b/src/i18n/locales/ja/translation.json @@ -245,6 +245,16 @@ "label": "実験的機能", "description": "まだ開発中の実験的機能を有効にします。" }, + "acceleration": { + "whisper": { + "title": "Whisper アクセラレーション", + "description": "Whisper モデルのハードウェアアクセラレーション。自動モードでは利用可能な場合 GPU を使用します(macOS では Metal、Windows/Linux では Vulkan)。" + }, + "ort": { + "title": "ONNX アクセラレーション", + "description": "ONNX モデルのハードウェアアクセラレーション(Parakeet、Canary、Moonshine など)。Windows の DirectML は実験的です。モデルの文字起こしに失敗する場合があります。" + } + }, "startHidden": { "label": "非表示で起動", "description": "ウィンドウを開かずにシステムトレイに起動。" diff --git a/src/i18n/locales/ko/translation.json b/src/i18n/locales/ko/translation.json index 6931315..8bc3463 100644 --- a/src/i18n/locales/ko/translation.json +++ b/src/i18n/locales/ko/translation.json @@ -245,6 +245,16 @@ "label": "실험적 기능", "description": "개발 중인 실험적 기능을 활성화합니다." }, + "acceleration": { + "whisper": { + "title": "Whisper 가속", + "description": "Whisper 모델의 하드웨어 가속. 자동 모드는 GPU를 사용합니다 (macOS에서는 Metal, Windows/Linux에서는 Vulkan)." + }, + "ort": { + "title": "ONNX 가속", + "description": "ONNX 모델의 하드웨어 가속 (Parakeet, Canary, Moonshine 등). Windows의 DirectML은 실험적입니다. 모델이 전사에 실패할 수 있습니다." + } + }, "startHidden": { "label": "숨김으로 시작", "description": "창을 열지 않고 시스템 트레이에서 실행합니다." diff --git a/src/i18n/locales/pl/translation.json b/src/i18n/locales/pl/translation.json index 071dfea..4ebcdb1 100644 --- a/src/i18n/locales/pl/translation.json +++ b/src/i18n/locales/pl/translation.json @@ -245,6 +245,16 @@ "label": "Funkcje Eksperymentalne", "description": "Włącz funkcje eksperymentalne, które są jeszcze w fazie rozwoju." }, + "acceleration": { + "whisper": { + "title": "Akceleracja Whisper", + "description": "Akceleracja sprzętowa dla modeli Whisper. Tryb automatyczny używa GPU, jeśli jest dostępny (Metal na macOS, Vulkan na Windows/Linux)." + }, + "ort": { + "title": "Akceleracja ONNX", + "description": "Akceleracja sprzętowa dla modeli ONNX (Parakeet, Canary, Moonshine itp.). DirectML na Windows jest eksperymentalne. Modele mogą nie transkrybować poprawnie." + } + }, "startHidden": { "label": "Uruchom ukryty", "description": "Uruchom w zasobniku systemowym bez otwierania okna." diff --git a/src/i18n/locales/pt/translation.json b/src/i18n/locales/pt/translation.json index fced01a..51d8c49 100644 --- a/src/i18n/locales/pt/translation.json +++ b/src/i18n/locales/pt/translation.json @@ -245,6 +245,16 @@ "label": "Recursos Experimentais", "description": "Ativar recursos experimentais que ainda estão em desenvolvimento." }, + "acceleration": { + "whisper": { + "title": "Aceleração Whisper", + "description": "Aceleração por hardware para modelos Whisper. Auto usa GPU se disponível (Metal no macOS, Vulkan no Windows/Linux)." + }, + "ort": { + "title": "Aceleração ONNX", + "description": "Aceleração por hardware para modelos ONNX (Parakeet, Canary, Moonshine, etc.). DirectML no Windows é experimental. Os modelos podem falhar na transcrição." + } + }, "startHidden": { "label": "Iniciar Oculto", "description": "Iniciar na bandeja do sistema sem abrir a janela." diff --git a/src/i18n/locales/ru/translation.json b/src/i18n/locales/ru/translation.json index 1c90413..ce4ec74 100644 --- a/src/i18n/locales/ru/translation.json +++ b/src/i18n/locales/ru/translation.json @@ -245,6 +245,16 @@ "label": "Экспериментальные функции", "description": "Включить экспериментальные функции, которые находятся в разработке." }, + "acceleration": { + "whisper": { + "title": "Ускорение Whisper", + "description": "Аппаратное ускорение для моделей Whisper. Автоматический режим использует GPU при наличии (Metal на macOS, Vulkan на Windows/Linux)." + }, + "ort": { + "title": "Ускорение ONNX", + "description": "Аппаратное ускорение для моделей ONNX (Parakeet, Canary, Moonshine и др.). DirectML на Windows является экспериментальным. Модели могут не выполнять транскрипцию." + } + }, "startHidden": { "label": "Скрыть при запуске", "description": "Запускать в системный трей, не открывая окно." diff --git a/src/i18n/locales/tr/translation.json b/src/i18n/locales/tr/translation.json index 3b33ebe..e5c5c1e 100644 --- a/src/i18n/locales/tr/translation.json +++ b/src/i18n/locales/tr/translation.json @@ -245,6 +245,16 @@ "label": "Deneysel Özellikler", "description": "Hala geliştirme aşamasında olan deneysel özellikleri etkinleştir." }, + "acceleration": { + "whisper": { + "title": "Whisper Hızlandırma", + "description": "Whisper modelleri için donanım hızlandırma. Otomatik mod, mevcutsa GPU kullanır (macOS'ta Metal, Windows/Linux'ta Vulkan)." + }, + "ort": { + "title": "ONNX Hızlandırma", + "description": "ONNX modelleri için donanım hızlandırma (Parakeet, Canary, Moonshine vb.). Windows'ta DirectML deneyseldir. Modeller transkripsiyon yapamayabilir." + } + }, "startHidden": { "label": "Gizli Başlat", "description": "Pencereyi açmadan sistem tepsisinde başlatır." diff --git a/src/i18n/locales/uk/translation.json b/src/i18n/locales/uk/translation.json index 2c5a6f9..1482ce4 100644 --- a/src/i18n/locales/uk/translation.json +++ b/src/i18n/locales/uk/translation.json @@ -245,6 +245,16 @@ "label": "Експериментальні функції", "description": "Увімкнути експериментальні функції, які ще в розробці." }, + "acceleration": { + "whisper": { + "title": "Прискорення Whisper", + "description": "Апаратне прискорення для моделей Whisper. Автоматичний режим використовує GPU за наявності (Metal на macOS, Vulkan на Windows/Linux)." + }, + "ort": { + "title": "Прискорення ONNX", + "description": "Апаратне прискорення для моделей ONNX (Parakeet, Canary, Moonshine тощо). DirectML на Windows є експериментальним. Моделі можуть не виконувати транскрипцію." + } + }, "startHidden": { "label": "Запуск у фоні", "description": "Запускати в системному треї без відкриття вікна" diff --git a/src/i18n/locales/vi/translation.json b/src/i18n/locales/vi/translation.json index e72d8cc..2d662b6 100644 --- a/src/i18n/locales/vi/translation.json +++ b/src/i18n/locales/vi/translation.json @@ -245,6 +245,16 @@ "label": "Tính năng thử nghiệm", "description": "Bật các tính năng thử nghiệm đang trong quá trình phát triển." }, + "acceleration": { + "whisper": { + "title": "Tăng tốc Whisper", + "description": "Tăng tốc phần cứng cho các mô hình Whisper. Chế độ tự động sử dụng GPU nếu có (Metal trên macOS, Vulkan trên Windows/Linux)." + }, + "ort": { + "title": "Tăng tốc ONNX", + "description": "Tăng tốc phần cứng cho các mô hình ONNX (Parakeet, Canary, Moonshine, v.v.). DirectML trên Windows là thử nghiệm. Các mô hình có thể không chuyển đổi giọng nói được." + } + }, "startHidden": { "label": "Khởi động ẩn", "description": "Khởi động vào khay hệ thống mà không mở cửa sổ." diff --git a/src/i18n/locales/zh-TW/translation.json b/src/i18n/locales/zh-TW/translation.json index f2a315f..cbe5218 100644 --- a/src/i18n/locales/zh-TW/translation.json +++ b/src/i18n/locales/zh-TW/translation.json @@ -245,6 +245,16 @@ "label": "實驗性功能", "description": "啟用仍在開發中的實驗性功能" }, + "acceleration": { + "whisper": { + "title": "Whisper 加速", + "description": "Whisper 模型的硬體加速。自動模式在可用時使用 GPU(macOS 上使用 Metal,Windows/Linux 上使用 Vulkan)。" + }, + "ort": { + "title": "ONNX 加速", + "description": "ONNX 模型的硬體加速(Parakeet、Canary、Moonshine 等)。Windows 上的 DirectML 為實驗性功能。模型可能無法正常轉錄。" + } + }, "startHidden": { "label": "隱藏啟動", "description": "啟動至系統匣而不開啟視窗" diff --git a/src/i18n/locales/zh/translation.json b/src/i18n/locales/zh/translation.json index 874e975..6cc5049 100644 --- a/src/i18n/locales/zh/translation.json +++ b/src/i18n/locales/zh/translation.json @@ -245,6 +245,16 @@ "label": "实验性功能", "description": "启用仍在开发中的实验性功能。" }, + "acceleration": { + "whisper": { + "title": "Whisper 加速", + "description": "Whisper 模型的硬件加速。自动模式在可用时使用 GPU(macOS 上使用 Metal,Windows/Linux 上使用 Vulkan)。" + }, + "ort": { + "title": "ONNX 加速", + "description": "ONNX 模型的硬件加速(Parakeet、Canary、Moonshine 等)。Windows 上的 DirectML 为实验性功能。模型可能无法正常转录。" + } + }, "startHidden": { "label": "隐藏启动", "description": "启动到系统托盘而不打开窗口。" diff --git a/src/stores/settingsStore.ts b/src/stores/settingsStore.ts index 2ef36f7..325c06e 100644 --- a/src/stores/settingsStore.ts +++ b/src/stores/settingsStore.ts @@ -1,7 +1,12 @@ import { create } from "zustand"; import { subscribeWithSelector } from "zustand/middleware"; import { listen } from "@tauri-apps/api/event"; -import type { AppSettings as Settings, AudioDevice } from "@/bindings"; +import type { + AppSettings as Settings, + AudioDevice, + WhisperAcceleratorSetting, + OrtAcceleratorSetting, +} from "@/bindings"; import { commands } from "@/bindings"; interface SettingsStore { @@ -136,6 +141,12 @@ const settingUpdaters: { commands.changeExperimentalEnabledSetting(value as boolean), show_tray_icon: (value) => commands.changeShowTrayIconSetting(value as boolean), + whisper_accelerator: (value) => + commands.changeWhisperAcceleratorSetting( + value as WhisperAcceleratorSetting, + ), + ort_accelerator: (value) => + commands.changeOrtAcceleratorSetting(value as OrtAcceleratorSetting), }; export const useSettingsStore = create()(