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.");
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");
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");
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())
.map_err(|e| anyhow::anyhow!("Failed to sync gbot config: {}", e))?;
// Load config from database which now has the CSV values
let mut config_conn = establish_pg_connection()?;
let config = AppConfig::from_database(&mut config_conn);
info!("Successfully loaded config from CSV");
// Create fresh connection for final config load
let mut final_conn = establish_pg_connection()?;
let config = AppConfig::from_database(&mut final_conn);
info!("Successfully loaded config from CSV with LLM settings");
Ok(config)
}
Err(e) => {

View file

@ -8,6 +8,13 @@ use std::io::Write;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct LLMConfig {
pub url: String,
pub key: String,
pub model: String,
}
#[derive(Clone)]
pub struct AppConfig {
pub drive: DriveConfig,
@ -15,7 +22,8 @@ pub struct AppConfig {
pub database: DatabaseConfig,
pub database_custom: DatabaseConfig,
pub email: EmailConfig,
pub ai: AIConfig,
pub llm: LLMConfig,
pub embedding: LLMConfig,
pub site_path: String,
pub stack_path: PathBuf,
pub db_conn: Option<Arc<Mutex<PgConnection>>>,
@ -54,14 +62,6 @@ pub struct EmailConfig {
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)]
pub struct ServerConfigRow {
#[diesel(sql_type = Text)]
@ -218,13 +218,6 @@ impl AppConfig {
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
if let Err(e) = write_drive_config_to_env(&minio) {
warn!("Failed to write drive config to .env: {}", e);
@ -239,7 +232,16 @@ impl AppConfig {
database,
database_custom,
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"),
stack_path,
db_conn: None,
@ -302,15 +304,6 @@ impl AppConfig {
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 {
drive: minio,
server: ServerConfig {
@ -323,7 +316,16 @@ impl AppConfig {
database,
database_custom,
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")
.unwrap_or_else(|_| "./botserver-stack/sites".to_string()),
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 llm_provider = Arc::new(crate::llm::OpenAIClient::new(
"empty".to_string(),
Some(cfg.ai.endpoint.clone()),
Some(cfg.llm.url.clone()),
));
let web_adapter = Arc::new(WebChannelAdapter::new());
let voice_adapter = Arc::new(VoiceAdapter::new(

View file

@ -241,7 +241,7 @@ post_install_cmds_linux: vec![
post_install_cmds_windows: vec![],
env_vars: HashMap::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(),
},
);
}
@ -841,4 +841,4 @@ post_install_cmds_linux: vec![
hasher.update(password.as_bytes());
format!("{:x}", hasher.finalize())
}
}
}

View file

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