kagi-api 0.1.1

Kagi.com API bindings (Search, FastGPT, Universal Summarizer, Enrichment)
Documentation
use std::{collections::HashMap, path::PathBuf};

use const_format::concatcp;

use crate::{KagiError, KagiResult};

/// The environment variable prefix giving way to the variables
///
/// - `KAGI_API_KEY`
/// - `KAGI_API_BASE`
/// - `KAGI_API_LOGDIR`
pub const ENV_PREFIX: &str = "KAGI_API";

pub const DEFAULT_API_BASE: &str = "https://kagi.com/api";

pub const REPLAY_LOG: &str = "kagi-results.json";

/// When the record/replay feature is enabled, determine if recording or replaying.
///
/// FIXME: Add third option to flexibly record or replay, depending on presence of query in log.
///
/// This would need to support in [rvcr] crate; currently replaying non-existing query panics.
#[derive(Debug, Default, Copy, Clone)]
pub enum RecordReplayMode {
    #[default]
    Record,
    Replay,
}

impl From<RecordReplayMode> for rvcr::VCRMode {
    fn from(value: RecordReplayMode) -> Self {
        match value {
            RecordReplayMode::Record => rvcr::VCRMode::Record,
            RecordReplayMode::Replay => rvcr::VCRMode::Replay,
        }
    }
}

#[derive(Debug, Clone)]
pub struct KagiConfig {
    pub api_key: String,
    pub api_base: String,
    pub logdir: Option<PathBuf>,
}

impl KagiConfig {
    pub fn with_api_key(api_key: &str) -> Self {
        Self {
            api_key: String::from(api_key),
            api_base: String::from(DEFAULT_API_BASE),
            logdir: None,
        }
    }

    pub fn from_env() -> KagiResult<KagiConfig> {
        let config_builder =
            config::Config::builder().add_source(config::Environment::with_prefix(ENV_PREFIX));
        let config = config_builder.build().map_err(KagiError::ConfigError)?;
        let config_map = config
            .try_deserialize::<HashMap<String, String>>()
            .map_err(KagiError::ConfigError)?;

        let Some(api_key) = config_map.get("key").map(|api_key| api_key.to_owned()) else {
            return Err(KagiError::EnvError(concatcp!(
                "Couldn't find the ",
                ENV_PREFIX,
                "_KEY",
                " environment variable containing the Kagi API key",
            )));
        };

        let api_base = config_map
            .get("base")
            .unwrap_or(&String::from(DEFAULT_API_BASE))
            .to_owned();

        let logdir = config_map.get("logdir").map(PathBuf::from);

        let config = KagiConfig {
            api_key,
            api_base,
            logdir,
        };

        Ok(config)
    }
}