doum_cli/cli/
secret.rs

1use crate::cli::ui::{prompt_password_input, prompt_text_input};
2use crate::llm::AnthropicSecret;
3use crate::llm::OpenAISecret;
4use crate::system::DoumError::Config;
5use crate::system::error::DoumResult;
6use dialoguer::Select;
7use rust_embed::RustEmbed;
8use serde::Deserialize;
9
10#[derive(RustEmbed)]
11#[folder = "static/presets/"]
12struct ModelPresets;
13
14#[derive(Debug, Deserialize, Clone)]
15pub struct ModelInfo {
16    pub id: String,
17    pub name: String,
18    pub description: String,
19}
20
21#[derive(Debug, Deserialize)]
22struct ModelList {
23    models: Vec<ModelInfo>,
24}
25
26/// Load model presets for a provider
27pub fn load_presets(provider: &str) -> Vec<ModelInfo> {
28    let filename = format!("{}.toml", provider);
29
30    if let Some(content) = ModelPresets::get(&filename)
31        && let Ok(data) = std::str::from_utf8(content.data.as_ref())
32        && let Ok(list) = toml::from_str::<ModelList>(data)
33    {
34        return list.models;
35    }
36
37    vec![]
38}
39
40pub fn handle_secret_command(provider: Option<String>) -> DoumResult<()> {
41    let provider = match provider {
42        Some(p) => p,
43        None => select_provider()?,
44    };
45
46    configure_provider_secret(&provider)
47}
48
49fn select_provider() -> DoumResult<String> {
50    let providers = vec!["openai", "anthropic"];
51    let selection = Select::new()
52        .with_prompt("Select provider to configure")
53        .items(&providers)
54        .default(0)
55        .interact()?;
56
57    Ok(providers[selection].to_string())
58}
59
60fn configure_provider_secret(provider: &str) -> DoumResult<()> {
61    match provider {
62        "openai" => configure_openai_secret(),
63        "anthropic" => configure_anthropic_secret(),
64        _ => Err(Config(format!("Unknown provider: {}", provider))),
65    }
66}
67
68fn configure_openai_secret() -> DoumResult<()> {
69    println!("\nšŸ” Configure OpenAI Secrets\n");
70
71    let api_key = prompt_password_input("OpenAI API Key (required)")?;
72
73    let organization = prompt_text_input("Organization ID (optional, press Enter to skip)", None)?;
74
75    let project = prompt_text_input("Project ID (optional, press Enter to skip)", None)?;
76
77    let secret = OpenAISecret {
78        api_key,
79        organization: if organization.is_empty() {
80            None
81        } else {
82            Some(organization)
83        },
84        project: if project.is_empty() {
85            None
86        } else {
87            Some(project)
88        },
89    };
90
91    secret.save()?;
92    println!("\nāœ… OpenAI secrets saved successfully");
93    Ok(())
94}
95
96fn configure_anthropic_secret() -> DoumResult<()> {
97    println!("\nšŸ” Configure Anthropic Secrets\n");
98
99    let api_key = prompt_password_input("Anthropic API Key (required)")?;
100
101    let secret = AnthropicSecret { api_key };
102
103    secret.save()?;
104    println!("\nāœ… Anthropic secrets saved successfully");
105    Ok(())
106}