summaryrefslogtreecommitdiffstats
path: root/src/config/bot.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config/bot.rs')
-rw-r--r--src/config/bot.rs260
1 files changed, 0 insertions, 260 deletions
diff --git a/src/config/bot.rs b/src/config/bot.rs
deleted file mode 100644
index 7177f92..0000000
--- a/src/config/bot.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-use super::*;
-
-use crate::{
- client::Model,
- function::{Functions, FunctionsFilter, SELECTED_ALL_FUNCTIONS},
-};
-
-use anyhow::{Context, Result};
-use std::{fs::read_to_string, path::Path};
-
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Clone, Serialize)]
-pub struct Bot {
- name: String,
- config: BotConfig,
- definition: BotDefinition,
- #[serde(skip)]
- functions: Functions,
- #[serde(skip)]
- rag: Option<Arc<Rag>>,
- #[serde(skip)]
- model: Model,
-}
-
-impl Bot {
- pub async fn init(
- config: &GlobalConfig,
- name: &str,
- abort_signal: AbortSignal,
- ) -> Result<Self> {
- let definition_path = Config::bot_definition_file(name)?;
- let functions_path = Config::bot_functions_file(name)?;
- let rag_path = Config::bot_rag_file(name)?;
- let embeddings_dir = Config::bot_embeddings_dir(name)?;
- let definition = BotDefinition::load(&definition_path)?;
- let functions = if functions_path.exists() {
- Functions::init(&functions_path)?
- } else {
- Functions::default()
- };
- let bot_config = config
- .read()
- .bots
- .iter()
- .find(|v| v.name == name)
- .cloned()
- .unwrap_or_else(|| BotConfig::new(name));
- let model = {
- let config = config.read();
- match bot_config.model_id.as_ref() {
- Some(model_id) => Model::retrieve_chat(&config, model_id)?,
- None => config.current_model().clone(),
- }
- };
- let rag = if rag_path.exists() {
- Some(Arc::new(Rag::load(config, "rag", &rag_path)?))
- } else if embeddings_dir.is_dir() {
- println!("The bot uses an embeddings directory, initializing RAG...");
- let doc_path = embeddings_dir.display().to_string();
- Some(Arc::new(
- Rag::init(config, "rag", &rag_path, &[doc_path], abort_signal).await?,
- ))
- } else {
- None
- };
-
- Ok(Self {
- name: name.to_string(),
- config: bot_config,
- definition,
- functions,
- rag,
- model,
- })
- }
-
- pub fn export(&self) -> Result<String> {
- let mut value = serde_json::json!(self);
- value["functions_dir"] = Config::bot_source_dir(&self.name)?
- .display()
- .to_string()
- .into();
- value["config_dir"] = Config::bot_config_dir(&self.name)?
- .display()
- .to_string()
- .into();
- let data = serde_yaml::to_string(&value)?;
- Ok(data)
- }
-
- pub fn banner(&self) -> String {
- self.definition.banner()
- }
-
- pub fn name(&self) -> &str {
- &self.name
- }
-
- pub fn config(&self) -> &BotConfig {
- &self.config
- }
-
- pub fn functions(&self) -> &Functions {
- &self.functions
- }
-
- pub fn definition(&self) -> &BotDefinition {
- &self.definition
- }
-
- pub fn rag(&self) -> Option<Arc<Rag>> {
- self.rag.clone()
- }
-
- pub fn conversation_staters(&self) -> &[String] {
- &self.definition.conversation_starters
- }
-}
-
-impl RoleLike for Bot {
- fn to_role(&self) -> Role {
- let mut role = Role::new("", &self.definition.instructions);
- role.sync(self);
- role
- }
-
- fn model(&self) -> &Model {
- &self.model
- }
-
- fn model_mut(&mut self) -> &mut Model {
- &mut self.model
- }
-
- fn temperature(&self) -> Option<f64> {
- self.config.temperature
- }
-
- fn top_p(&self) -> Option<f64> {
- self.config.top_p
- }
-
- fn functions_filter(&self) -> Option<FunctionsFilter> {
- if self.functions.is_empty() {
- None
- } else {
- Some(SELECTED_ALL_FUNCTIONS.into())
- }
- }
-
- fn set_model(&mut self, model: &Model) {
- self.config.model_id = Some(model.id());
- self.model = model.clone();
- }
-
- fn set_temperature(&mut self, value: Option<f64>) {
- self.config.temperature = value;
- }
-
- fn set_top_p(&mut self, value: Option<f64>) {
- self.config.top_p = value;
- }
-
- fn set_functions_filter(&mut self, _value: Option<FunctionsFilter>) {}
-}
-
-#[derive(Debug, Clone, Default, Deserialize, Serialize)]
-pub struct BotConfig {
- pub name: String,
- #[serde(rename(serialize = "model", deserialize = "model"))]
- pub model_id: Option<String>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub temperature: Option<f64>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub top_p: Option<f64>,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub dangerously_functions_filter: Option<FunctionsFilter>,
-}
-
-impl BotConfig {
- pub fn new(name: &str) -> Self {
- Self {
- name: name.to_string(),
- ..Default::default()
- }
- }
-}
-
-#[derive(Debug, Clone, Default, Deserialize, Serialize)]
-pub struct BotDefinition {
- pub name: String,
- #[serde(default)]
- pub description: String,
- #[serde(default)]
- pub version: String,
- pub instructions: String,
- #[serde(default)]
- pub conversation_starters: Vec<String>,
-}
-
-impl BotDefinition {
- pub fn load(path: &Path) -> Result<Self> {
- let contents = read_to_string(path)
- .with_context(|| format!("Failed to read bot index file at '{}'", path.display()))?;
- let definition: Self = serde_yaml::from_str(&contents)
- .with_context(|| format!("Failed to load bot at '{}'", path.display()))?;
- Ok(definition)
- }
-
- fn banner(&self) -> String {
- let BotDefinition {
- name,
- description,
- version,
- conversation_starters,
- ..
- } = self;
- let starters = if conversation_starters.is_empty() {
- String::new()
- } else {
- let starters = conversation_starters
- .iter()
- .map(|v| format!("- {v}"))
- .collect::<Vec<_>>()
- .join("\n");
- format!(
- r#"
-
-## Conversation Starters
-{starters}"#
- )
- };
- format!(
- r#"# {name} {version}
-{description}{starters}"#
- )
- }
-}
-
-pub fn list_bots() -> Vec<String> {
- list_bots_impl().unwrap_or_default()
-}
-
-fn list_bots_impl() -> Result<Vec<String>> {
- let base_dir = Config::functions_dir()?;
- let contents = read_to_string(base_dir.join("bots.txt"))?;
- let bots = contents
- .split('\n')
- .filter_map(|line| {
- let line = line.trim();
- if line.is_empty() {
- None
- } else {
- Some(line.to_string())
- }
- })
- .collect();
- Ok(bots)
-}