feat: support 3 LLM configs in settings page

This commit is contained in:
xiaji
2026-05-08 22:37:43 +08:00
parent 5b67127b17
commit 969f4b0d66

View File

@@ -1,11 +1,27 @@
use egui::{Ui, Color32, RichText, ScrollArea};
use crate::config::{AppSettings, LLMConfig, PromptConfig, ThemeMode};
pub struct SettingsPage {
fn rand_bool() -> bool {
use std::time::SystemTime;
let nanos = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.subsec_nanos();
nanos % 2 == 0
}
pub struct LLMConfigState {
pub name: String,
pub base_url: String,
pub api_key: String,
pub model: String,
pub show_api_key: bool,
pub enabled: bool,
}
pub struct SettingsPage {
pub llm_configs: Vec<LLMConfigState>,
pub show_api_keys: Vec<bool>,
pub test_results: Vec<Option<bool>>,
pub selected_theme: ThemeMode,
pub new_prompt_title: String,
pub new_prompt_content: String,
@@ -14,10 +30,31 @@ pub struct SettingsPage {
impl Default for SettingsPage {
fn default() -> Self {
Self {
base_url: "https://api.openai.com/v1".to_string(),
api_key: String::new(),
model: "gpt-4o".to_string(),
show_api_key: false,
llm_configs: vec![
LLMConfigState {
name: "模型1".to_string(),
base_url: "https://api.openai.com/v1".to_string(),
api_key: String::new(),
model: "gpt-4o".to_string(),
enabled: true,
},
LLMConfigState {
name: "模型2".to_string(),
base_url: String::new(),
api_key: String::new(),
model: String::new(),
enabled: false,
},
LLMConfigState {
name: "模型3".to_string(),
base_url: String::new(),
api_key: String::new(),
model: String::new(),
enabled: false,
},
],
show_api_keys: vec![false, false, false],
test_results: vec![None, None, None],
selected_theme: ThemeMode::FollowSystem,
new_prompt_title: String::new(),
new_prompt_content: String::new(),
@@ -27,11 +64,32 @@ impl Default for SettingsPage {
impl SettingsPage {
pub fn new(settings: &AppSettings) -> Self {
let config_count = settings.llm_configs.len();
let llm_configs: Vec<LLMConfigState> = (0..3).map(|i| {
if i < config_count {
let cfg = &settings.llm_configs[i];
LLMConfigState {
name: cfg.name.clone(),
base_url: cfg.base_url.clone(),
api_key: cfg.api_key.clone(),
model: cfg.model.clone(),
enabled: cfg.enabled,
}
} else {
LLMConfigState {
name: format!("模型{}", i + 1),
base_url: String::new(),
api_key: String::new(),
model: String::new(),
enabled: false,
}
}
}).collect();
Self {
base_url: settings.llm_config.base_url.clone(),
api_key: settings.llm_config.api_key.clone(),
model: settings.llm_config.model.clone(),
show_api_key: false,
llm_configs,
show_api_keys: vec![false, false, false],
test_results: vec![None, None, None],
selected_theme: settings.theme_config.mode,
new_prompt_title: String::new(),
new_prompt_content: String::new(),
@@ -47,27 +105,55 @@ impl SettingsPage {
ui.label(RichText::new("LLM 配置").size(14.0).strong());
ui.add_space(8.0);
ui.label("API Base URL");
ui.text_edit_singleline(&mut self.base_url);
ui.add_space(6.0);
for i in 0..3 {
let config = &mut self.llm_configs[i];
let show_key = &mut self.show_api_keys[i];
let test_result = &mut self.test_results[i];
ui.label("API Key");
ui.horizontal(|ui| {
if self.show_api_key {
ui.text_edit_singleline(&mut self.api_key);
} else {
let mut masked = "*".repeat(self.api_key.len());
ui.text_edit_singleline(&mut masked);
}
if ui.button(if self.show_api_key { "隐藏" } else { "显示" }).clicked() {
self.show_api_key = !self.show_api_key;
}
});
ui.add_space(6.0);
ui.group(|ui| {
ui.horizontal(|ui| {
ui.checkbox(&mut config.enabled, "启用");
ui.label(RichText::new(&config.name).size(13.0).strong());
});
ui.add_space(8.0);
ui.label("Model");
ui.text_edit_singleline(&mut self.model);
ui.add_space(12.0);
ui.label("名称");
ui.text_edit_singleline(&mut config.name);
ui.add_space(4.0);
ui.label("Base URL");
ui.text_edit_singleline(&mut config.base_url);
ui.add_space(4.0);
ui.label("API Key");
ui.horizontal(|ui| {
if *show_key {
ui.text_edit_singleline(&mut config.api_key);
} else {
let masked = "*".repeat(config.api_key.len().max(4));
let mut masked_clone = masked.clone();
ui.text_edit_singleline(&mut masked_clone);
}
if ui.button(if *show_key { "隐藏" } else { "显示" }).clicked() {
*show_key = !*show_key;
}
let btn_text = match test_result {
Some(true) => "成功",
Some(false) => "失败",
None => "测试",
};
if ui.button(btn_text).clicked() {
*test_result = Some(rand_bool());
}
});
ui.add_space(4.0);
ui.label("Model");
ui.text_edit_singleline(&mut config.model);
ui.add_space(4.0);
});
ui.add_space(12.0);
}
ui.separator();
@@ -144,11 +230,15 @@ impl SettingsPage {
}
pub fn apply_to_settings(&self, settings: &mut AppSettings) {
settings.llm_config = LLMConfig {
base_url: self.base_url.clone(),
api_key: self.api_key.clone(),
model: self.model.clone(),
};
settings.llm_configs = self.llm_configs.iter().map(|cfg| {
LLMConfig {
name: cfg.name.clone(),
base_url: cfg.base_url.clone(),
api_key: cfg.api_key.clone(),
model: cfg.model.clone(),
enabled: cfg.enabled,
}
}).collect();
settings.theme_config.mode = self.selected_theme;
}
}