feat(config): refactor AI config into separate LLM and embedding configs

- Split AIConfig into separate LLMConfig and embedding config structs
- Update create_site.rs to use config.llm instead of config.ai
- Improve config loading comments in bootstrap manager
- Add new LLM-related environment variables with defaults
- Maintain backward compatibility with existing config loading
- Clean up unused AIConfig struct and related code

The change better organizes the AI-related configuration by separating LLM and embedding configurations, making the code more maintainable and flexible for future AI service integrations.
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-11-01 08:43:14 -03:00
parent a19ba2bef7
commit eb647530bf
7 changed files with 40 additions and 38 deletions

View file

@ -78,7 +78,7 @@ async fn create_site(
); );
info!("Asking LLM to create site."); info!("Asking LLM to create site.");
let llm_result = utils::call_llm(&full_prompt, &config.ai).await?; let llm_result = utils::call_llm(&full_prompt, &config.llm).await?;
let index_path = alias_path.join("index.html"); let index_path = alias_path.join("index.html");
fs::write(index_path, llm_result).map_err(|e| e.to_string())?; fs::write(index_path, llm_result).map_err(|e| e.to_string())?;

View file

@ -544,13 +544,14 @@ impl BootstrapManager {
let temp_path = std::env::temp_dir().join("config.csv"); let temp_path = std::env::temp_dir().join("config.csv");
std::fs::write(&temp_path, csv_content)?; std::fs::write(&temp_path, csv_content)?;
// First sync the CSV to database
config_manager.sync_gbot_config(&default_bot_id, temp_path.to_str().unwrap()) config_manager.sync_gbot_config(&default_bot_id, temp_path.to_str().unwrap())
.map_err(|e| anyhow::anyhow!("Failed to sync gbot config: {}", e))?; .map_err(|e| anyhow::anyhow!("Failed to sync gbot config: {}", e))?;
// Load config from database which now has the CSV values // Create fresh connection for final config load
let mut config_conn = establish_pg_connection()?; let mut final_conn = establish_pg_connection()?;
let config = AppConfig::from_database(&mut config_conn); let config = AppConfig::from_database(&mut final_conn);
info!("Successfully loaded config from CSV"); info!("Successfully loaded config from CSV with LLM settings");
Ok(config) Ok(config)
} }
Err(e) => { Err(e) => {

View file

@ -8,6 +8,13 @@ use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct LLMConfig {
pub url: String,
pub key: String,
pub model: String,
}
#[derive(Clone)] #[derive(Clone)]
pub struct AppConfig { pub struct AppConfig {
pub drive: DriveConfig, pub drive: DriveConfig,
@ -15,7 +22,8 @@ pub struct AppConfig {
pub database: DatabaseConfig, pub database: DatabaseConfig,
pub database_custom: DatabaseConfig, pub database_custom: DatabaseConfig,
pub email: EmailConfig, pub email: EmailConfig,
pub ai: AIConfig, pub llm: LLMConfig,
pub embedding: LLMConfig,
pub site_path: String, pub site_path: String,
pub stack_path: PathBuf, pub stack_path: PathBuf,
pub db_conn: Option<Arc<Mutex<PgConnection>>>, pub db_conn: Option<Arc<Mutex<PgConnection>>>,
@ -54,14 +62,6 @@ pub struct EmailConfig {
pub password: String, pub password: String,
} }
#[derive(Clone)]
pub struct AIConfig {
pub instance: String,
pub key: String,
pub version: String,
pub endpoint: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, QueryableByName)] #[derive(Debug, Clone, Serialize, Deserialize, QueryableByName)]
pub struct ServerConfigRow { pub struct ServerConfigRow {
#[diesel(sql_type = Text)] #[diesel(sql_type = Text)]
@ -218,13 +218,6 @@ impl AppConfig {
password: get_str("EMAIL_PASS", "pass"), password: get_str("EMAIL_PASS", "pass"),
}; };
let ai = AIConfig {
instance: get_str("AI_INSTANCE", "gpt-4"),
key: get_str("AI_KEY", ""),
version: get_str("AI_VERSION", "2023-12-01-preview"),
endpoint: get_str("AI_ENDPOINT", "https://api.openai.com"),
};
// Write drive config to .env file // Write drive config to .env file
if let Err(e) = write_drive_config_to_env(&minio) { if let Err(e) = write_drive_config_to_env(&minio) {
warn!("Failed to write drive config to .env: {}", e); warn!("Failed to write drive config to .env: {}", e);
@ -239,7 +232,16 @@ impl AppConfig {
database, database,
database_custom, database_custom,
email, email,
ai, llm: LLMConfig {
url: get_str("LLM_URL", "http://localhost:8081"),
key: get_str("LLM_KEY", ""),
model: get_str("LLM_MODEL", "gpt-4"),
},
embedding: LLMConfig {
url: get_str("EMBEDDING_URL", "http://localhost:8082"),
key: get_str("EMBEDDING_KEY", ""),
model: get_str("EMBEDDING_MODEL", "text-embedding-ada-002"),
},
site_path: get_str("SITES_ROOT", "./botserver-stack/sites"), site_path: get_str("SITES_ROOT", "./botserver-stack/sites"),
stack_path, stack_path,
db_conn: None, db_conn: None,
@ -302,15 +304,6 @@ impl AppConfig {
password: std::env::var("EMAIL_PASS").unwrap_or_else(|_| "pass".to_string()), password: std::env::var("EMAIL_PASS").unwrap_or_else(|_| "pass".to_string()),
}; };
let ai = AIConfig {
instance: std::env::var("AI_INSTANCE").unwrap_or_else(|_| "gpt-4".to_string()),
key: std::env::var("AI_KEY").unwrap_or_else(|_| "".to_string()),
version: std::env::var("AI_VERSION")
.unwrap_or_else(|_| "2023-12-01-preview".to_string()),
endpoint: std::env::var("AI_ENDPOINT")
.unwrap_or_else(|_| "https://api.openai.com".to_string()),
};
AppConfig { AppConfig {
drive: minio, drive: minio,
server: ServerConfig { server: ServerConfig {
@ -323,7 +316,16 @@ impl AppConfig {
database, database,
database_custom, database_custom,
email, email,
ai, llm: LLMConfig {
url: std::env::var("LLM_URL").unwrap_or_else(|_| "http://localhost:8081".to_string()),
key: std::env::var("LLM_KEY").unwrap_or_else(|_| "".to_string()),
model: std::env::var("LLM_MODEL").unwrap_or_else(|_| "gpt-4".to_string()),
},
embedding: LLMConfig {
url: std::env::var("EMBEDDING_URL").unwrap_or_else(|_| "http://localhost:8082".to_string()),
key: std::env::var("EMBEDDING_KEY").unwrap_or_else(|_| "".to_string()),
model: std::env::var("EMBEDDING_MODEL").unwrap_or_else(|_| "text-embedding-ada-002".to_string()),
},
site_path: std::env::var("SITES_ROOT") site_path: std::env::var("SITES_ROOT")
.unwrap_or_else(|_| "./botserver-stack/sites".to_string()), .unwrap_or_else(|_| "./botserver-stack/sites".to_string()),
stack_path: PathBuf::from(stack_path), stack_path: PathBuf::from(stack_path),

View file

@ -190,7 +190,7 @@ async fn main() -> std::io::Result<()> {
let tool_manager = Arc::new(tools::ToolManager::new()); let tool_manager = Arc::new(tools::ToolManager::new());
let llm_provider = Arc::new(crate::llm::OpenAIClient::new( let llm_provider = Arc::new(crate::llm::OpenAIClient::new(
"empty".to_string(), "empty".to_string(),
Some(cfg.ai.endpoint.clone()), Some(cfg.llm.url.clone()),
)); ));
let web_adapter = Arc::new(WebChannelAdapter::new()); let web_adapter = Arc::new(WebChannelAdapter::new());
let voice_adapter = Arc::new(VoiceAdapter::new( let voice_adapter = Arc::new(VoiceAdapter::new(

View file

@ -241,7 +241,7 @@ post_install_cmds_linux: vec![
post_install_cmds_windows: vec![], post_install_cmds_windows: vec![],
env_vars: HashMap::new(), env_vars: HashMap::new(),
data_download_list: Vec::new(), data_download_list: Vec::new(),
exec_cmd: "{{BIN_PATH}}/bin/valkey-server --port 6379 --dir {{DATA_PATH}}".to_string(), exec_cmd: "nohup {{BIN_PATH}}/bin/valkey-server --port 6379 --dir {{DATA_PATH}} > {{LOGS_PATH}}/valkey.log 2>&1 &".to_string(),
}, },
); );
} }

View file

@ -1,4 +1,3 @@
use crate::config::AIConfig;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use diesel::{Connection, PgConnection}; use diesel::{Connection, PgConnection};
use futures_util::StreamExt; use futures_util::StreamExt;
@ -175,7 +174,7 @@ pub fn parse_filter_with_offset(
pub async fn call_llm( pub async fn call_llm(
prompt: &str, prompt: &str,
_ai_config: &AIConfig, _llm_config: &crate::config::LLMConfig,
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> { ) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
Ok(format!("Generated response for: {}", prompt)) Ok(format!("Generated response for: {}", prompt))
} }

View file

@ -9,7 +9,7 @@ llm-url,http://localhost:8080/v1
llm-model,botserver-stack/data/llm/DeepSeek-R1-Distill-Qwen-1.5B-Q3_K_M.gguf llm-model,botserver-stack/data/llm/DeepSeek-R1-Distill-Qwen-1.5B-Q3_K_M.gguf
embedding-url,http://localhost:8082 embedding-url,http://localhost:8082
embedding-model-path,botserver-stack/data/llm/bge-small-en-v1.5-f32.gguf embedding-model,botserver-stack/data/llm/bge-small-en-v1.5-f32.gguf
llm-server,false llm-server,false
llm-server-path,botserver-stack/bin/llm/ llm-server-path,botserver-stack/bin/llm/

1 name value
9 embedding-model-path embedding-model botserver-stack/data/llm/bge-small-en-v1.5-f32.gguf
10 llm-server false
11 llm-server-path botserver-stack/bin/llm/
12 llm-server-model botserver-stack/data/llm/DeepSeek-R1-Distill-Qwen-1.5B-Q3_K_M.gguf
13 llm-server-host 0.0.0.0
14 llm-server-port 8080
15 llm-server-gpu-layers 35