experimental: pick between cpu/gpu acceleration + enable directml on windows (#1058)

* first pass at gpu acceleration

* unload the model when changing

* mock accelerator

* translations and build fix

* format

* clean up helptext

* type cleanup

* format

* lint
This commit is contained in:
CJ Pais 2026-03-16 20:41:30 +08:00 committed by GitHub
parent f8bbcd791c
commit cafc2b7208
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 484 additions and 64 deletions

69
src-tauri/Cargo.lock generated
View file

@ -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"

View file

@ -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",

View file

@ -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,

View file

@ -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<String>,
pub ort: Vec<String>,
}
/// Return which accelerators are compiled into this build.
pub fn get_available_accelerators() -> AvailableAccelerators {
use transcribe_rs::accel::OrtAccelerator;
let ort_options: Vec<String> = 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");

View file

@ -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<String>,
pub ort: Vec<String>,
}
/// Returns empty lists in CI mock.
pub fn get_available_accelerators() -> AvailableAccelerators {
AvailableAccelerators {
whisper: vec![],
ort: vec![],
}
}

View file

@ -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<String>,
#[serde(default)]
pub custom_filler_words: Option<Vec<String>>,
#[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(),
}
}

View file

@ -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::<std::sync::Arc<crate::managers::transcription::TranscriptionManager>>();
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()
}

View file

@ -339,6 +339,28 @@ async changeShowTrayIconSetting(enabled: boolean) : Promise<Result<null, string>
else return { status: "error", error: e as any };
}
},
async changeWhisperAcceleratorSetting(accelerator: WhisperAcceleratorSetting) : Promise<Result<null, string>> {
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<Result<null, string>> {
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<AvailableAccelerators> {
return await TAURI_INVOKE("get_available_accelerators");
},
/**
* Start key recording mode
*/
@ -757,9 +779,10 @@ async isLaptop() : Promise<Result<boolean, string>> {
/** 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 **/

View file

@ -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<WhisperAcceleratorSetting, string> = {
auto: "Auto",
cpu: "CPU",
gpu: "GPU",
};
const ORT_LABELS: Record<OrtAcceleratorSetting, string> = {
auto: "Auto",
cpu: "CPU",
cuda: "CUDA",
directml: "DirectML",
rocm: "ROCm",
};
interface AccelerationSelectorProps {
descriptionMode?: "tooltip" | "inline";
grouped?: boolean;
}
export const AccelerationSelector: FC<AccelerationSelectorProps> = ({
descriptionMode = "tooltip",
grouped = false,
}) => {
const { t } = useTranslation();
const { getSetting, updateSetting, isUpdating } = useSettings();
const [whisperOptions, setWhisperOptions] = useState<DropdownOption[]>([]);
const [ortOptions, setOrtOptions] = useState<DropdownOption[]>([]);
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 (
<>
<SettingContainer
title={t("settings.advanced.acceleration.whisper.title")}
description={t("settings.advanced.acceleration.whisper.description")}
descriptionMode={descriptionMode}
grouped={grouped}
layout="horizontal"
>
<Dropdown
options={whisperOptions}
selectedValue={currentWhisper}
onSelect={(value) =>
updateSetting(
"whisper_accelerator",
value as WhisperAcceleratorSetting,
)
}
disabled={isUpdating("whisper_accelerator")}
/>
</SettingContainer>
{ortOptions.length > 2 && (
<SettingContainer
title={t("settings.advanced.acceleration.ort.title")}
description={t("settings.advanced.acceleration.ort.description")}
descriptionMode={descriptionMode}
grouped={grouped}
layout="horizontal"
>
<Dropdown
options={ortOptions}
selectedValue={currentOrt}
onSelect={(value) =>
updateSetting("ort_accelerator", value as OrtAcceleratorSetting)
}
disabled={isUpdating("ort_accelerator")}
/>
</SettingContainer>
)}
</>
);
};

View file

@ -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}
/>
<AccelerationSelector descriptionMode="tooltip" grouped={true} />
</SettingsGroup>
)}
</div>

View file

@ -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": ".التشغيل في صينية النظام دون فتح النافذة"

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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": "ウィンドウを開かずにシステムトレイに起動。"

View file

@ -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": "창을 열지 않고 시스템 트레이에서 실행합니다."

View file

@ -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."

View file

@ -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."

View file

@ -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": "Запускать в системный трей, не открывая окно."

View file

@ -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."

View file

@ -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": "Запускати в системному треї без відкриття вікна"

View file

@ -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ổ."

View file

@ -245,6 +245,16 @@
"label": "實驗性功能",
"description": "啟用仍在開發中的實驗性功能"
},
"acceleration": {
"whisper": {
"title": "Whisper 加速",
"description": "Whisper 模型的硬體加速。自動模式在可用時使用 GPUmacOS 上使用 MetalWindows/Linux 上使用 Vulkan。"
},
"ort": {
"title": "ONNX 加速",
"description": "ONNX 模型的硬體加速Parakeet、Canary、Moonshine 等。Windows 上的 DirectML 為實驗性功能。模型可能無法正常轉錄。"
}
},
"startHidden": {
"label": "隱藏啟動",
"description": "啟動至系統匣而不開啟視窗"

View file

@ -245,6 +245,16 @@
"label": "实验性功能",
"description": "启用仍在开发中的实验性功能。"
},
"acceleration": {
"whisper": {
"title": "Whisper 加速",
"description": "Whisper 模型的硬件加速。自动模式在可用时使用 GPUmacOS 上使用 MetalWindows/Linux 上使用 Vulkan。"
},
"ort": {
"title": "ONNX 加速",
"description": "ONNX 模型的硬件加速Parakeet、Canary、Moonshine 等。Windows 上的 DirectML 为实验性功能。模型可能无法正常转录。"
}
},
"startHidden": {
"label": "隐藏启动",
"description": "启动到系统托盘而不打开窗口。"

View file

@ -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<SettingsStore>()(