summaryrefslogtreecommitdiffstats
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs152
1 files changed, 139 insertions, 13 deletions
diff --git a/src/config.rs b/src/config.rs
index 802f376..2f0a361 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,9 +1,11 @@
use std::{
+ cell::RefCell,
env,
fs::{create_dir_all, read_to_string, File, OpenOptions},
io::Write,
path::{Path, PathBuf},
process::exit,
+ sync::Arc,
};
use anyhow::{anyhow, Context, Result};
@@ -35,11 +37,24 @@ pub struct Config {
#[serde(default)]
pub dry_run: bool,
/// Predefined roles
- #[serde(default, skip_serializing)]
+ #[serde(default, skip)]
pub roles: Vec<Role>,
+ /// Current selected role
+ #[serde(default, skip)]
+ pub role: Option<Role>,
}
+pub type SharedConfig = Arc<RefCell<Config>>;
+
impl Config {
+ pub const UPDATE_KEYS: [&str; 6] = [
+ "api_key",
+ "temperature",
+ "save",
+ "highlight",
+ "proxy",
+ "dry_run",
+ ];
pub fn init(is_interactive: bool) -> Result<Config> {
let config_path = Config::config_file()?;
if is_interactive && !config_path.exists() {
@@ -99,18 +114,17 @@ impl Config {
Ok(file)
}
- pub fn save_message(
- file: Option<&mut File>,
- input: &str,
- output: &str,
- role_name: &Option<String>,
- ) {
- let role_name = match role_name {
- Some(v) => format!("({v})"),
- None => String::new(),
- };
- let timestamp = format!("[{}]", now());
- if let (false, Some(file)) = (output.is_empty(), file) {
+ pub fn save_message(&self, file: Option<&mut File>, input: &str, output: &str) {
+ if output.is_empty() || !self.save {
+ return;
+ }
+ if let Some(file) = file {
+ let role_name = self
+ .role
+ .as_ref()
+ .map(|v| format!("({})", v.name))
+ .unwrap_or_default();
+ let timestamp = format!("[{}]", now());
let _ = file.write_all(
format!(
"# CHAT:{timestamp} {role_name}\n{}\n\n--------\n{}\n--------\n\n",
@@ -138,6 +152,118 @@ impl Config {
Self::local_file(MESSAGE_FILE_NAME)
}
+ pub fn change_role(&mut self, name: &str) -> String {
+ match self.find_role(name) {
+ Some(role) => {
+ let output = format!("{}>> {}", role.name, role.prompt.trim());
+ self.role = Some(role);
+ output
+ }
+ None => "Unknown role".into(),
+ }
+ }
+
+ pub fn get_prompt(&self) -> Option<String> {
+ self.role.as_ref().and_then(|v| {
+ if v.prompt.is_empty() {
+ None
+ } else {
+ Some(v.prompt.to_string())
+ }
+ })
+ }
+
+ pub fn info(&self) -> Result<String> {
+ let file_info = |path: &Path| {
+ let state = if path.exists() { "" } else { " ⚠️" };
+ format!("{}{state}", path.display())
+ };
+ let proxy = self
+ .proxy
+ .as_ref()
+ .map(|v| v.to_string())
+ .unwrap_or("-".into());
+ let temperature = self
+ .temperature
+ .map(|v| v.to_string())
+ .unwrap_or("-".into());
+ let role_name = self
+ .role
+ .as_ref()
+ .map(|v| v.name.to_string())
+ .unwrap_or("-".into());
+ let items = vec![
+ ("config_file", file_info(&Config::config_file()?)),
+ ("roles_file", file_info(&Config::roles_file()?)),
+ ("messages_file", file_info(&Config::messages_file()?)),
+ ("role", role_name),
+ ("api_key", self.api_key.clone()),
+ ("temperature", temperature),
+ ("save", self.save.to_string()),
+ ("highlight", self.highlight.to_string()),
+ ("proxy", proxy),
+ ("dry_run", self.dry_run.to_string()),
+ ];
+ let mut output = String::new();
+ for (name, value) in items {
+ output.push_str(&format!("{name:<20}{value}\n"));
+ }
+ Ok(output)
+ }
+
+ pub fn update(&mut self, data: &str) -> Result<String> {
+ let parts: Vec<&str> = data.split_whitespace().collect();
+ if parts.len() != 2 {
+ return Ok("Usage: .set <key> <value>. If value is null, unset key.".into());
+ }
+ let key = parts[0];
+ let value = parts[1];
+ let unset = value == "null";
+ match key {
+ "api_key" => {
+ if unset {
+ return Ok("Not allowd".into());
+ } else {
+ self.api_key = value.to_string();
+ }
+ }
+ "temperature" => {
+ if unset {
+ self.temperature = None;
+ } else {
+ let value = value.parse().with_context(|| "Invalid value")?;
+ self.temperature = Some(value);
+ }
+ }
+ "save" => {
+ let value = value.parse().with_context(|| "Invalid value")?;
+ self.save = value;
+ }
+ "highlight" => {
+ let value = value.parse().with_context(|| "Invalid value")?;
+ self.highlight = value;
+ }
+ "proxy" => {
+ if unset {
+ self.proxy = None;
+ } else {
+ self.proxy = Some(value.to_string());
+ }
+ }
+ "dry_run" => {
+ let value = value.parse().with_context(|| "Invalid value")?;
+ self.dry_run = value;
+ }
+ _ => {
+ return Ok(format!(
+ "Unknown key, valid keys are {}",
+ Config::UPDATE_KEYS.join(", ")
+ ))
+ }
+ }
+ Ok("Done".into())
+ }
+
fn load_roles(&mut self) -> Result<()> {
let path = Self::roles_file()?;
if !path.exists() {