Skip to main content

systemprompt_cli/commands/cloud/profile/
api_keys.rs

1use anyhow::{bail, Result};
2use dialoguer::theme::ColorfulTheme;
3use dialoguer::{Password, Select};
4use systemprompt_logging::CliService;
5
6#[derive(Debug)]
7pub struct ApiKeys {
8    pub gemini: Option<String>,
9    pub anthropic: Option<String>,
10    pub openai: Option<String>,
11}
12
13impl ApiKeys {
14    pub fn from_options(
15        gemini: Option<String>,
16        anthropic: Option<String>,
17        openai: Option<String>,
18    ) -> Result<Self> {
19        if gemini.is_none() && anthropic.is_none() && openai.is_none() {
20            bail!(
21                "At least one AI provider API key is required.\nProvide: --anthropic-key, \
22                 --openai-key, or --gemini-key"
23            );
24        }
25        Ok(Self {
26            gemini,
27            anthropic,
28            openai,
29        })
30    }
31}
32
33pub fn collect_api_keys() -> Result<ApiKeys> {
34    CliService::info("At least one AI provider API key is required.");
35
36    let providers = vec![
37        "Google AI (Gemini) - https://aistudio.google.com/app/apikey",
38        "Anthropic (Claude) - https://console.anthropic.com/api-keys",
39        "OpenAI (GPT) - https://platform.openai.com/api-keys",
40    ];
41
42    let selection = Select::with_theme(&ColorfulTheme::default())
43        .with_prompt("Select your AI provider")
44        .items(&providers)
45        .default(0)
46        .interact()?;
47
48    match selection {
49        0 => {
50            let key = Password::with_theme(&ColorfulTheme::default())
51                .with_prompt("Gemini API Key")
52                .interact()?;
53            if key.is_empty() {
54                bail!("API key is required");
55            }
56            Ok(ApiKeys {
57                gemini: Some(key),
58                anthropic: None,
59                openai: None,
60            })
61        },
62        1 => {
63            let key = Password::with_theme(&ColorfulTheme::default())
64                .with_prompt("Anthropic API Key")
65                .interact()?;
66            if key.is_empty() {
67                bail!("API key is required");
68            }
69            Ok(ApiKeys {
70                gemini: None,
71                anthropic: Some(key),
72                openai: None,
73            })
74        },
75        2 => {
76            let key = Password::with_theme(&ColorfulTheme::default())
77                .with_prompt("OpenAI API Key")
78                .interact()?;
79            if key.is_empty() {
80                bail!("API key is required");
81            }
82            Ok(ApiKeys {
83                gemini: None,
84                anthropic: None,
85                openai: Some(key),
86            })
87        },
88        _ => bail!("Invalid selection"),
89    }
90}