add cohere (#1200)

* add cohere

* format

* add appropriate translations

* add chinese properly

* 0.3.8 sentencepiece fix

* update
This commit is contained in:
CJ Pais 2026-04-01 20:36:34 +08:00 committed by GitHub
parent 892658ee89
commit 4609db7fdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 161 additions and 17 deletions

4
src-tauri/Cargo.lock generated
View file

@ -6992,9 +6992,9 @@ dependencies = [
[[package]]
name = "transcribe-rs"
version = "0.3.5"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d72db290071cb4c3da90136174b1a108771311a5d506c74738e1a4da71da2c38"
checksum = "b231bc9bd1b20be89583a49c3885dfa7d7323299564ee78eddf83db04f2b337b"
dependencies = [
"base64 0.22.1",
"derive_builder",

View file

@ -69,7 +69,7 @@ rusqlite = { version = "0.37", features = ["bundled"] }
tar = "0.4.44"
flate2 = "1.0"
sha2 = "0.10"
transcribe-rs = { version = "0.3.5", features = ["whisper-cpp", "onnx"] }
transcribe-rs = { version = "0.3.8", features = ["whisper-cpp", "onnx"] }
handy-keys = "0.2.4"
ferrous-opencc = "0.2.3"
clap = { version = "4", features = ["derive"] }

View file

@ -26,6 +26,7 @@ pub enum EngineType {
SenseVoice,
GigaAM,
Canary,
Cohere,
}
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
@ -133,7 +134,7 @@ impl ModelManager {
sha256: Some(
"1be3a9b2063867b937e64e2ec7483364a79917e157fa98c5d94b5c1fffea987b".to_string(),
),
size_mb: 487,
size_mb: 465,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -161,7 +162,7 @@ impl ModelManager {
sha256: Some(
"79283fc1f9fe12ca3248543fbd54b73292164d8df5a16e095e2bceeaaabddf57".to_string(),
),
size_mb: 492, // Approximate size
size_mb: 469,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -188,7 +189,7 @@ impl ModelManager {
sha256: Some(
"1fc70f774d38eb169993ac391eea357ef47c88757ef72ee5943879b7e8e2bc69".to_string(),
),
size_mb: 1600, // Approximate size
size_mb: 1549,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -215,7 +216,7 @@ impl ModelManager {
sha256: Some(
"d75795ecff3f83b5faa89d1900604ad8c780abd5739fae406de19f23ecd98ad1".to_string(),
),
size_mb: 1100, // Approximate size
size_mb: 1031,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -243,7 +244,7 @@ impl ModelManager {
sha256: Some(
"8efbf0ce8a3f50fe332b7617da787fb81354b358c288b008d3bdef8359df64c6".to_string(),
),
size_mb: 1080,
size_mb: 1030,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -271,7 +272,7 @@ impl ModelManager {
sha256: Some(
"ac9b9429984dd565b25097337a887bb7f0f8ac393573661c651f0e7d31563991".to_string(),
),
size_mb: 473, // Approximate size for int8 quantized model
size_mb: 451,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -308,7 +309,7 @@ impl ModelManager {
sha256: Some(
"43d37191602727524a7d8c6da0eef11c4ba24320f5b4730f1a2497befc2efa77".to_string(),
),
size_mb: 478, // Approximate size for int8 quantized model
size_mb: 456,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -335,7 +336,7 @@ impl ModelManager {
sha256: Some(
"04bf6ab012cfceebd4ac7cf88c1b31d027bbdd3cd704649b692e2e935236b7e8".to_string(),
),
size_mb: 58,
size_mb: 55,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -393,7 +394,7 @@ impl ModelManager {
sha256: Some(
"dbb3e1c1832bd88a4ac712f7449a136cc2c9a18c5fe33a12ed1b7cb1cfe9cdd5".to_string(),
),
size_mb: 100,
size_mb: 99,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -457,7 +458,7 @@ impl ModelManager {
sha256: Some(
"171d611fe5d353a50bbb741b6f3ef42559b1565685684e9aa888ef563ba3e8a4".to_string(),
),
size_mb: 160,
size_mb: 152,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -487,7 +488,7 @@ impl ModelManager {
sha256: Some(
"d872462268430db140b69b72e0fc4b787b194c1dbe51b58de39444d55b6da45b".to_string(),
),
size_mb: 152,
size_mb: 151,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -558,7 +559,7 @@ impl ModelManager {
sha256: Some(
"02305b2a25f9cf3e7deaffa7f94df00efa44f442cd55c101c2cb9c000f904666".to_string(),
),
size_mb: 692,
size_mb: 691,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
@ -574,6 +575,41 @@ impl ModelManager {
},
);
let cohere_languages: Vec<String> = vec![
"en", "fr", "de", "it", "es", "pt", "el", "nl", "pl", "zh", "zh-Hans", "zh-Hant", "ja",
"ko", "vi", "ar",
]
.into_iter()
.map(String::from)
.collect();
available_models.insert(
"cohere-int8".to_string(),
ModelInfo {
id: "cohere-int8".to_string(),
name: "Cohere".to_string(),
description: "A large, slower, but very accurate multilingual model.".to_string(),
filename: "cohere-int8".to_string(),
url: Some("https://blob.handy.computer/cohere-int8.tar.gz".to_string()),
sha256: Some(
"ea2257d52434f3644574f187dcdcf666e302cd11b92866116ab8e14cd9c887f0".to_string(),
),
size_mb: 1708,
is_downloaded: false,
is_downloading: false,
partial_size: 0,
is_directory: true,
engine_type: EngineType::Cohere,
accuracy_score: 0.90,
speed_score: 0.60,
supports_translation: false,
is_recommended: false,
supported_languages: cohere_languages,
supports_language_selection: true,
is_custom: false,
},
);
// Auto-discover custom Whisper models (.bin files) in the models directory
if let Err(e) = Self::discover_custom_whisper_models(&models_dir, &mut available_models) {
warn!("Failed to discover custom models: {}", e);

View file

@ -17,6 +17,7 @@ use tauri::{AppHandle, Emitter, Manager};
use transcribe_rs::{
onnx::{
canary::CanaryModel,
cohere::CohereModel,
gigaam::GigaAMModel,
moonshine::{MoonshineModel, MoonshineVariant, StreamingModel},
parakeet::{ParakeetModel, ParakeetParams, TimestampGranularity},
@ -43,6 +44,7 @@ enum LoadedEngine {
SenseVoice(SenseVoiceModel),
GigaAM(GigaAMModel),
Canary(CanaryModel),
Cohere(CohereModel),
}
/// RAII guard that clears the `is_loading` flag and notifies waiters on drop.
@ -367,6 +369,14 @@ impl TranscriptionManager {
})?;
LoadedEngine::Canary(engine)
}
EngineType::Cohere => {
let engine = CohereModel::load(&model_path, &Quantization::Int8).map_err(|e| {
let error_msg = format!("Failed to load cohere model {}: {}", model_id, e);
emit_loading_failed(&error_msg);
anyhow::anyhow!(error_msg)
})?;
LoadedEngine::Cohere(engine)
}
};
// Update the current engine and model ID
@ -601,6 +611,24 @@ impl TranscriptionManager {
.transcribe(&audio, &options)
.map_err(|e| anyhow::anyhow!("Canary transcription failed: {}", e))
}
LoadedEngine::Cohere(cohere_engine) => {
let lang = if validated_language == "auto" {
None
} else if validated_language == "zh-Hans"
|| validated_language == "zh-Hant"
{
Some("zh".to_string())
} else {
Some(validated_language.clone())
};
let options = TranscribeOptions {
language: lang,
..Default::default()
};
cohere_engine
.transcribe(&audio, &options)
.map_err(|e| anyhow::anyhow!("Cohere transcription failed: {}", e))
}
}
},
));

View file

@ -834,7 +834,7 @@ export type AvailableAccelerators = { whisper: string[]; ort: string[]; gpu_devi
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 }
export type EngineType = "Whisper" | "Parakeet" | "Moonshine" | "MoonshineStreaming" | "SenseVoice" | "GigaAM" | "Canary"
export type EngineType = "Whisper" | "Parakeet" | "Moonshine" | "MoonshineStreaming" | "SenseVoice" | "GigaAM" | "Canary" | "Cohere"
export type GpuDeviceOption = { id: number; name: string; total_vram_mb: number }
export type HistoryEntry = { id: number; file_name: string; timestamp: number; saved: boolean; title: string; transcription_text: string; post_processed_text: string | null; post_process_prompt: string | null; post_process_requested: boolean }
export type HistoryUpdatePayload = { action: "added"; entry: HistoryEntry } | { action: "updated"; entry: HistoryEntry } | { action: "deleted"; id: number } | { action: "toggled"; id: number }

View file

@ -35,5 +35,5 @@ export const LANGUAGE_METADATA: Record<
ar: { name: "Arabic", nativeName: "العربية", priority: 17, direction: "rtl" },
he: { name: "Hebrew", nativeName: "עברית", priority: 18, direction: "rtl" },
sv: { name: "Swedish", nativeName: "Svenska", priority: 19 },
bg: { name: "Bulgarian", nativeName: "Български", priority: 20 }
bg: { name: "Bulgarian", nativeName: "Български", priority: 20 },
};

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "متعدد اللغات ودقيق. 25 لغة أوروبية. يدعم الترجمة."
},
"cohere-int8": {
"name": "Cohere",
"description": "نموذج كبير وأبطأ، لكنه دقيق جداً ومتعدد اللغات."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Точен многоезичен. 25 европейски езика. Поддържа превод."
},
"cohere-int8": {
"name": "Cohere",
"description": "Голям, по-бавен, но много точен многоезичен модел."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Přesný vícejazyčný. 25 evropských jazyků. Podporuje překlad."
},
"cohere-int8": {
"name": "Cohere",
"description": "Velký, pomalejší, ale velmi přesný vícejazyčný model."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Genaue mehrsprachige Erkennung. 25 europäische Sprachen. Unterstützt Übersetzung."
},
"cohere-int8": {
"name": "Cohere",
"description": "Ein großes, langsameres, aber sehr genaues mehrsprachiges Modell."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Accurate multilingual. 25 European languages. Supports translation."
},
"cohere-int8": {
"name": "Cohere",
"description": "A large, slower, but very accurate multilingual model."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Multilingüe preciso. 25 idiomas europeos. Soporta traducción."
},
"cohere-int8": {
"name": "Cohere",
"description": "Un modelo grande, más lento, pero muy preciso y multilingüe."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Multilingue précis. 25 langues européennes. Supporte la traduction."
},
"cohere-int8": {
"name": "Cohere",
"description": "Un modèle volumineux, plus lent, mais très précis et multilingue."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "רב-לשוני ומדויק. 25 שפות אירופיות. תומך בתרגום."
},
"cohere-int8": {
"name": "Cohere",
"description": "מודל גדול, איטי יותר, אך מדויק מאוד ורב-לשוני."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Multilingue accurato. 25 lingue europee. Supporta la traduzione."
},
"cohere-int8": {
"name": "Cohere",
"description": "Un modello grande, più lento, ma molto accurato e multilingue."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "高精度な多言語対応。25のヨーロッパ言語。翻訳対応。"
},
"cohere-int8": {
"name": "Cohere",
"description": "大型で低速ですが、非常に高精度な多言語モデル。"
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "정확한 다국어 지원. 25개 유럽 언어. 번역 지원."
},
"cohere-int8": {
"name": "Cohere",
"description": "크고 느리지만 매우 정확한 다국어 모델."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Dokładny wielojęzyczny. 25 języków europejskich. Obsługuje tłumaczenie."
},
"cohere-int8": {
"name": "Cohere",
"description": "Duży, wolniejszy, ale bardzo dokładny model wielojęzyczny."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Multilíngue preciso. 25 idiomas europeus. Suporta tradução."
},
"cohere-int8": {
"name": "Cohere",
"description": "Um modelo grande, mais lento, mas muito preciso e multilíngue."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Точная многоязычная. 25 европейских языков. Поддержка перевода."
},
"cohere-int8": {
"name": "Cohere",
"description": "Большая, медленная, но очень точная многоязычная модель."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Noggrann flerspråkig. 25 europeiska språk. Stöder översättning."
},
"cohere-int8": {
"name": "Cohere",
"description": "En stor, långsammare, men mycket noggrann flerspråkig modell."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Doğru çok dilli. 25 Avrupa dili. Çeviri desteği."
},
"cohere-int8": {
"name": "Cohere",
"description": "Büyük, daha yavaş, ancak çok doğru çok dilli bir model."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Точна багатомовна. 25 європейських мов. Підтримує переклад."
},
"cohere-int8": {
"name": "Cohere",
"description": "Велика, повільніша, але дуже точна багатомовна модель."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "Đa ngôn ngữ chính xác. 25 ngôn ngữ châu Âu. Hỗ trợ dịch thuật."
},
"cohere-int8": {
"name": "Cohere",
"description": "Mô hình lớn, chậm hơn, nhưng rất chính xác và đa ngôn ngữ."
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "準確的多語言模型。25種歐洲語言。支援翻譯。"
},
"cohere-int8": {
"name": "Cohere",
"description": "大型模型,速度較慢,但多語言辨識非常準確。"
}
},
"errors": {

View file

@ -88,6 +88,10 @@
"canary-1b-v2": {
"name": "Canary 1B v2",
"description": "准确的多语言模型。25种欧洲语言。支持翻译。"
},
"cohere-int8": {
"name": "Cohere",
"description": "大型模型,速度较慢,但多语言识别非常准确。"
}
},
"errors": {