nexus_core/app/
settings.rs1#![allow(
5 clippy::cast_possible_truncation,
6 clippy::cast_possible_wrap,
7 clippy::cast_precision_loss,
8 clippy::cast_sign_loss
9)]
10use anyhow::{Result, bail};
11
12use super::{App, OCR_ENGINES, SEARCH_PROVIDERS, VERBOSITY_LEVELS};
13
14impl App {
15 pub fn cycle_ocr_engine(&mut self) -> Result<()> {
22 let i = super::OCR_ENGINES
23 .iter()
24 .position(|&e| e == self.ocr_engine)
25 .unwrap_or(0);
26 let next = super::OCR_ENGINES[(i + 1) % super::OCR_ENGINES.len()];
27 if next == "local" {
28 self.ocr_local_install("");
29 return Ok(());
30 }
31 self.ocr_engine = next.to_string();
32 self.db.set_setting("ocr_engine", &self.ocr_engine)?;
33 Ok(())
34 }
35
36 pub fn set_setting(&mut self, key: &str, value: &str) -> Result<()> {
42 if !SETTING_KEYS.contains(&key) {
43 bail!("unknown setting: {key}");
44 }
45 if !valid_setting_value(key, value) {
46 bail!("invalid value for {key}: {value:?}");
47 }
48 let embedding_changed =
49 key == "embedding_model" && self.embedding_model.trim() != value.trim();
50 self.apply_setting(key, value);
51 if embedding_changed {
52 self.embed_rx = None;
58 self.db.clear_chunk_embeddings()?;
59 }
60 if key == "blocked_domains" {
61 std::fs::write(
64 self.space.blocked_domains_path(&self.active_space.name),
65 value,
66 )?;
67 } else {
68 self.db.set_setting(key, value)?;
69 }
70 self.refresh_toolbox();
71 if key == "embedding_model" {
72 self.start_embedding();
73 }
74 self.push_status(format!("{key} set"));
75 Ok(())
76 }
77}
78
79const SETTING_KEYS: [&str; 21] = [
82 "show_stats",
83 "show_reasoning",
84 "hide_hints",
85 "usage_range",
86 "temperature",
87 "top_p",
88 "max_tokens",
89 "memory_model",
90 "transcriber_model",
91 "ocr_model",
92 "ocr_engine",
93 "local_ocr_model",
94 "embedding_model",
95 "image_gen_model",
96 "video_gen_model",
97 "compact_threshold",
98 "searxng_url",
99 "verbosity",
100 "langsearch_key",
101 "search_provider",
102 "blocked_domains",
103];
104
105fn valid_setting_value(key: &str, value: &str) -> bool {
109 match key {
110 "show_stats" | "show_reasoning" | "hide_hints" => matches!(value, "0" | "1"),
111 "temperature" | "top_p" => value.parse::<f32>().is_ok(),
112 "max_tokens" => value.parse::<u32>().is_ok(),
113 "compact_threshold" => value.parse::<u8>().is_ok(),
114 "usage_range" => crate::db::UsageRange::CYCLE
115 .iter()
116 .any(|r| r.key() == value),
117 "ocr_engine" => OCR_ENGINES.contains(&value),
118 "verbosity" => VERBOSITY_LEVELS.contains(&value),
119 "search_provider" => SEARCH_PROVIDERS.contains(&value),
120 _ => true, }
122}