From c3aa2d7c1b5586132e8913f01baf915e137818a9 Mon Sep 17 00:00:00 2001 From: segudev <41948994+segudev@users.noreply.github.com> Date: Fri, 11 Jul 2025 17:42:54 -0700 Subject: [PATCH 1/2] Add "Translate to English" setting: Introduced a new setting to enable automatic translation of speech to English. Updated relevant components, settings modules, and transcription logic to support this feature. Adjusted accessibility permission calls for consistency. --- src-tauri/src/lib.rs | 1 + src-tauri/src/managers/transcription.rs | 11 ++++++++++- src-tauri/src/settings.rs | 17 +++++++++++++---- src-tauri/src/shortcut.rs | 8 ++++++++ src/lib/types.ts | 1 + 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e6f7d25..6897a89 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -175,6 +175,7 @@ pub fn run() { shortcut::reset_binding, shortcut::change_ptt_setting, shortcut::change_audio_feedback_setting, + shortcut::change_translate_to_english_setting, trigger_update_check, commands::models::get_available_models, commands::models::get_model_info, diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index 7d64087..01035fe 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -173,6 +173,9 @@ impl TranscriptionManager { ) })?; + // Get current settings to check translation preference + let settings = get_settings(&self.app_handle); + // Initialize parameters let mut params = FullParams::new(SamplingStrategy::default()); params.set_language(Some("auto")); @@ -182,6 +185,11 @@ impl TranscriptionManager { params.set_print_timestamps(false); params.set_suppress_blank(true); params.set_suppress_non_speech_tokens(true); + + // Enable translation to English if requested + if settings.translate_to_english { + params.set_translate(true); + } state .full(params, &audio) @@ -199,7 +207,8 @@ impl TranscriptionManager { } let et = std::time::Instant::now(); - println!("\ntook {}ms", (et - st).as_millis()); + let translation_note = if settings.translate_to_english { " (translated)" } else { "" }; + println!("\ntook {}ms{}", (et - st).as_millis(), translation_note); Ok(result.trim().to_string()) } diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index aeb96a8..7b441ee 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -26,6 +26,8 @@ pub struct AppSettings { pub selected_microphone: Option, #[serde(default)] pub selected_output_device: Option, + #[serde(default = "default_translate_to_english")] + pub translate_to_english: bool, } fn default_model() -> String { @@ -40,6 +42,11 @@ fn default_always_on_microphone() -> bool { false } +fn default_translate_to_english() -> bool { + // Default to false - users need to opt-in to translation + false +} + pub const SETTINGS_STORE_PATH: &str = "settings_store.json"; pub fn get_default_settings() -> AppSettings { @@ -47,12 +54,12 @@ pub fn get_default_settings() -> AppSettings { #[cfg(target_os = "windows")] let default_shortcut = "ctrl+space"; #[cfg(target_os = "macos")] - let default_shortcut = "alt+space"; // Alt key on macOS (Option key) + let default_shortcut = "alt+space"; // Alt key on macOS (Option key) #[cfg(target_os = "linux")] let default_shortcut = "ctrl+space"; #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - let default_shortcut = "alt+space"; // Fallback for other platforms - + let default_shortcut = "alt+space"; // Fallback for other platforms + let mut bindings = HashMap::new(); bindings.insert( "transcribe".to_string(), @@ -83,6 +90,7 @@ pub fn get_default_settings() -> AppSettings { always_on_microphone: false, selected_microphone: None, selected_output_device: None, + translate_to_english: false, } } @@ -130,7 +138,8 @@ pub fn get_settings(app: &AppHandle) -> AppSettings { .expect("Failed to initialize store"); if let Some(settings_value) = store.get("settings") { - serde_json::from_value::(settings_value).unwrap_or_else(|_| get_default_settings()) + serde_json::from_value::(settings_value) + .unwrap_or_else(|_| get_default_settings()) } else { get_default_settings() } diff --git a/src-tauri/src/shortcut.rs b/src-tauri/src/shortcut.rs index fae9de7..516a32e 100644 --- a/src-tauri/src/shortcut.rs +++ b/src-tauri/src/shortcut.rs @@ -111,6 +111,14 @@ pub fn change_audio_feedback_setting(app: AppHandle, enabled: bool) -> Result<() Ok(()) } +#[tauri::command] +pub fn change_translate_to_english_setting(app: AppHandle, enabled: bool) -> Result<(), String> { + let mut settings = settings::get_settings(&app); + settings.translate_to_english = enabled; + settings::write_settings(&app, settings); + Ok(()) +} + fn _register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<(), String> { // Parse shortcut and return error if it fails let shortcut = match binding.current_binding.parse::() { diff --git a/src/lib/types.ts b/src/lib/types.ts index fd97768..e8314c1 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -27,6 +27,7 @@ export const SettingsSchema = z.object({ always_on_microphone: z.boolean(), selected_microphone: z.string().nullable().optional(), selected_output_device: z.string().nullable().optional(), + translate_to_english: z.boolean(), }); export const BindingResponseSchema = z.object({ From 21e96083dfdd38e3a747f38b394bf16b95ef07cb Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Fri, 11 Jul 2025 18:01:12 -0700 Subject: [PATCH 2/2] add ui toggle back --- src-tauri/src/managers/transcription.rs | 8 +++-- src-tauri/tauri.conf.json | 4 +-- src/components/settings/Settings.tsx | 2 ++ .../settings/TranslateToEnglish.tsx | 29 +++++++++++++++++++ src/components/settings/index.ts | 1 + src/hooks/useSettings.ts | 6 ++++ 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/components/settings/TranslateToEnglish.tsx diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index 01035fe..5212f7e 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -185,7 +185,7 @@ impl TranscriptionManager { params.set_print_timestamps(false); params.set_suppress_blank(true); params.set_suppress_non_speech_tokens(true); - + // Enable translation to English if requested if settings.translate_to_english { params.set_translate(true); @@ -207,7 +207,11 @@ impl TranscriptionManager { } let et = std::time::Instant::now(); - let translation_note = if settings.translate_to_english { " (translated)" } else { "" }; + let translation_note = if settings.translate_to_english { + " (translated)" + } else { + "" + }; println!("\ntook {}ms{}", (et - st).as_millis(), translation_note); Ok(result.trim().to_string()) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ffc77be..bd90ebc 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -14,9 +14,9 @@ { "title": "Handy", "width": 540, - "height": 590, + "height": 630, "minWidth": 540, - "minHeight": 590, + "minHeight": 630, "resizable": true, "maximizable": false } diff --git a/src/components/settings/Settings.tsx b/src/components/settings/Settings.tsx index 423174d..9d31e16 100644 --- a/src/components/settings/Settings.tsx +++ b/src/components/settings/Settings.tsx @@ -5,6 +5,7 @@ import { PushToTalk } from "./PushToTalk"; import { AudioFeedback } from "./AudioFeedback"; import { OutputDeviceSelector } from "./OutputDeviceSelector"; import { HandyShortcut } from "./HandyShortcut"; +import { TranslateToEnglish } from "./TranslateToEnglish"; import { SettingsGroup } from "../ui/SettingsGroup"; export const Settings: React.FC = () => { @@ -19,6 +20,7 @@ export const Settings: React.FC = () => { + diff --git a/src/components/settings/TranslateToEnglish.tsx b/src/components/settings/TranslateToEnglish.tsx new file mode 100644 index 0000000..92917c3 --- /dev/null +++ b/src/components/settings/TranslateToEnglish.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { ToggleSwitch } from "../ui/ToggleSwitch"; +import { useSettings } from "../../hooks/useSettings"; + +interface TranslateToEnglishProps { + descriptionMode?: "inline" | "tooltip"; + grouped?: boolean; +} + +export const TranslateToEnglish: React.FC = ({ + descriptionMode = "tooltip", + grouped = false, +}) => { + const { getSetting, updateSetting, isUpdating } = useSettings(); + + const translateToEnglish = getSetting("translate_to_english") || false; + + return ( + updateSetting("translate_to_english", enabled)} + isUpdating={isUpdating("translate_to_english")} + label="Translate to English" + description="Automatically translate speech from other languages to English during transcription." + descriptionMode={descriptionMode} + grouped={grouped} + /> + ); +}; diff --git a/src/components/settings/index.ts b/src/components/settings/index.ts index 81c1d65..b6f37bf 100644 --- a/src/components/settings/index.ts +++ b/src/components/settings/index.ts @@ -5,3 +5,4 @@ export { AlwaysOnMicrophone } from "./AlwaysOnMicrophone"; export { PushToTalk } from "./PushToTalk"; export { AudioFeedback } from "./AudioFeedback"; export { HandyShortcut } from "./HandyShortcut"; +export { TranslateToEnglish } from "./TranslateToEnglish"; diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts index 103e611..e1170ae 100644 --- a/src/hooks/useSettings.ts +++ b/src/hooks/useSettings.ts @@ -189,6 +189,11 @@ export const useSettings = (): UseSettingsReturn => { deviceName: outputDeviceName, }); break; + case "translate_to_english": + await invoke("change_translate_to_english_setting", { + enabled: value, + }); + break; case "bindings": // Handle bindings separately - they use their own invoke methods break; @@ -231,6 +236,7 @@ export const useSettings = (): UseSettingsReturn => { push_to_talk: false, selected_microphone: "Default", selected_output_device: "Default", + translate_to_english: false, }; const defaultValue = defaults[key];