From 663864cb78fc327f3569ef3eb0b69af3d6062c5f Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Wed, 29 Oct 2025 09:54:39 -0300 Subject: [PATCH] refactor(config): remove unused S3 bucket configuration and setup logic Eliminates the `s3_bucket` field from `AppConfig` and deletes related initialization code in `main.rs`. This simplifies configuration management since S3 bucket handling is no longer required or used in the application. --- add-req.sh | 13 ++- src/basic/keywords/get.rs | 2 +- src/bootstrap/mod.rs | 92 ++++++++++++++---- src/config/mod.rs | 9 +- src/main.rs | 30 +----- .../annoucements.gbot/config.csv | 4 + .../announcements.gbdialog/change-subject.bas | 9 ++ .../announcements.gbdialog/start.bas | 18 +++- .../announcements.gbdialog/update-summary.bas | 8 +- .../announcements.gbkb/auxiliom/auxiliom.pdf | Bin 0 -> 14715 bytes .../announcements.gbkb/news/news.pdf | Bin 0 -> 19166 bytes .../announcements.gbkb/toolbix/toolbix.pdf | Bin 0 -> 14947 bytes .../announcements.gbkb/weekly/default.pdf | Bin 16894 -> 0 bytes .../default.gbai/default.gbot/config.csv | 6 +- 14 files changed, 120 insertions(+), 71 deletions(-) create mode 100644 templates/announcements.gbai/annoucements.gbot/config.csv create mode 100644 templates/announcements.gbai/announcements.gbdialog/change-subject.bas create mode 100644 templates/announcements.gbai/announcements.gbkb/auxiliom/auxiliom.pdf create mode 100644 templates/announcements.gbai/announcements.gbkb/news/news.pdf create mode 100644 templates/announcements.gbai/announcements.gbkb/toolbix/toolbix.pdf delete mode 100644 templates/announcements.gbai/announcements.gbkb/weekly/default.pdf diff --git a/add-req.sh b/add-req.sh index 7b50bef5..0fce6738 100755 --- a/add-req.sh +++ b/add-req.sh @@ -20,25 +20,24 @@ done dirs=( # "auth" - "automation" - "basic" + # "automation" + # "basic" # "bot" "bootstrap" - # "package_manager" + "package_manager" # "channels" # "config" # "context" # "email" - # "file" + "file" # "llm" "drive_monitor" # "llm_legacy" # "org" # "session" - "file" - "kb" + #"kb" "shared" - "tests" + #"tests" # "tools" # "web_automation" # "whatsapp" diff --git a/src/basic/keywords/get.rs b/src/basic/keywords/get.rs index 089c75f7..aa2ab44b 100644 --- a/src/basic/keywords/get.rs +++ b/src/basic/keywords/get.rs @@ -175,7 +175,7 @@ pub async fn get_from_bucket( "App configuration missing".into() })?; - let org_prefix = &cfg.minio.org_prefix; + let org_prefix = &cfg.drive.org_prefix; if org_prefix.contains("..") || org_prefix.contains('/') || org_prefix.contains('\\') { error!("Invalid org_prefix: {}", org_prefix); diff --git a/src/bootstrap/mod.rs b/src/bootstrap/mod.rs index 66d9b243..6988f638 100644 --- a/src/bootstrap/mod.rs +++ b/src/bootstrap/mod.rs @@ -2,11 +2,10 @@ use crate::config::AppConfig; use crate::package_manager::{InstallMode, PackageManager}; use anyhow::Result; use diesel::connection::SimpleConnection; -use diesel::{Connection, QueryableByName}; use diesel::RunQueryDsl; +use diesel::{Connection, QueryableByName}; use dotenvy::dotenv; -use log::{error, info}; -use opendal::services::S3; +use log::{error, info, trace}; use opendal::Operator; use rand::distr::Alphanumeric; use rand::Rng; @@ -29,6 +28,7 @@ pub struct ComponentInfo { pub struct BootstrapManager { pub install_mode: InstallMode, pub tenant: Option, + pub s3_operator: Operator, } impl BootstrapManager { @@ -37,9 +37,12 @@ impl BootstrapManager { "Initializing BootstrapManager with mode {:?} and tenant {:?}", install_mode, tenant ); + let config = AppConfig::from_env(); + let s3_operator = Self::create_s3_operator(&config); Self { install_mode, tenant, + s3_operator, } } @@ -289,9 +292,21 @@ impl BootstrapManager { } } + self.s3_operator = Self::create_s3_operator(&config); Ok(config) } + fn create_s3_operator(config: &AppConfig) -> Operator { + use opendal::Scheme; + use std::collections::HashMap; + let mut map = HashMap::new(); + map.insert("endpoint".to_string(), config.drive.server.clone()); + map.insert("access_key_id".to_string(), config.drive.access_key.clone()); + map.insert("secret_access_key".to_string(), config.drive.secret_key.clone()); + trace!("Creating S3 operator with endpoint {}", config.drive.server); + Operator::via_iter(Scheme::S3, map).expect("Failed to initialize S3 operator") + } + fn generate_secure_password(&self, length: usize) -> String { let mut rng = rand::rng(); std::iter::repeat_with(|| rng.sample(Alphanumeric) as char) @@ -307,7 +322,7 @@ impl BootstrapManager { } fn update_bot_config(&self, bot_id: &uuid::Uuid, component: &str) -> Result<()> { - use diesel::sql_types::{Uuid as SqlUuid, Text}; + use diesel::sql_types::{Text, Uuid as SqlUuid}; let database_url = std::env::var("DATABASE_URL") .unwrap_or_else(|_| "postgres://gbuser:@localhost:5432/botserver".to_string()); let mut conn = diesel::pg::PgConnection::establish(&database_url)?; @@ -321,7 +336,7 @@ impl BootstrapManager { "INSERT INTO bot_configuration (id, bot_id, config_key, config_value, config_type) VALUES ($1, $2, $3, $4, 'string') ON CONFLICT (config_key) - DO UPDATE SET config_value = EXCLUDED.config_value, updated_at = NOW()" + DO UPDATE SET config_value = EXCLUDED.config_value, updated_at = NOW()", ) .bind::(new_id) .bind::(bot_id) @@ -332,39 +347,53 @@ impl BootstrapManager { Ok(()) } - pub async fn upload_templates_to_minio(&self, config: &AppConfig) -> Result<()> { + pub async fn upload_templates_to_drive(&self, config: &AppConfig) -> Result<()> { let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| config.database_url()); let mut conn = diesel::PgConnection::establish(&database_url)?; self.create_bots_from_templates(&mut conn)?; - - let client = Operator::new( - S3::default() - .root("/") - .endpoint(&config.minio.server) - .access_key_id(&config.minio.access_key) - .secret_access_key(&config.minio.secret_key), - )? - .finish(); - let templates_dir = Path::new("templates"); if !templates_dir.exists() { return Ok(()); } - + let operator = &self.s3_operator; for entry in std::fs::read_dir(templates_dir)? { + let bot_name = templates_dir + .read_dir()? + .filter_map(|e| e.ok()) + .find(|e| { + e.path().is_dir() + && e.path() + .file_name() + .unwrap() + .to_string_lossy() + .ends_with(".gbai") + }) + .map(|e| { + let name = e.path().file_name().unwrap().to_string_lossy().to_string(); + name + }) + .unwrap_or_else(|| "default".to_string()); let entry = entry?; let path = entry.path(); - if path.is_dir() && path.extension().map(|e| e == "gbai").unwrap_or(false) { + if path.is_dir() + && path + .file_name() + .unwrap() + .to_string_lossy() + .ends_with(".gbai") + { let bot_name = path.file_name().unwrap().to_string_lossy().to_string(); - - self.upload_directory_recursive(&client, &path, &bot_name, "") + let bucket = bot_name.clone(); + info!("Uploading template {} to Drive bucket {}", bot_name, bucket); + self.upload_directory_recursive(&operator, &path, &bucket, &bot_name) .await?; + info!("Uploaded template {} to Drive bucket {}", bot_name, bucket); } } - Ok(()) } + fn create_bots_from_templates(&self, conn: &mut diesel::PgConnection) -> Result<()> { use crate::shared::models::schema::bots; use diesel::prelude::*; @@ -425,6 +454,16 @@ impl BootstrapManager { prefix: &'a str, ) -> std::pin::Pin> + 'a>> { Box::pin(async move { + trace!("Checking bucket existence: {}", bucket); + if client.stat(bucket).await.is_err() { + info!("Bucket {} not found, creating it", bucket); + trace!("Creating bucket: {}", bucket); + client.create_dir(bucket).await?; + trace!("Bucket {} created successfully", bucket); + } else { + trace!("Bucket {} already exists", bucket); + } + trace!("Starting upload from local path: {}", local_path.display()); for entry in std::fs::read_dir(local_path)? { let entry = entry?; let path = entry.path(); @@ -443,7 +482,18 @@ impl BootstrapManager { key ); let content = std::fs::read(&path)?; + trace!( + "Writing file {} to bucket {} with key {}", + path.display(), + bucket, + key + ); client.write(&key, content).await?; + trace!( + "Successfully wrote file {} to bucket {}", + path.display(), + bucket + ); } else if path.is_dir() { self.upload_directory_recursive(client, &path, bucket, &key) .await?; diff --git a/src/config/mod.rs b/src/config/mod.rs index ebcf621a..f0f75a58 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -8,14 +8,13 @@ use std::sync::{Arc, Mutex}; #[derive(Clone)] pub struct AppConfig { - pub minio: DriveConfig, + pub drive: DriveConfig, pub server: ServerConfig, pub database: DatabaseConfig, pub database_custom: DatabaseConfig, pub email: EmailConfig, pub ai: AIConfig, pub site_path: String, - pub s3_bucket: String, pub stack_path: PathBuf, pub db_conn: Option>>, } @@ -218,7 +217,7 @@ impl AppConfig { }; AppConfig { - minio, + drive: minio, server: ServerConfig { host: get_str("SERVER_HOST", "127.0.0.1"), port: get_u16("SERVER_PORT", 8080), @@ -227,7 +226,6 @@ impl AppConfig { database_custom, email, ai, - s3_bucket: get_str("DRIVE_BUCKET", "default"), site_path: get_str("SITES_ROOT", "./botserver-stack/sites"), stack_path, db_conn: None, @@ -300,7 +298,7 @@ impl AppConfig { }; AppConfig { - minio, + drive: minio, server: ServerConfig { host: std::env::var("SERVER_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()), port: std::env::var("SERVER_PORT") @@ -312,7 +310,6 @@ impl AppConfig { database_custom, email, ai, - s3_bucket: std::env::var("DRIVE_BUCKET").unwrap_or_else(|_| "default".to_string()), site_path: std::env::var("SITES_ROOT") .unwrap_or_else(|_| "./botserver-stack/sites".to_string()), stack_path: PathBuf::from(stack_path), diff --git a/src/main.rs b/src/main.rs index 1849f04f..fddf2d36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -140,7 +140,7 @@ async fn main() -> std::io::Result<()> { let _ = bootstrap.start_all(); - if let Err(e) = bootstrap.upload_templates_to_minio(&cfg).await { + if let Err(e) = bootstrap.upload_templates_to_drive(&cfg).await { log::warn!("Failed to upload templates to MinIO: {}", e); } @@ -193,32 +193,8 @@ async fn main() -> std::io::Result<()> { )); let tool_api = Arc::new(tools::ToolApi::new()); - use opendal::services::S3; - use opendal::Operator; - use opendal::ErrorKind; - async fn ensure_bucket_exists(cfg: &AppConfig) { - let builder = S3::default() - .endpoint(&cfg.minio.server) - .access_key_id(&cfg.minio.access_key) - .secret_access_key(&cfg.minio.secret_key) - .bucket(&cfg.s3_bucket) - .root("/"); - let op = Operator::new(builder).unwrap().finish(); - match op.stat("/").await { - Ok(_) => info!("Bucket {} exists", cfg.s3_bucket), - Err(e) if e.kind() == ErrorKind::NotFound => { - if let Err(err) = op.create_dir("/").await { - info!("Created bucket {}: {:?}", cfg.s3_bucket, err); - } - } - Err(e) => info!("Bucket check failed: {:?}", e), - } - } - - ensure_bucket_exists(&config).await; - - let drive = init_drive(&config.minio) + let drive = init_drive(&config.drive) .await .expect("Failed to initialize Drive"); @@ -279,7 +255,7 @@ async fn main() -> std::io::Result<()> { let drive_state = app_state.clone(); let bot_guid = std::env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string()); - let bucket_name = format!("{}{}.gbai", cfg.minio.org_prefix, bot_guid); + let bucket_name = format!("{}{}.gbai", cfg.drive.org_prefix, bot_guid); let drive_monitor = Arc::new(DriveMonitor::new(drive_state, bucket_name)); let _drive_handle = drive_monitor.spawn(); diff --git a/templates/announcements.gbai/annoucements.gbot/config.csv b/templates/announcements.gbai/annoucements.gbot/config.csv new file mode 100644 index 00000000..d639a67e --- /dev/null +++ b/templates/announcements.gbai/annoucements.gbot/config.csv @@ -0,0 +1,4 @@ +name,value +prompt-compact, 10 +prompt-cache,true +prompt-fixed-kb,geral diff --git a/templates/announcements.gbai/announcements.gbdialog/change-subject.bas b/templates/announcements.gbai/announcements.gbdialog/change-subject.bas new file mode 100644 index 00000000..e2ffefa5 --- /dev/null +++ b/templates/announcements.gbai/announcements.gbdialog/change-subject.bas @@ -0,0 +1,9 @@ +PARAM subject as string +DESCRIPTION "Chamado quando alguém quer mudar o assunto da conversa." + +kbname = LLM "Devolva uma única palavra circular, comunicado ou geral de acordo com a seguinte frase:" + subject + +ADD_KB kbname + + +TALK "You have chosen to change the subject to " + subject + "." \ No newline at end of file diff --git a/templates/announcements.gbai/announcements.gbdialog/start.bas b/templates/announcements.gbai/announcements.gbdialog/start.bas index 7a5f9df5..16be13d8 100644 --- a/templates/announcements.gbai/announcements.gbdialog/start.bas +++ b/templates/announcements.gbai/announcements.gbdialog/start.bas @@ -1,9 +1,17 @@ -LET resume = GET_BOT_MEMORY("resume") +LET resume1 = GET_BOT_MEMORY("general") +LET resume2 = GET_BOT_MEMORY("auxiliom") +LET resume3 = GET_BOT_MEMORY("toolbix") -IF resume <> "" THEN - TALK resume -END IF +SET_CONTEXT "general", resume1 +SET_CONTEXT "auxiliom", resume2 +SET_CONTEXT "toolbix", resume3 + + +ADD_SUGGESTION "general", "Show me the weekly announcements" +ADD_SUGGESTION "auxiliom", "Will Auxiliom help me with what?" +ADD_SUGGESTION "auxiliom", "What does Auxiliom do?" +ADD_SUGGESTION "toolbix", "Show me Toolbix features" +ADD_SUGGESTION "toolbix", "How can Toolbix help my business?" -ADD_KB "weekly" TALK "You can ask me about any of the announcements or circulars." diff --git a/templates/announcements.gbai/announcements.gbdialog/update-summary.bas b/templates/announcements.gbai/announcements.gbdialog/update-summary.bas index 8a736cf7..d164e53a 100644 --- a/templates/announcements.gbai/announcements.gbdialog/update-summary.bas +++ b/templates/announcements.gbai/announcements.gbdialog/update-summary.bas @@ -1,5 +1,11 @@ -let text = GET "default.gbdrive/default.pdf" +let text = GET "announcements.gbkb/news/news.pdf" let resume = LLM "Resume this document, in a table (DO NOT THINK) no_think: " + text SET_BOT_MEMORY "resume", resume + +let text1 = GET "announcements.gbkb/auxiliom/auxiliom.pdf" +SET_BOT_MEMORY "auxiliom", text1 + +let text2 = GET "announcements.gbkb/toolbix/toolbix.pdf" +SET_BOT_MEMORY "toolbix", text2 \ No newline at end of file diff --git a/templates/announcements.gbai/announcements.gbkb/auxiliom/auxiliom.pdf b/templates/announcements.gbai/announcements.gbkb/auxiliom/auxiliom.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0097331fecfa449199e9440fa3732ed60f0f0918 GIT binary patch literal 14715 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 literal 0 HcmV?d00001 diff --git a/templates/announcements.gbai/announcements.gbkb/toolbix/toolbix.pdf b/templates/announcements.gbai/announcements.gbkb/toolbix/toolbix.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eb2e7c34cb76a35361186a5bb4158703db2c8cae GIT binary patch literal 14947 zcmeHu2T)Vnx3`LbfPjF46(YR|se}aSC4w~Ry@t>Ukc5taNR!@_B7z8_R7DU$I*1@3 zB1&(HfOHU%rrtcmOXzyRV-hxw8ju;p=Q?$w(Km}J8I;0*Wn`c(wh zcTg>hhORVfb!z6Fa_GV5Di7w=--ms^&SCqCBXnXQ@Y2D%NFJ+R9lQLeUo#gITr!_y zVK4`=v6>8NCcl8k+dbt~P0Ki!`bz(M`%@{M&flHo)Gwd**-Bj{TD2D{6eecqy=sAtqO;8!U&Pc(#xZh&dUd_`1_A*l1U6VIbzHs&pakjr! z)W}pq=oL&Ytt)p^@OIy#+d6>WoN$J*uaG^;RC=`DQ74S8nF zZL;4tyKLV!RziFiJjRpllfdlz-TP+xQyBfE6kBzJ^?_uAwHwdM)>{b7cXI~D( za+j>ip?d9Vf$n{zxIHuxkNMAY;#52Y&${`&d`LvuOQ>DXZ9&{9$8$_`dGNln8??@S zn5dlVE@_|mI_6HQL$~UkSE)9`QHpDiKC^o%J-FVnn%Q~SWn*nB?&=<(zScvL_36+X&ktS-P+q5MJv8ErsZ>MhBcx{7NC0RI3uH((c>3RLIi( zy7@zLafj(vM(NoYf7UOC5X^^V#@;)$OK|0Kem!GL&5{w#anjYt?Gk30b=8~~40TPj zsh)ie@W1kcMq)cBvqtv7<=cHX=8HaMmUeBu=(}+p6;=J>i(k~X$T4lx1$-FksL9l51CNUAn=go`zIH{t-1Q=6fVG+MnGaF>AWRQs>q4X6qfF zK#@0v&c*V5>J1!CIiIPg&zmS-&|Zz_Lc-1#Jl`KAdn1RG(DhjFt>+a|wc#BmQ?*Qd zub~2+LxYWJ#NC1992nyjK9Z-L+MRc3y=&p`XLEu(nOXXDY78jiTCLr^R|f^L2ivC` zD%(IDrtV&L)moHyoApOt)2HVqzML>|=ut`SzYsI6Ww6ej;3qwDT`6V%UeSVCv2*T~ zI~xvM5BVP3R=M9kd+hb?$FDc8aEDU}DeH2aYQAvr^_CgKg4*rZ>9X`O$D!71Iv3em zmd2CB&Ls+#l_Y3>YJ6#ZoJ+9f2;uGx`Gpx7@vG-4Zwl9-paqE^a@46%Zilw(1I?ai z&0gwoREM<-n3cw*>Ihy}o^bRXUi%PPJr)Gzd?U5lDNn&(yar4BE_ zyxTzny0NF!_OZS3fg0NP7BSU;n9O)OAf@!C!o>}yWnLIt_#Jm~It=!`3!UaVdpvSa|#Dm6KYbFM*4YfQfjNYjwdL^l;9<= z&p7nnV2aDnH%mY@vhCSJH={m!;@k^?`N>8(^{m53#8a9(9}C6n>38QZ1`Vct>Ta!9 zfbrQ@X+3;=QN60Su!@TU`|MKoQwvbI+oPl4$O$ETD_E+Ku-Y_&rO(uoo#0yJRUBNG z?ltq8®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 literal 0 HcmV?d00001 diff --git a/templates/announcements.gbai/announcements.gbkb/weekly/default.pdf b/templates/announcements.gbai/announcements.gbkb/weekly/default.pdf deleted file mode 100644 index f38959e6d263c2939a11035ba06768ee97cf86f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16894 zcmeHu2T)Ymv$vus3?L{72na(C0y8kc0FoqUBdh&t=g)uzS>)L=APTPPj{d0K4+?ar!V7uNofu)PAGt}Be$ce zqoyMRzzqZg5oWdkAt8_=%)ts}4TPX6Y9MJFI11(jl7^e2V3II%gau4Q1b{?2!A$J| zZmG_yN_GKa_|3y*z4e()IYZ&VOWxvmo;qxY<%hs(eGlD2oU<>3UU2;c(t8In2`j?> ztS<|Clbt<9he4E8!OC72u<}_5ShB0eE;j()9%%~Azm&os=%cPZc`@)_ZE`xRapz)* z{g{#<>l-6-^=mVd|Lu zclTo5a0E{hX+Ez6g=@Lr4scfvYztL2-IhR>odz+ z&WJV<6+*Mb&b=M=v2O(oiU+gmY+Bp%He2mjT?x0nzfD-S?%^0m`i3b0U=9{P{f6#g zTn)f@7}J4(xiD|P)1dzm2mb#i4nO0>1?1x4=i&J^DytrzUc{62izk-SAcY#~7t}R@ z#n;=LEKV3xOsMyO@aab{v1VV>T~^THb}`d$kEdl=TAmY&v6Gij-_Nec9UOxvTT%*) z7{#nzsby@Q9aNHluJGCP1ucvXHqYihP)~Ll*I7Ueg@-H3oxYzxL-Y&`2)uolx+Ax95bza3YqC8Zdqb;MSKI8%4cY;p9i?pwp>x97GNSf0 zCP}2nWLwKZXy=YGuyaHvq_P4;{lxzH>5IrH#^Gi1{!^ln*y)0o=dcf;4NArN__41* z>0ULCPwJOK)2#=^5F}q*&3xXN9M)I}PY#)U!~YbRwPEr#GE)7t7H2e)ftdaoc|GDv zutVJLt0lJ=N1unZ%SFX-JV{I+`HaEZ^7XbL>;-CeRSiPTw5@HuDFcC|MT15f2Fr;u z=RS2BG9htQg<8b)a%1bMVGrX;Vr6iX+>N&kA6n{JiJbVb25NZ=i>K2Syt=;6SFd~T zvRuevtZKlD(OY`adxfaLUcP<&Ti?P>GZ?LiK;u%qXE98Z&EhMjPLIEir|ODZM9ulW z@JeYSc(Woy&W5{x-TIZ`%1x>x`T+Z;h5L#ZMLcXOp;u3@ov-3`eKgv^ari1j z(LE+tBT~hMBL{4owuY}XCw%C!y1Pm5S*`?nv!&uAje@jFlzfUkT0y*`;Ew9pyCL*) zE$f?LFR}Ibj;aof^qGw*!nCCWJZ}7QDB%@nQ_iCXh|CmkhG|yoso7mQ5q8u5kZlj0 z{CILm2ACJ3J%!B>i5gObnL;Qny?dk~5(ZGHN_Dd5(ZSk%pCn322kwKSf!j%mwy|5R zhZExgA%jqRJXdFzD#SFE?QB(rbH}MO$KcES?rL9NvyLZ4+9d|6tzUy+&Tlm1Zno@q zg^|W{><+j#K4xcH(1|J=9=GAOz1hPp))&YlnLGwhG66^nE2Ue9l^IyGZP^{hLEZhL ztB7uneO@N@(9>h-C04?_PTNdmJWA!rz(EJw;eDE|$U3Bk1uCX1%4HQ2KdqLIbi7hy zzuo>RT3SU%)<-3MN)7IZ3+ zO2Rc`VZyI)b-d_Du2k09bX}IHIvJ}fv{C1Yzh=K}Ym2IzH#I(KK=~F#XZPv}TIel~I!kl+K4sT>Z zzwi?!n=+oQAdbodc%2|)t|qKWhWwlGJ!c`BCQ-5*n!qjY^J7Wd{G@7|sj<~~P8lM5 zVG-&>oR@pOZifQ{Q_7KTp54s&L3{V>m5&Aa6|($H#9=|p z@xdz5S^N4c&75JR-PP#?AK#5FQp3djV#*YVSp&LOnXZ;#tBHG-e*y^Q^C)fX;i^83 zsYe9zgjgBE=f)SRAFG)QPw&(jCig4ywFN~yDx*@+H)+3gY@bfF)bh#R5VTvz*;JPE z-u+5qb+nk9*~R4sBck1$ds*R^;~uHWLX+x_9Y&Bzig&Zb=UkZC5x5l4UZqPO zl@1BVf43S+Iu6D{N>6EHO)wF5rp;yN|RK)zCvb$GqmBuep;H#Ej zd=Z(oBViLox0uff&Ck8RPv67;&3EM)m^ALexwZ(&kY7Oeu!)-7kYjao(V3yD0-EWzeM} zBaewmZS6SSd1vS&nh#?s&XsKqOVx@8^t(9;OKDd5KB&`?!`ID@pMBaXot>SpZAbcy z3GNcOT75!39M2hB#tSiDd-#cNn+U#guOcP!KtS1QVmeGCu%`XKjyc4M{8YdFq-ih{ zFOXn@SjzDk4pZ185SH5Iqp9m*na^=9&!~{ydx1ko5@MfA-7g-s`22Z8>=iMa@`fSRQn27KX@jUe0e)G7k4rNd=1OL zu{&^%$Y{l@!M8ZaaTduKzD5Zl*2;(smRaoY63L)HxW4O_Z}Fx7a+J>lF#qVWzaVV%RaO;uz02O5!V?`gAx zqo^f?6}M_De|BTnr4uTBg7@Xx6wh)K{RZt2oX3)3qy!Ta0AqP*33!Uu1(!Ul~i!yk%_ zJ1v#edY^+t@18-A=Y$)MOa0AvmAjvwd_;(xb?hvho`)rPpG2;&%mjJDK9N}myIZKu zsQ~c84nN;w8{=14zZu+q5FR*HaWk;pov%oPR>xZ*aaAS0eN~NL8xXIyD4#`rw@02< z6HuYH!4lZ5R>%>Eowt~|fno*AD3}(L#N-jNVpot1CA2e0rS|%+3)Xoa^BVijzi?HW zK3zXvpSf4j_2iLdd9p>1!o)~o>6Lr$x)CLHXG2Q^C10Sf4vk;L*5cCVB z97?E}fDJ#+4{f%my6q&oXSiRouS^W+(yQ%Oi;2wGW>h$sFP=A|0Nni`6vivpG1DC{ z?!+n?FK*3>qp(z;H_}Wp6ECiH`^a5zX1egF?tJuQZ%#gL)Hck>7n&5_{iroe z*Ol=}E#BRHx%G0Z>T1z~HvN74FHKn1rlj!t z*VYH$QgOaWRy-&dPcmTYZcA2_OtBhwEX;}1kuYtK|~T` zWnP&tcy-3q_WJ2GCNwh88qhm&!rLmAb>!C2N+jk`f(rF3#V zL|f#N8M<8Aks-5>FNQPf6^(AOb1)U^R1}flyu-V6b4^X-x2Hozq9S-_Nx@%k?6$eM%?h1c_ZAy(KX;?ipz(RSIgb@7{BZwu zj@mXiWT(ie8&MPZRhfNI{T2sX*qd(agMIzPuU=tXDtRy4;bY`@ho=yT56O;nKst8& zv><%M+8>*5(Y|eZ@iBq&>|y{x#Pnh&ff|Xv6t1$G$-tFfakx&qyVqp33ndEtAL@7@2T*k}psZLo`&P zr&N`Tb7zsf;`#o5xR$wGh4O9O_ox#~NSMNdmb-AvgYc6&{9))@W2~$4Kvk?bMskB) z2i#N+UuKrvlFJk26_Q{>>nyVu``%>}eT zLX!Da<29SKldBtYc=_Sp!EgNd+12IK!*_N`N(klF)6U9W+@^1>-_n$P&J@OjBaB~N z&SeB0yU7_^9`=08_FAWTN%bOXFnc(6^wCR`>Ss!wohgY}aiK7Fp~xc0LLt}6t=(A@ zskaS<>#pmvEH|-RX%5;XwTsqHDFpC@!q$qAfXdrNdMj@n+5#^qUbzseqPFah428+xcy#Atonq+lAY;VYbmCEcE_0=1Jre074ZfQv zYZGt*ER^QL1{_Mr6;jDlRF8{Li;KA!ayj$yjbTGs)H*y{#HxqawKh&6QGFeZb!U}( zXOQ)C)y6OxR9g-ErCEC8TW6DHO6P@)YOR}lJwCf;x_!>0NVktMCdjp^v4*=n=LfZrf-8ub z(aBaw``p=zdUvBz-c|LpNayWa#j|fT>YBGtju13HGl>bi)bqQWV$F3x)oSOCw1JKD zOTjLLG(v7E8Y&NNmvMI2l?APL-HN>@j7U#mH~Mf;Pf*;N-#|xF%E#$447ufHWX$q` z+oPn*wp!V0`o_dwSZ1!{0UxOPS8y6zMcdV?^pq!sgfI(3t%ED@B{KOpbMxmG8IdlS*{L0n_LdwQq(-ojAM1eP;JI zsfXEFl07k9N9}#cjxK%1QRi^@z;$UTTi4*J_Wev&3ti9aRwL#WuWb&c@o4i0P0c+0 zw&^GyXU1%Qu~I1TaS4l*iq%rOx%T9h`s4-gqPJUIa_)2-^d{=LUn0)-f-=rgus7)c z`Fs7loNISlq!2CBTn|l@9vQ2zWba2M9Sdyw@Z$k#hpfpBFRGiY;Grmj%*9QGtzKKx z8Y{HLFVl8QTqS%W^m@Pi(N#P`Dnf0yx`7UC>Y+Wy_0| zoktr*ZbWX2tY-p(YvhrXDh!dkz^k*>GV&dh20nZETeeb%UtH%>4GRZ!b1VpNZG`QW z41b7hbEUovDWnPbILqGm+yaD5ER}t%KpgxoS^3@j_r= z#*x|Ge0#|0@iyx!0b_f{9X|)wOiQUbu108jFo{vTh52Ew2(Sdzb=MHvO`RGXEp~%kW^T*a(GdN45*mF5spdz{Tr5 z?mbT>l**G(R8pTAuz2()XwwD*5e`{9Ptx`qOVeArP8PP}&E|w|5{nqyadbY+iYBq< z*D|)&yo8qpwo4_boxUVkb=7TeD}HD__wI4Xwd07GK-9EBmX@!)g0SJj}GC}6Xvsp8AhfNzE&xoja#aJR-<=@`zI0-?q|Fxp9@9_$~J=ytu;@H1IC<03Km> zRj^N72B+ijSsa!5iJ zqB;(g0Ii|>IxJt`uv7JHIf|Q;wk%JgGGmqblOdWV#H9BD%a<+ta1&A;7jT(V!D|7z z#FET7%8O}H`G)CZgU?#$CyT~1s!OB5+A1cpE>g50V4*QU*cmz?;QYYvFez{EIE*>t z>#0BGr8g}nngrDuUi-E|cL!WFL4ed&jn6Z;Csy`)1VzrKp4dr-^Sb88DVcw)A%+St zIB@bhSync)45vfinnU#mvdX)nK>_V2d<7Ekrl{6!R2zCMgHsu*T{YvR=H5(Rz!|*=4WHSie$DB)vdi>ld%N#T(v%I~K zWZW*Y&omlKr>gSWRzjrc%a#(H*5-bnaLG~S)uHmTXEimf8^>2`wQH+1zWCpx%E7mr zI(GbK@2j~i1BNuPHDqP6JCzV*rf8 zDvauOYthT9qQ?M?d19wD6H@=~Ya+HnAYT6|f z1DRh>`7DFP^E}GkI)04HMOi1%7wf>WcmF*!WBQV%hi${hk6SG#wSO&DjjJ zo&mG{q5zUNfhn0-*?y<2Hx-{R#sG%KrS-6xS=?jBZr@*}_OQD7F+HV6p5=`>%e&gF zxQaH3$gxTgyL(q;%h5nLS;LbeZxw_6ovm}bcPBK)XKyr^3OT!2sEYL#Jg`dc zC9@1&OwP~~cykm`cpj?5FHYr_lH{@6<%wGZT{2`P=n|B>>KRbAcw1aAh?4eBk`;?m zf?j^YXWV5d7k9>MUsGX`rWXb6d%BOP*fl zX_jEFx52^i4D0-UlV6k00{toW=?*z5<-%~}>Ra^@wOxicZE_Qt#~Xx0j=WlOj`N*g zADz**Gr(E#2e;~-wXDSYO5{^$DaMMbbeDnt@+lI@U!K-HUWt`?T9ZuvYBH`SXii!A zjy=cPgTS$gC2#u7ssj@oad~}}H7?NbxnQ;5Nz&L5vvaYQ4O!F;mud!K=CkM9x}Wgm zDMQ*S(2}uJWo#-fZfTcP3FJ=aRcYo1G-}%v$*~^u=9SQD*Hy~vE07i`v)bQID)5l8 zS?3bfKD%f0{*}{5O8Hr_n)iqDcQfX)`-e2eY@J1IKD>RCvDGR}O>8!*p|K&ya7=K# zv!#F=<{6K}tNBJ#97$JU2jnbP!e=J#7}fAGE2KkwthV57C#A|}OlBjSAUM*f`m__? zUnTD8RoCjO;5E4+hH@K}Rq%;Ho|EtsiwO`s`ha7 zY3`wk5bxYu;@jj?!JL$ebd$=5qYLL6G|EEcG}rmMjsf~N{718_*ep~>_?oTNvwXk; zsZ$cL!zYLMJ?|v=b$LkVr$t9H+DA{bJ4UIi$dgN2tpfBe6VNi`NVMdSE=h7n#CT`b zAFjj>>W+zcgrNafE)t&35z?zt3qwU)hkYmxMJqm7(}V zBm9t1gCWROvj$sVj((H5aaVci;oZ! zqHUY7$HFymI|+fUViRVbOI-Fa!pHPPd?BlDaz`P$&2 z`snt&bDS>ha?$J!#@S+j`Dn31i?C*vP#y%0z05OV^QZccD`*3e%+hJQ^#?crgvMS! zQJQ%qU0$bp=~QEah|ETl1b?vDYHYKRtApy_Qj zhQFMfdg{e3wtD;3Ezb~n%9J;%H8qmFnF9=VLSpYnODfMd^Y)nZd8B0y9tI71KC@Tr zE5>D0#s6jz*x_W!d(K zHQ1RAAbwAICnpAM^&soEv@+(RpVT$duiN$mo_BC|)-K_fNa}{gCP}c2IhW!ZS`R9R z5I+)`k^+R{(OD3qVwH6ywERO5*B@N;D(h-FEPeFG0)JDB{;TwdGV#yy#c7;ge2eoz z$7gOxw|){$S=G=T`MjMDZvm&K2$js*%l2Z0henZSq+ZZFJHYmo-TBIw$KN@;0kGa?_(ck2nKpA)|POl$q> z>es7Tgmg3vqWpWlg2SIh$a~9P9`-Br8}5|0Or3~oeQSy}kR0UHGQ>BeYD{b?Y`}r9 z59_9cWsooxF~!E3$F4Jjl$4chdyGU*xep>inhoKgdLuJ~f*Ix8{9V%NSKf`679@>m z(;LGgM6PuA7({A{bW{6OwI5j{pS@oSCavcb<~bswzilb<6ai?tY(FBel|ukcGqW-n zE~#jj*60sWAzO%Zt6fTK`{Ld7VAy|!v*}KjrooVlD9-6sDnd7!x_7=EgoQE3;q%Bt zYL^cqqY?v1&!KHoX>kREP}(xPLicAyQ^v2K?Nz4Prb-Kn8`f6BAArX=8XBTE^6fQC z?FSVM0=%`1!QUz{ARxu%H1wOpYc#GgT*4R+yCH~kgZ{LRW= z-%g!e-l#e$Nn--L?0cItU)r!1-7MxABEOYWG3(aGa(nfL<-ip-{!2225M6mla;)z_7|BfyWm!jBtZ5gc3%1 z_TWTQ-x#|Ck(;CMb9}1nJt93C@$C|+0Y&0}QFnr=D8Uq)@I$!-elI)`_(?<;0BN{8 z!a&jp2b3fXY3^j>h(e$XfY6W1ruHz9_&v;ZN72R%=46VpK{%+xoNO!sm%k1k4raRV`>GHL*H;mdEeGhE<5 z=I~n)6A%CYP{L#wqvYTZCXzl*ZSQxv?wfWYG$85*&W*71LK{M{-6*=7=C@ufemWW$ z(b~c~3~#+93J;btoXF4U(1zBKB}z?Fel(%jDaC#esE@#U7O*|*etWd>HU(us%cmEL z5d7-RZg#wOs3>&M;X0v=u+b71j&bUh$&?hg&n%qYUiJE4urDR*O5RJyBS_mhcs;dl z`6%i+U-hT)vnIILE91q76+n_Fj73#BL9h5Y>bmEEz1b{ex|*vO$js^Nu_r8>aPj!NAL>(dj_zb+6`z62CPBk9o8?ynhH`ru zA1GE^otH-488Vla9$@7DQgC0cWm+^}=u1%ypVz$ZoJSL-s0`aoBl4Vo6Khmp8TZo_@14Zk99p9X1iRYB6aPi# zadG_-q2IF%r0#5n!layrlQZl)RooN_!^HW&Pc|DTBuc{C)CrSBil#sN-24ELwv7eK z8mSKkLbW_x${G#{N=vCylP;!no(p48PTg z2?_m>k6ueZ#NKy8n5)B3`XF>IA4mh{hBExqQuvFX@0(h|K=)0ZFbj+iBLJiZLn54= z%wb3%7e_fAXN8gz2nNC`UmM$ko-A(-p#raIyk%2?z*)z}z5i zZVogD2h!aEW$MP^fTYKW_#xxB2&1rilwEEISidtoZOt~24vCU=QHNxVFiMKzrL41 z*xNfh*r42nFe3kufwu3bR7q(qm=h9hp9s3f^C#CIG|W6e7{h;=$p3b7Xg~k%wLeYH z&D0S+Iq+|jL-Pqrpld|Y{~Q_!1YAVh$p&3TDg^o~{kzS-6Je6*B2y7=FgGs;Sb&3z zO9KoRp@IKK;9pE|3>5=a_rw0`~Ocw{(#odXt^+*D+W0GF92HJ zzhHMiU_U81%pMH^qCr4Y2Mbdt3jpXo5QFle(arl-z#pI`=pGP#bfAJpW8Kks80bFS z)Es7y1_(joaD=%X2Ac#aprJ)BG*J2rSol}0@Xz`r5$4Vq85n(B7}NfwP(lAY3HWD; z-}x}78^0Z7{1B<(1cRv|5ExP4QBce?kn1}X3IM4g;4mdqNA!r_W(d0f)8g;b{HqGg zu%9ZFo$ZnO05DJ=_`{eVzlH$AUncnr`*(O71I8lJTK|H;q8(&ofz^9i8uJm@hzjq2=(RDuJc^Em|Xd34Jf2*GdV++PU$sY}h*3E~u<+o`<1w?*00v!$v z?#Lo3h`~L<0$f~ZLj=Au!fo2A)W1kARYk$ z9tnP^xU?h}lvi9z0>UjJjm~IkhyYlchgX0PvwtB`rcS8uX~V?_;Q|8~8KqRD0sjZI Cm;{di diff --git a/templates/default.gbai/default.gbot/config.csv b/templates/default.gbai/default.gbot/config.csv index 8a4f03d9..3d3fcf93 100644 --- a/templates/default.gbai/default.gbot/config.csv +++ b/templates/default.gbai/default.gbot/config.csv @@ -1,8 +1,8 @@ name,value -server_host=0.0.0.0 -server_port=8080 -sites_root=/tmp +server_host,0.0.0.0 +server_port,8080 +sites_root,/tmp llm-key,gsk_ llm-model,openai/gpt-oss-20b