fixes for 0.6.11: linking, ui (#579)
* static linking? * move to 0.2.1 * transcribe-rs 0.2.2 * Update Cargo.lock * remove settings which dont apply to models
This commit is contained in:
parent
738c5a82d8
commit
56b0f44e45
9 changed files with 289 additions and 621 deletions
295
src-tauri/Cargo.lock
generated
295
src-tauri/Cargo.lock
generated
|
|
@ -25,20 +25,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
|
@ -380,12 +366,6 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
|
|
@ -433,7 +413,7 @@ dependencies = [
|
|||
"bitflags 2.10.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.12.1",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
|
|
@ -697,15 +677,6 @@ dependencies = [
|
|||
"toml 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.29.2"
|
||||
|
|
@ -912,21 +883,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
|
||||
dependencies = [
|
||||
"castaway",
|
||||
"cfg-if",
|
||||
"itoa",
|
||||
"rustversion",
|
||||
"ryu",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
|
|
@ -936,19 +892,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
|
|
@ -1119,25 +1062,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
|
|
@ -1267,15 +1191,6 @@ dependencies = [
|
|||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dary_heap"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
|
|
@ -1526,12 +1441,6 @@ version = "1.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
|
|
@ -1675,15 +1584,6 @@ version = "3.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
||||
|
||||
[[package]]
|
||||
name = "esaxx-rs"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.1"
|
||||
|
|
@ -2449,7 +2349,7 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash 0.7.8",
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2850,19 +2750,6 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88"
|
||||
dependencies = [
|
||||
"console",
|
||||
"portable-atomic",
|
||||
"unicode-width",
|
||||
"unit-prefix",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.19.0"
|
||||
|
|
@ -2953,15 +2840,6 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
|
|
@ -3219,22 +3097,6 @@ dependencies = [
|
|||
"core-foundation-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
|
||||
dependencies = [
|
||||
"macro_rules_attribute-proc_macro",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute-proc_macro"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
|
|
@ -3370,28 +3232,6 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monostate"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
|
||||
dependencies = [
|
||||
"monostate-impl",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monostate-impl"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.9"
|
||||
|
|
@ -3968,28 +3808,6 @@ version = "1.70.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "6.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.3.2"
|
||||
|
|
@ -4819,37 +4637,6 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-cond"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools 0.14.0",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdev"
|
||||
version = "0.5.0-2"
|
||||
|
|
@ -5751,18 +5538,6 @@ dependencies = [
|
|||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spm_precompiled"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"nom 7.1.3",
|
||||
"serde",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
|
|
@ -6789,40 +6564,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokenizers"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"aho-corasick",
|
||||
"compact_str",
|
||||
"dary_heap",
|
||||
"derive_builder",
|
||||
"esaxx-rs",
|
||||
"getrandom 0.3.4",
|
||||
"indicatif",
|
||||
"itertools 0.14.0",
|
||||
"log",
|
||||
"macro_rules_attribute",
|
||||
"monostate",
|
||||
"onig",
|
||||
"paste",
|
||||
"rand 0.9.2",
|
||||
"rayon",
|
||||
"rayon-cond",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spm_precompiled",
|
||||
"thiserror 2.0.17",
|
||||
"unicode-normalization-alignments",
|
||||
"unicode-segmentation",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.48.0"
|
||||
|
|
@ -7056,9 +6797,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "transcribe-rs"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d8fb085c53485dfaa3f0e377c2c8f5e4affb991ddf7cb04fe32e49fc3e81bc4"
|
||||
checksum = "2a15e55d3bd4f74a474b7ff2c87ab416130223db490102c5ad32c6e2227686b0"
|
||||
dependencies = [
|
||||
"derive_builder",
|
||||
"env_logger",
|
||||
|
|
@ -7071,7 +6812,6 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.17",
|
||||
"tokenizers",
|
||||
"whisper-rs",
|
||||
]
|
||||
|
||||
|
|
@ -7195,39 +6935,12 @@ version = "1.0.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization-alignments"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de"
|
||||
dependencies = [
|
||||
"smallvec 1.15.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_categories"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "unit-prefix"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ chrono = "0.4"
|
|||
rusqlite = { version = "0.37", features = ["bundled"] }
|
||||
tar = "0.4.44"
|
||||
flate2 = "1.0"
|
||||
transcribe-rs = { version = "0.2", features = ["whisper", "parakeet", "moonshine"] }
|
||||
transcribe-rs = { version = "0.2.2", features = ["whisper", "parakeet", "moonshine"] }
|
||||
ferrous-opencc = "0.2.3"
|
||||
specta = "=2.0.0-rc.22"
|
||||
specta-typescript = "0.0.9"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import React, { useState, useRef, useEffect, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { SettingContainer } from "../ui/SettingContainer";
|
||||
import { ResetButton } from "../ui/ResetButton";
|
||||
import { useSettings } from "../../hooks/useSettings";
|
||||
import { useModels } from "../../hooks/useModels";
|
||||
import { LANGUAGES } from "../../lib/constants/languages";
|
||||
|
||||
interface LanguageSelectorProps {
|
||||
|
|
@ -12,22 +10,18 @@ interface LanguageSelectorProps {
|
|||
grouped?: boolean;
|
||||
}
|
||||
|
||||
const unsupportedModels = ["parakeet-tdt-0.6b-v2", "parakeet-tdt-0.6b-v3"];
|
||||
|
||||
export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
||||
descriptionMode = "tooltip",
|
||||
grouped = false,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSetting, updateSetting, resetSetting, isUpdating } = useSettings();
|
||||
const { currentModel, loadCurrentModel } = useModels();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const selectedLanguage = getSetting("selected_language") || "auto";
|
||||
const isUnsupported = unsupportedModels.includes(currentModel);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
|
|
@ -46,17 +40,6 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
};
|
||||
}, []);
|
||||
|
||||
// Listen for model state changes to update UI reactively
|
||||
useEffect(() => {
|
||||
const modelStateUnlisten = listen("model-state-changed", () => {
|
||||
loadCurrentModel();
|
||||
});
|
||||
|
||||
return () => {
|
||||
modelStateUnlisten.then((fn) => fn());
|
||||
};
|
||||
}, [loadCurrentModel]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && searchInputRef.current) {
|
||||
searchInputRef.current.focus();
|
||||
|
|
@ -71,10 +54,9 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
[searchQuery],
|
||||
);
|
||||
|
||||
const selectedLanguageName = isUnsupported
|
||||
? t("settings.general.language.auto")
|
||||
: LANGUAGES.find((lang) => lang.value === selectedLanguage)?.label ||
|
||||
t("settings.general.language.auto");
|
||||
const selectedLanguageName =
|
||||
LANGUAGES.find((lang) => lang.value === selectedLanguage)?.label ||
|
||||
t("settings.general.language.auto");
|
||||
|
||||
const handleLanguageSelect = async (languageCode: string) => {
|
||||
await updateSetting("selected_language", languageCode);
|
||||
|
|
@ -87,7 +69,7 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
};
|
||||
|
||||
const handleToggle = () => {
|
||||
if (isUpdating("selected_language") || isUnsupported) return;
|
||||
if (isUpdating("selected_language")) return;
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
|
|
@ -108,26 +90,21 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
return (
|
||||
<SettingContainer
|
||||
title={t("settings.general.language.title")}
|
||||
description={
|
||||
isUnsupported
|
||||
? t("settings.general.language.descriptionUnsupported")
|
||||
: t("settings.general.language.description")
|
||||
}
|
||||
description={t("settings.general.language.description")}
|
||||
descriptionMode={descriptionMode}
|
||||
grouped={grouped}
|
||||
disabled={isUnsupported}
|
||||
>
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="relative" ref={dropdownRef}>
|
||||
<button
|
||||
type="button"
|
||||
className={`px-2 py-1 text-sm font-semibold bg-mid-gray/10 border border-mid-gray/80 rounded min-w-[200px] text-left flex items-center justify-between transition-all duration-150 ${
|
||||
isUpdating("selected_language") || isUnsupported
|
||||
isUpdating("selected_language")
|
||||
? "opacity-50 cursor-not-allowed"
|
||||
: "hover:bg-logo-primary/10 cursor-pointer hover:border-logo-primary"
|
||||
}`}
|
||||
onClick={handleToggle}
|
||||
disabled={isUpdating("selected_language") || isUnsupported}
|
||||
disabled={isUpdating("selected_language")}
|
||||
>
|
||||
<span className="truncate">{selectedLanguageName}</span>
|
||||
<svg
|
||||
|
|
@ -147,7 +124,7 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
</svg>
|
||||
</button>
|
||||
|
||||
{isOpen && !isUpdating("selected_language") && !isUnsupported && (
|
||||
{isOpen && !isUpdating("selected_language") && (
|
||||
<div className="absolute top-full left-0 right-0 mt-1 bg-background border border-mid-gray/80 rounded shadow-lg z-50 max-h-60 overflow-hidden">
|
||||
{/* Search input */}
|
||||
<div className="p-2 border-b border-mid-gray/80">
|
||||
|
|
@ -191,7 +168,7 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
|||
</div>
|
||||
<ResetButton
|
||||
onClick={handleReset}
|
||||
disabled={isUpdating("selected_language") || isUnsupported}
|
||||
disabled={isUpdating("selected_language")}
|
||||
/>
|
||||
</div>
|
||||
{isUpdating("selected_language") && (
|
||||
|
|
|
|||
|
|
@ -1,66 +1,27 @@
|
|||
import React, { useEffect, useMemo } from "react";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { ToggleSwitch } from "../ui/ToggleSwitch";
|
||||
import { useSettings } from "../../hooks/useSettings";
|
||||
import { useModels } from "../../hooks/useModels";
|
||||
|
||||
interface TranslateToEnglishProps {
|
||||
descriptionMode?: "inline" | "tooltip";
|
||||
grouped?: boolean;
|
||||
}
|
||||
|
||||
const unsupportedTranslationModels = [
|
||||
"parakeet-tdt-0.6b-v2",
|
||||
"parakeet-tdt-0.6b-v3",
|
||||
"turbo",
|
||||
];
|
||||
|
||||
export const TranslateToEnglish: React.FC<TranslateToEnglishProps> = React.memo(
|
||||
({ descriptionMode = "tooltip", grouped = false }) => {
|
||||
const { t } = useTranslation();
|
||||
const { getSetting, updateSetting, isUpdating } = useSettings();
|
||||
const { currentModel, loadCurrentModel, models } = useModels();
|
||||
|
||||
const translateToEnglish = getSetting("translate_to_english") || false;
|
||||
const isDisabledTranslation =
|
||||
unsupportedTranslationModels.includes(currentModel);
|
||||
|
||||
const description = useMemo(() => {
|
||||
if (isDisabledTranslation) {
|
||||
const currentModelDisplayName = models.find(
|
||||
(model) => model.id === currentModel,
|
||||
)?.name;
|
||||
return t(
|
||||
"settings.advanced.translateToEnglish.descriptionUnsupported",
|
||||
{
|
||||
model: currentModelDisplayName,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return t("settings.advanced.translateToEnglish.description");
|
||||
}, [t, models, currentModel, isDisabledTranslation]);
|
||||
|
||||
// Listen for model state changes to update UI reactively
|
||||
useEffect(() => {
|
||||
const modelStateUnlisten = listen("model-state-changed", () => {
|
||||
loadCurrentModel();
|
||||
});
|
||||
|
||||
return () => {
|
||||
modelStateUnlisten.then((fn) => fn());
|
||||
};
|
||||
}, [loadCurrentModel]);
|
||||
|
||||
return (
|
||||
<ToggleSwitch
|
||||
checked={translateToEnglish}
|
||||
onChange={(enabled) => updateSetting("translate_to_english", enabled)}
|
||||
isUpdating={isUpdating("translate_to_english")}
|
||||
disabled={isDisabledTranslation}
|
||||
label={t("settings.advanced.translateToEnglish.label")}
|
||||
description={description}
|
||||
description={t("settings.advanced.translateToEnglish.description")}
|
||||
descriptionMode={descriptionMode}
|
||||
grouped={grouped}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,9 +9,14 @@ import { StartHidden } from "../StartHidden";
|
|||
import { AutostartToggle } from "../AutostartToggle";
|
||||
import { PasteMethodSetting } from "../PasteMethod";
|
||||
import { ClipboardHandlingSetting } from "../ClipboardHandling";
|
||||
import { useModelStore } from "../../../stores/modelStore";
|
||||
|
||||
export const AdvancedSettings: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentModel, getModelInfo } = useModelStore();
|
||||
const currentModelInfo = getModelInfo(currentModel);
|
||||
const showTranslateToEnglish =
|
||||
currentModelInfo?.engine_type === "Whisper" && currentModel !== "turbo";
|
||||
return (
|
||||
<div className="max-w-3xl w-full mx-auto space-y-6">
|
||||
<SettingsGroup title={t("settings.advanced.title")}>
|
||||
|
|
@ -20,7 +25,9 @@ export const AdvancedSettings: React.FC = () => {
|
|||
<ShowOverlay descriptionMode="tooltip" grouped={true} />
|
||||
<PasteMethodSetting descriptionMode="tooltip" grouped={true} />
|
||||
<ClipboardHandlingSetting descriptionMode="tooltip" grouped={true} />
|
||||
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
||||
{showTranslateToEnglish && (
|
||||
<TranslateToEnglish descriptionMode="tooltip" grouped={true} />
|
||||
)}
|
||||
<ModelUnloadTimeoutSetting descriptionMode="tooltip" grouped={true} />
|
||||
<CustomWords descriptionMode="tooltip" grouped />
|
||||
</SettingsGroup>
|
||||
|
|
|
|||
|
|
@ -8,16 +8,22 @@ import { OutputDeviceSelector } from "../OutputDeviceSelector";
|
|||
import { PushToTalk } from "../PushToTalk";
|
||||
import { AudioFeedback } from "../AudioFeedback";
|
||||
import { useSettings } from "../../../hooks/useSettings";
|
||||
import { useModelStore } from "../../../stores/modelStore";
|
||||
import { VolumeSlider } from "../VolumeSlider";
|
||||
|
||||
export const GeneralSettings: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { audioFeedbackEnabled } = useSettings();
|
||||
const { currentModel, getModelInfo } = useModelStore();
|
||||
const currentModelInfo = getModelInfo(currentModel);
|
||||
const showLanguageSelector = currentModelInfo?.engine_type === "Whisper";
|
||||
return (
|
||||
<div className="max-w-3xl w-full mx-auto space-y-6">
|
||||
<SettingsGroup title={t("settings.general.title")}>
|
||||
<HandyShortcut shortcutId="transcribe" grouped={true} />
|
||||
<LanguageSelector descriptionMode="tooltip" grouped={true} />
|
||||
{showLanguageSelector && (
|
||||
<LanguageSelector descriptionMode="tooltip" grouped={true} />
|
||||
)}
|
||||
<PushToTalk descriptionMode="tooltip" grouped={true} />
|
||||
</SettingsGroup>
|
||||
<SettingsGroup title={t("settings.sound.title")}>
|
||||
|
|
|
|||
|
|
@ -1,254 +0,0 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { commands, type ModelInfo } from "@/bindings";
|
||||
|
||||
interface DownloadProgress {
|
||||
model_id: string;
|
||||
downloaded: number;
|
||||
total: number;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
export const useModels = () => {
|
||||
const [models, setModels] = useState<ModelInfo[]>([]);
|
||||
const [currentModel, setCurrentModel] = useState<string>("");
|
||||
const [downloadingModels, setDownloadingModels] = useState<Set<string>>(
|
||||
new Set(),
|
||||
);
|
||||
const [extractingModels, setExtractingModels] = useState<Set<string>>(
|
||||
new Set(),
|
||||
);
|
||||
const [downloadProgress, setDownloadProgress] = useState<
|
||||
Map<string, DownloadProgress>
|
||||
>(new Map());
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [hasAnyModels, setHasAnyModels] = useState(false);
|
||||
const [isFirstRun, setIsFirstRun] = useState(false);
|
||||
|
||||
const loadModels = async () => {
|
||||
try {
|
||||
const result = await commands.getAvailableModels();
|
||||
if (result.status === "ok") {
|
||||
setModels(result.data);
|
||||
setError(null);
|
||||
} else {
|
||||
setError(`Failed to load models: ${result.error}`);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(`Failed to load models: ${err}`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const loadCurrentModel = async () => {
|
||||
try {
|
||||
const result = await commands.getCurrentModel();
|
||||
if (result.status === "ok") {
|
||||
setCurrentModel(result.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to load current model:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const checkFirstRun = async () => {
|
||||
try {
|
||||
const result = await commands.hasAnyModelsAvailable();
|
||||
if (result.status === "ok") {
|
||||
const hasModels = result.data;
|
||||
setHasAnyModels(hasModels);
|
||||
setIsFirstRun(!hasModels);
|
||||
return !hasModels;
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
console.error("Failed to check model availability:", err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const selectModel = async (modelId: string) => {
|
||||
try {
|
||||
setError(null);
|
||||
const result = await commands.setActiveModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
setCurrentModel(modelId);
|
||||
setIsFirstRun(false);
|
||||
setHasAnyModels(true);
|
||||
return true;
|
||||
} else {
|
||||
setError(`Failed to switch to model: ${result.error}`);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError(`Failed to switch to model: ${err}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const downloadModel = async (modelId: string) => {
|
||||
try {
|
||||
setError(null);
|
||||
setDownloadingModels((prev) => new Set(prev.add(modelId)));
|
||||
const result = await commands.downloadModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
return true;
|
||||
} else {
|
||||
setError(`Failed to download model: ${result.error}`);
|
||||
setDownloadingModels((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError(`Failed to download model: ${err}`);
|
||||
setDownloadingModels((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteModel = async (modelId: string) => {
|
||||
try {
|
||||
setError(null);
|
||||
const result = await commands.deleteModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
await loadModels(); // Refresh the list
|
||||
return true;
|
||||
} else {
|
||||
setError(`Failed to delete model: ${result.error}`);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError(`Failed to delete model: ${err}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const getModelInfo = (modelId: string): ModelInfo | undefined => {
|
||||
return models.find((model) => model.id === modelId);
|
||||
};
|
||||
|
||||
const isModelDownloading = (modelId: string): boolean => {
|
||||
return downloadingModels.has(modelId);
|
||||
};
|
||||
|
||||
const isModelExtracting = (modelId: string): boolean => {
|
||||
return extractingModels.has(modelId);
|
||||
};
|
||||
|
||||
const getDownloadProgress = (
|
||||
modelId: string,
|
||||
): DownloadProgress | undefined => {
|
||||
return downloadProgress.get(modelId);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadModels();
|
||||
loadCurrentModel();
|
||||
checkFirstRun();
|
||||
|
||||
// Listen for download progress
|
||||
const progressUnlisten = listen<DownloadProgress>(
|
||||
"model-download-progress",
|
||||
(event) => {
|
||||
setDownloadProgress(
|
||||
(prev) => new Map(prev.set(event.payload.model_id, event.payload)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Listen for download completion
|
||||
const completeUnlisten = listen<string>(
|
||||
"model-download-complete",
|
||||
(event) => {
|
||||
const modelId = event.payload;
|
||||
setDownloadingModels((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
setDownloadProgress((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
// Refresh models list to update download status
|
||||
loadModels();
|
||||
},
|
||||
);
|
||||
|
||||
// Listen for extraction events
|
||||
const extractionStartedUnlisten = listen<string>(
|
||||
"model-extraction-started",
|
||||
(event) => {
|
||||
const modelId = event.payload;
|
||||
setExtractingModels((prev) => new Set(prev.add(modelId)));
|
||||
},
|
||||
);
|
||||
|
||||
const extractionCompletedUnlisten = listen<string>(
|
||||
"model-extraction-completed",
|
||||
(event) => {
|
||||
const modelId = event.payload;
|
||||
setExtractingModels((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
// Refresh models list to update download status
|
||||
loadModels();
|
||||
},
|
||||
);
|
||||
|
||||
const extractionFailedUnlisten = listen<{
|
||||
model_id: string;
|
||||
error: string;
|
||||
}>("model-extraction-failed", (event) => {
|
||||
const modelId = event.payload.model_id;
|
||||
setExtractingModels((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(modelId);
|
||||
return next;
|
||||
});
|
||||
setError(`Failed to extract model: ${event.payload.error}`);
|
||||
});
|
||||
|
||||
return () => {
|
||||
progressUnlisten.then((fn) => fn());
|
||||
completeUnlisten.then((fn) => fn());
|
||||
extractionStartedUnlisten.then((fn) => fn());
|
||||
extractionCompletedUnlisten.then((fn) => fn());
|
||||
extractionFailedUnlisten.then((fn) => fn());
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
models,
|
||||
currentModel,
|
||||
loading,
|
||||
error,
|
||||
downloadingModels,
|
||||
extractingModels,
|
||||
downloadProgress,
|
||||
hasAnyModels,
|
||||
isFirstRun,
|
||||
loadModels,
|
||||
loadCurrentModel,
|
||||
checkFirstRun,
|
||||
selectModel,
|
||||
downloadModel,
|
||||
deleteModel,
|
||||
getModelInfo,
|
||||
isModelDownloading,
|
||||
isModelExtracting,
|
||||
getDownloadProgress,
|
||||
};
|
||||
};
|
||||
|
|
@ -5,6 +5,10 @@ import App from "./App";
|
|||
// Initialize i18n
|
||||
import "./i18n";
|
||||
|
||||
// Initialize model store (loads models and sets up event listeners)
|
||||
import { useModelStore } from "./stores/modelStore";
|
||||
useModelStore.getState().initialize();
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
|
|
|
|||
254
src/stores/modelStore.ts
Normal file
254
src/stores/modelStore.ts
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
import { create } from "zustand";
|
||||
import { subscribeWithSelector } from "zustand/middleware";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { commands, type ModelInfo } from "@/bindings";
|
||||
|
||||
interface DownloadProgress {
|
||||
model_id: string;
|
||||
downloaded: number;
|
||||
total: number;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
interface ModelStore {
|
||||
models: ModelInfo[];
|
||||
currentModel: string;
|
||||
downloadingModels: Set<string>;
|
||||
extractingModels: Set<string>;
|
||||
downloadProgress: Map<string, DownloadProgress>;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
hasAnyModels: boolean;
|
||||
isFirstRun: boolean;
|
||||
|
||||
// Actions
|
||||
initialize: () => Promise<void>;
|
||||
loadModels: () => Promise<void>;
|
||||
loadCurrentModel: () => Promise<void>;
|
||||
checkFirstRun: () => Promise<boolean>;
|
||||
selectModel: (modelId: string) => Promise<boolean>;
|
||||
downloadModel: (modelId: string) => Promise<boolean>;
|
||||
deleteModel: (modelId: string) => Promise<boolean>;
|
||||
|
||||
// Getters
|
||||
getModelInfo: (modelId: string) => ModelInfo | undefined;
|
||||
isModelDownloading: (modelId: string) => boolean;
|
||||
isModelExtracting: (modelId: string) => boolean;
|
||||
getDownloadProgress: (modelId: string) => DownloadProgress | undefined;
|
||||
|
||||
// Internal setters
|
||||
setModels: (models: ModelInfo[]) => void;
|
||||
setCurrentModel: (model: string) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
setError: (error: string | null) => void;
|
||||
setHasAnyModels: (hasAny: boolean) => void;
|
||||
setIsFirstRun: (isFirst: boolean) => void;
|
||||
addDownloadingModel: (modelId: string) => void;
|
||||
removeDownloadingModel: (modelId: string) => void;
|
||||
addExtractingModel: (modelId: string) => void;
|
||||
removeExtractingModel: (modelId: string) => void;
|
||||
setDownloadProgress: (modelId: string, progress: DownloadProgress) => void;
|
||||
removeDownloadProgress: (modelId: string) => void;
|
||||
}
|
||||
|
||||
export const useModelStore = create<ModelStore>()(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
models: [],
|
||||
currentModel: "",
|
||||
downloadingModels: new Set(),
|
||||
extractingModels: new Set(),
|
||||
downloadProgress: new Map(),
|
||||
loading: true,
|
||||
error: null,
|
||||
hasAnyModels: false,
|
||||
isFirstRun: false,
|
||||
|
||||
// Internal setters
|
||||
setModels: (models) => set({ models }),
|
||||
setCurrentModel: (currentModel) => set({ currentModel }),
|
||||
setLoading: (loading) => set({ loading }),
|
||||
setError: (error) => set({ error }),
|
||||
setHasAnyModels: (hasAnyModels) => set({ hasAnyModels }),
|
||||
setIsFirstRun: (isFirstRun) => set({ isFirstRun }),
|
||||
addDownloadingModel: (modelId) =>
|
||||
set((state) => ({
|
||||
downloadingModels: new Set(state.downloadingModels).add(modelId),
|
||||
})),
|
||||
removeDownloadingModel: (modelId) =>
|
||||
set((state) => {
|
||||
const next = new Set(state.downloadingModels);
|
||||
next.delete(modelId);
|
||||
return { downloadingModels: next };
|
||||
}),
|
||||
addExtractingModel: (modelId) =>
|
||||
set((state) => ({
|
||||
extractingModels: new Set(state.extractingModels).add(modelId),
|
||||
})),
|
||||
removeExtractingModel: (modelId) =>
|
||||
set((state) => {
|
||||
const next = new Set(state.extractingModels);
|
||||
next.delete(modelId);
|
||||
return { extractingModels: next };
|
||||
}),
|
||||
setDownloadProgress: (modelId, progress) =>
|
||||
set((state) => ({
|
||||
downloadProgress: new Map(state.downloadProgress).set(
|
||||
modelId,
|
||||
progress,
|
||||
),
|
||||
})),
|
||||
removeDownloadProgress: (modelId) =>
|
||||
set((state) => {
|
||||
const next = new Map(state.downloadProgress);
|
||||
next.delete(modelId);
|
||||
return { downloadProgress: next };
|
||||
}),
|
||||
|
||||
// Getters
|
||||
getModelInfo: (modelId) =>
|
||||
get().models.find((model) => model.id === modelId),
|
||||
isModelDownloading: (modelId) => get().downloadingModels.has(modelId),
|
||||
isModelExtracting: (modelId) => get().extractingModels.has(modelId),
|
||||
getDownloadProgress: (modelId) => get().downloadProgress.get(modelId),
|
||||
|
||||
// Actions
|
||||
loadModels: async () => {
|
||||
try {
|
||||
const result = await commands.getAvailableModels();
|
||||
if (result.status === "ok") {
|
||||
set({ models: result.data, error: null });
|
||||
} else {
|
||||
set({ error: `Failed to load models: ${result.error}` });
|
||||
}
|
||||
} catch (err) {
|
||||
set({ error: `Failed to load models: ${err}` });
|
||||
} finally {
|
||||
set({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
loadCurrentModel: async () => {
|
||||
try {
|
||||
const result = await commands.getCurrentModel();
|
||||
if (result.status === "ok") {
|
||||
set({ currentModel: result.data });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to load current model:", err);
|
||||
}
|
||||
},
|
||||
|
||||
checkFirstRun: async () => {
|
||||
try {
|
||||
const result = await commands.hasAnyModelsAvailable();
|
||||
if (result.status === "ok") {
|
||||
const hasModels = result.data;
|
||||
set({ hasAnyModels: hasModels, isFirstRun: !hasModels });
|
||||
return !hasModels;
|
||||
}
|
||||
return false;
|
||||
} catch (err) {
|
||||
console.error("Failed to check model availability:", err);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
selectModel: async (modelId) => {
|
||||
try {
|
||||
set({ error: null });
|
||||
const result = await commands.setActiveModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
set({ currentModel: modelId, isFirstRun: false, hasAnyModels: true });
|
||||
return true;
|
||||
} else {
|
||||
set({ error: `Failed to switch to model: ${result.error}` });
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
set({ error: `Failed to switch to model: ${err}` });
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
downloadModel: async (modelId) => {
|
||||
const { addDownloadingModel, removeDownloadingModel } = get();
|
||||
try {
|
||||
set({ error: null });
|
||||
addDownloadingModel(modelId);
|
||||
const result = await commands.downloadModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
return true;
|
||||
} else {
|
||||
set({ error: `Failed to download model: ${result.error}` });
|
||||
removeDownloadingModel(modelId);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
set({ error: `Failed to download model: ${err}` });
|
||||
removeDownloadingModel(modelId);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
deleteModel: async (modelId) => {
|
||||
const { loadModels } = get();
|
||||
try {
|
||||
set({ error: null });
|
||||
const result = await commands.deleteModel(modelId);
|
||||
if (result.status === "ok") {
|
||||
await loadModels();
|
||||
return true;
|
||||
} else {
|
||||
set({ error: `Failed to delete model: ${result.error}` });
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
set({ error: `Failed to delete model: ${err}` });
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
initialize: async () => {
|
||||
const { loadModels, loadCurrentModel, checkFirstRun } = get();
|
||||
await Promise.all([loadModels(), loadCurrentModel(), checkFirstRun()]);
|
||||
},
|
||||
})),
|
||||
);
|
||||
|
||||
// Set up event listeners at module load
|
||||
listen("model-state-changed", () => {
|
||||
useModelStore.getState().loadCurrentModel();
|
||||
});
|
||||
|
||||
listen<DownloadProgress>("model-download-progress", (event) => {
|
||||
useModelStore
|
||||
.getState()
|
||||
.setDownloadProgress(event.payload.model_id, event.payload);
|
||||
});
|
||||
|
||||
listen<string>("model-download-complete", (event) => {
|
||||
const modelId = event.payload;
|
||||
const state = useModelStore.getState();
|
||||
state.removeDownloadingModel(modelId);
|
||||
state.removeDownloadProgress(modelId);
|
||||
state.loadModels();
|
||||
});
|
||||
|
||||
listen<string>("model-extraction-started", (event) => {
|
||||
useModelStore.getState().addExtractingModel(event.payload);
|
||||
});
|
||||
|
||||
listen<string>("model-extraction-completed", (event) => {
|
||||
const state = useModelStore.getState();
|
||||
state.removeExtractingModel(event.payload);
|
||||
state.loadModels();
|
||||
});
|
||||
|
||||
listen<{ model_id: string; error: string }>(
|
||||
"model-extraction-failed",
|
||||
(event) => {
|
||||
const state = useModelStore.getState();
|
||||
state.removeExtractingModel(event.payload.model_id);
|
||||
state.setError(`Failed to extract model: ${event.payload.error}`);
|
||||
},
|
||||
);
|
||||
Loading…
Reference in a new issue