diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 6caeaf9..2630a7a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -109,6 +109,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -432,6 +482,26 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.69.5" @@ -705,6 +775,25 @@ dependencies = [ "toml 0.9.8", ] +[[package]] +name = "cbindgen" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" +dependencies = [ + "clap", + "heck 0.5.0", + "indexmap 2.12.0", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.108", + "tempfile", + "toml 0.9.8", +] + [[package]] name = "cc" version = "1.2.43" @@ -788,6 +877,46 @@ dependencies = [ "libloading 0.8.9", ] +[[package]] +name = "clap" +version = "4.5.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8120877db0e5c011242f96806ce3c94e0737ab8108532a76a3300a01db2ab8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02576b399397b659c26064fbc92a75fede9d18ffd5f80ca1cd74ddab167016e1" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.108", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + [[package]] name = "clipboard-win" version = "5.4.1" @@ -836,6 +965,12 @@ dependencies = [ "objc", ] +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "combine" version = "4.6.7" @@ -1704,6 +1839,38 @@ dependencies = [ "log", ] +[[package]] +name = "ferrous-opencc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7604efd2d4d8ee72dcbf7b24b604d7a4c764dfab40152bbe12ae241f784560b" +dependencies = [ + "anyhow", + "bincode", + "cbindgen", + "clap", + "ferrous-opencc-compiler", + "fst", + "phf 0.11.3", + "phf_codegen 0.11.3", + "serde", + "serde_json", + "tempfile", + "thiserror 2.0.17", + "wasm-bindgen-test", +] + +[[package]] +name = "ferrous-opencc-compiler" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161c89665fa27878bd14fa7adc2e392f4e17f6fe9d45d66d6e73585c70f3e4e0" +dependencies = [ + "anyhow", + "bincode", + "fst", +] + [[package]] name = "field-offset" version = "0.3.6" @@ -1828,6 +1995,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + [[package]] name = "funty" version = "2.0.0" @@ -2335,6 +2508,7 @@ dependencies = [ "cpal", "enigo", "env_filter", + "ferrous-opencc", "flate2", "futures-util", "hound", @@ -2903,6 +3077,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.12.1" @@ -3278,6 +3458,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "minicov" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3922,6 +4112,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "open" version = "5.3.2" @@ -7353,6 +7549,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "ureq" version = "3.1.2" @@ -7426,6 +7628,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.18.1" @@ -7473,6 +7681,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "vswhom" version = "0.1.0" @@ -7611,6 +7825,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-bindgen-test" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e381134e148c1062f965a42ed1f5ee933eef2927c3f70d1812158f711d39865" +dependencies = [ + "js-sys", + "minicov", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b673bca3298fe582aeef8352330ecbad91849f85090805582400850f8270a2e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "wasm-streams" version = "0.4.2" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 9ea5bbc..55e21c3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -67,6 +67,7 @@ rusqlite = { version = "0.32.1", features = ["bundled"] } tar = "0.4.44" flate2 = "1.0" transcribe-rs = "0.1.4" +ferrous-opencc = "0.2.3" [target.'cfg(unix)'.dependencies] signal-hook = "0.3" diff --git a/src-tauri/src/actions.rs b/src-tauri/src/actions.rs index d47dc84..41952d5 100644 --- a/src-tauri/src/actions.rs +++ b/src-tauri/src/actions.rs @@ -12,6 +12,7 @@ use async_openai::types::{ }; use log::{debug, error}; use once_cell::sync::Lazy; +use ferrous_opencc::{OpenCC, config::BuiltinConfig}; use std::collections::HashMap; use std::sync::Arc; use std::time::Instant; @@ -160,6 +161,47 @@ async fn maybe_post_process_transcription( } } +async fn maybe_convert_chinese_variant( + settings: &AppSettings, + transcription: &str, +) -> Option { + // Check if language is set to Simplified or Traditional Chinese + let is_simplified = settings.selected_language == "zh-Hans"; + let is_traditional = settings.selected_language == "zh-Hant"; + + if !is_simplified && !is_traditional { + debug!("selected_language is not Simplified or Traditional Chinese; skipping translation"); + return None; + } + + debug!("Starting Chinese translation using OpenCC for language: {}", settings.selected_language); + + // Use OpenCC to convert based on selected language + let config = if is_simplified { + // Convert Traditional Chinese to Simplified Chinese + BuiltinConfig::Tw2sp + } else { + // Convert Simplified Chinese to Traditional Chinese + BuiltinConfig::S2twp + }; + + match OpenCC::from_config(config) { + Ok(converter) => { + let converted = converter.convert(transcription); + debug!( + "OpenCC translation completed. Input length: {}, Output length: {}", + transcription.len(), + converted.len() + ); + Some(converted) + } + Err(e) => { + error!("Failed to initialize OpenCC converter: {}. Falling back to original transcription.", e); + None + } + } +} + impl ShortcutAction for TranscribeAction { fn start(&self, app: &AppHandle, binding_id: &str, _shortcut_str: &str) { let start_time = Instant::now(); @@ -273,7 +315,15 @@ impl ShortcutAction for TranscribeAction { let mut post_processed_text: Option = None; let mut post_process_prompt: Option = None; - if let Some(processed_text) = + // First, check if Chinese variant conversion is needed + if let Some(converted_text) = + maybe_convert_chinese_variant(&settings, &transcription).await + { + final_text = converted_text.clone(); + post_processed_text = Some(converted_text); + } + // Then apply regular post-processing if enabled + else if let Some(processed_text) = maybe_post_process_transcription(&settings, &transcription).await { final_text = processed_text.clone(); diff --git a/src-tauri/src/managers/transcription.rs b/src-tauri/src/managers/transcription.rs index d87b88e..ad03368 100644 --- a/src-tauri/src/managers/transcription.rs +++ b/src-tauri/src/managers/transcription.rs @@ -349,12 +349,21 @@ impl TranscriptionManager { match engine { LoadedEngine::Whisper(whisper_engine) => { - let params = WhisperInferenceParams { - language: if settings.selected_language == "auto" { - None + // Normalize language code for Whisper + // Convert zh-Hans and zh-Hant to zh since Whisper uses ISO 639-1 codes + let whisper_language = if settings.selected_language == "auto" { + None + } else { + let normalized = if settings.selected_language == "zh-Hans" || settings.selected_language == "zh-Hant" { + "zh".to_string() } else { - Some(settings.selected_language.clone()) - }, + settings.selected_language.clone() + }; + Some(normalized) + }; + + let params = WhisperInferenceParams { + language: whisper_language, translate: settings.translate_to_english, ..Default::default() }; diff --git a/src/lib/constants/languages.ts b/src/lib/constants/languages.ts index 42cbf65..ebcd22a 100644 --- a/src/lib/constants/languages.ts +++ b/src/lib/constants/languages.ts @@ -6,7 +6,8 @@ export interface Language { export const LANGUAGES: Language[] = [ { value: "auto", label: "Auto Detect" }, { value: "en", label: "English" }, - { value: "zh", label: "Chinese" }, + { value: "zh-Hans", label: "Simplified Chinese" }, + { value: "zh-Hant", label: "Traditional Chinese" }, { value: "de", label: "German" }, { value: "es", label: "Spanish" }, { value: "ru", label: "Russian" },