Skip to content

Commit 43d9e4c

Browse files
committed
Add feature to save OpenAI API key locally
- Extend `README.md` with instructions to save the API key. - Modify `main.go` to include a `--save-key` flag. - Implement functions in `savekey.go` for saving/loading the key.
1 parent 535d91f commit 43d9e4c

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ aicommit -c "improved HTTP performance by 50%"
6161
aicommit -c "bad code but need for urgent customer fix"
6262
```
6363

64+
When tired of setting environment variables, you can save your key to disk:
65+
66+
```bash
67+
export OPENAI_API_KEY="..."
68+
aicommit --save-key
69+
# The environment variable will override the saved key.
70+
```
71+
6472
## Style Guide
6573

6674
`aicommit` will read the `COMMITS.md` file in the root of the repository to

cmd/aicommit/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,38 @@ func main() {
204204
var (
205205
opts runOptions
206206
openAIKey string
207+
doSaveKey bool
207208
)
208209
cmd := &serpent.Command{
209210
Use: "aicommit [ref]",
210211
Short: "aicommit is a tool for generating commit messages",
211212
Handler: func(inv *serpent.Invocation) error {
213+
savedKey, err := loadKey()
214+
if err != nil && !os.IsNotExist(err) {
215+
return err
216+
}
217+
if savedKey != "" && openAIKey == "" {
218+
openAIKey = savedKey
219+
}
212220
if openAIKey == "" {
213221
return errors.New("$OPENAI_API_KEY is not set")
214222
}
223+
224+
if doSaveKey {
225+
err := saveKey(openAIKey)
226+
if err != nil {
227+
return err
228+
}
229+
230+
kp, err := keyPath()
231+
if err != nil {
232+
return err
233+
}
234+
235+
fmt.Fprintf(inv.Stdout, "Saved OpenAI API key to %s\n", kp)
236+
return nil
237+
}
238+
215239
client := openai.NewClient(openAIKey)
216240
opts.client = client
217241
if len(inv.Args) > 0 {
@@ -226,6 +250,12 @@ func main() {
226250
Env: "OPENAI_API_KEY",
227251
Value: serpent.StringOf(&openAIKey),
228252
},
253+
{
254+
Name: "save-key",
255+
Description: "Save the OpenAI API key to persistent local configuration and exit.",
256+
Flag: "save-key",
257+
Value: serpent.BoolOf(&doSaveKey),
258+
},
229259
{
230260
Name: "dry-run",
231261
Flag: "dry",

cmd/aicommit/savekey.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
func configDir() (string, error) {
10+
cdir, err := os.UserConfigDir()
11+
if err != nil {
12+
return "", err
13+
}
14+
err = os.MkdirAll(filepath.Join(cdir, "aicommit"), 0o700)
15+
if err != nil {
16+
return "", err
17+
}
18+
return filepath.Join(cdir, "aicommit"), nil
19+
}
20+
21+
func keyPath() (string, error) {
22+
cdir, err := configDir()
23+
if err != nil {
24+
return "", err
25+
}
26+
return filepath.Join(cdir, "openai.key"), nil
27+
}
28+
29+
func saveKey(key string) error {
30+
if key == "" {
31+
return errors.New("key is empty")
32+
}
33+
kp, err := keyPath()
34+
if err != nil {
35+
return err
36+
}
37+
return os.WriteFile(kp, []byte(key), 0o600)
38+
}
39+
40+
func loadKey() (string, error) {
41+
kp, err := keyPath()
42+
if err != nil {
43+
return "", err
44+
}
45+
b, err := os.ReadFile(kp)
46+
if err != nil {
47+
return "", err
48+
}
49+
return string(b), nil
50+
}

0 commit comments

Comments
 (0)