slf/gitai/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
pub mod git;
pub mod providers;

use anyhow::{anyhow, Result};
use async_trait::async_trait;
use providers::{OLLAMA_HOST, OLLAMA_MODEL};
use serde::{Deserialize, Serialize};

use crate::config::ShelfConfig;

#[async_trait]
pub trait Provider: Send + Sync {
    async fn generate_commit_message(&self, diff: &str) -> Result<String>;

    fn prompt(&self, diff: &str) -> String {
        format!(
            "Generate a concise commit message for the following git diff output:\n{}",
            diff
        )
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GitAIConfig {
    pub provider: String,
    pub openai_api_key: Option<String>,
    pub anthropic_api_key: Option<String>,
    pub gemini_api_key: Option<String>,
    pub groq_api_key: Option<String>,
    pub xai_api_key: Option<String>,
    pub ollama_host: Option<String>,
    pub ollama_model: Option<String>,
}

impl GitAIConfig {
    pub async fn load() -> Result<Self> {
        ShelfConfig::load_config()
    }

    pub fn set(&mut self, key: &str, value: &str) -> Result<()> {
        match key {
            "provider" => self.provider = value.to_string(),
            "openai_api_key" => self.openai_api_key = Some(value.to_string()),
            "anthropic_api_key" => self.anthropic_api_key = Some(value.to_string()),
            "gemini_api_key" => self.gemini_api_key = Some(value.to_string()),
            "groq_api_key" => self.groq_api_key = Some(value.to_string()),
            "xai_api_key" => self.xai_api_key = Some(value.to_string()),
            "ollama_host" => self.ollama_host = Some(value.to_string()),
            "ollama_model" => self.ollama_model = Some(value.to_string()),
            _ => return Err(anyhow!("Unknown config key: {}", key)),
        }
        Ok(())
    }

    pub fn get(&self, key: &str) -> Option<String> {
        match key {
            "provider" => Some(self.provider.clone()),
            "openai_api_key" => self.openai_api_key.clone(),
            "anthropic_api_key" => self.anthropic_api_key.clone(),
            "gemini_api_key" => self.gemini_api_key.clone(),
            "groq_api_key" => self.groq_api_key.clone(),
            "xai_api_key" => self.xai_api_key.clone(),
            "ollama_host" => self.ollama_host.clone(),
            "ollama_model" => self.ollama_model.clone(),
            _ => None,
        }
    }

    pub async fn save(&self) -> Result<()> {
        ShelfConfig::save_config(self)
    }

    pub fn list(&self) -> Vec<(&str, String)> {
        let mut items = vec![("provider", self.provider.clone())];

        if let Some(key) = &self.openai_api_key {
            items.push(("openai_api_key", key.clone()));
        }
        if let Some(key) = &self.anthropic_api_key {
            items.push(("anthropic_api_key", key.clone()));
        }
        if let Some(key) = &self.gemini_api_key {
            items.push(("gemini_api_key", key.clone()));
        }
        if let Some(key) = &self.groq_api_key {
            items.push(("groq_api_key", key.clone()));
        }
        if let Some(host) = &self.xai_api_key {
            items.push(("xai_api_key", host.clone()));
        }
        if let Some(host) = &self.ollama_host {
            items.push(("ollama_host", host.clone()));
        }
        if let Some(model) = &self.ollama_model {
            items.push(("ollama_model", model.clone()));
        }

        items
    }
}

impl Default for GitAIConfig {
    fn default() -> Self {
        Self {
            provider: "groq".to_string(),
            openai_api_key: None,
            anthropic_api_key: None,
            gemini_api_key: None,
            groq_api_key: None,
            xai_api_key: None,
            ollama_host: Some(OLLAMA_HOST.to_string()),
            ollama_model: Some(OLLAMA_MODEL.to_string()),
        }
    }
}