Skip to content

Commit 8acd1c4

Browse files
committed
Add initial implementation of Gema CLI with environment configuration and command execution
0 parents  commit 8acd1c4

File tree

7 files changed

+567
-0
lines changed

7 files changed

+567
-0
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
GENAI_API_KEY=
2+
GENAI_DEFAULT_MODEL=

Readme.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Gema CLI
2+
3+
Gema CLI is an AI assistant for your terminal that can run commands based on your queries. It leverages the power of AI to understand your requests and suggest appropriate commands to execute.
4+
5+
## Installation
6+
7+
To install Gema CLI, clone the repository and build the executable:
8+
9+
```sh
10+
git clone https://github.com/4nkitd/gemini-cli.git
11+
cd gemini-cli
12+
go build -o ?
13+
```
14+
15+
## Usage
16+
17+
Before using Gema CLI, you need to set the following environment variables:
18+
19+
- `GENAI_DEFAULT_MODEL`: The default AI model to use.
20+
- `GENAI_API_KEY`: Your API key for accessing the AI service.
21+
22+
You can set these environment variables in your terminal:
23+
24+
```sh
25+
export GENAI_DEFAULT_MODEL="models/gemini-2.0-flash-exp"
26+
export GENAI_API_KEY=your_api_key
27+
```
28+
29+
To use Gema CLI, simply run the executable with your query:
30+
31+
```sh
32+
./? "your query here"
33+
```
34+
35+
Gema CLI will process your query, provide a response, and suggest a command to run. You will be prompted to confirm whether you want to execute the suggested command.
36+
37+
## Example
38+
39+
```sh
40+
./? "list all files in the current directory"
41+
```
42+
43+
Output:
44+
45+
```
46+
Response:
47+
Here is the command to list all files in the current directory:
48+
49+
Suggested Command to RUN: ls -la
50+
51+
Run command (y for yes, n for no):
52+
```
53+
54+
If you type `y`, the command will be executed, and the output will be displayed.
55+
56+
## Contributing
57+
58+
Contributions are welcome! Please open an issue or submit a pull request on GitHub.

gemini.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
"os"
9+
"strings"
10+
11+
"github.com/google/generative-ai-go/genai"
12+
"google.golang.org/api/option"
13+
)
14+
15+
type AiResponse struct {
16+
Response string `json:"response"`
17+
Command string `json:"command"`
18+
}
19+
20+
func AskQuery(query string) AiResponse {
21+
22+
apiKey := os.Getenv("GENAI_API_KEY")
23+
if apiKey == "" {
24+
log.Fatal("GENAI_API_KEY environment variable is not set")
25+
}
26+
27+
defaultModel := os.Getenv("GENAI_DEFAULT_MODEL")
28+
if defaultModel == "" {
29+
log.Fatal("GENAI_DEFAULT_MODEL environment variable is not set")
30+
}
31+
var aiTemp float32 = 1
32+
33+
ctx := context.Background()
34+
client, err := genai.NewClient(ctx, option.WithAPIKey(apiKey))
35+
if err != nil {
36+
log.Fatal(err)
37+
}
38+
defer client.Close()
39+
model := client.GenerativeModel(defaultModel)
40+
model.Temperature = &aiTemp
41+
42+
model.SystemInstruction = &genai.Content{Parts: []genai.Part{genai.Text(SystemInstruction)}}
43+
model.ResponseMIMEType = "application/json"
44+
model.ResponseSchema = &genai.Schema{
45+
Type: genai.TypeObject,
46+
Properties: map[string]*genai.Schema{
47+
"response": {
48+
Type: genai.TypeString,
49+
},
50+
"command": {
51+
Type: genai.TypeString,
52+
},
53+
},
54+
Required: []string{"response"},
55+
}
56+
57+
resp, err := model.GenerateContent(ctx, genai.Text(query))
58+
if err != nil {
59+
log.Fatal(err)
60+
}
61+
62+
jsonResponse := responseString(resp)
63+
64+
if !json.Valid([]byte(jsonResponse)) {
65+
log.Fatal("Invalid JSON response")
66+
}
67+
68+
var result AiResponse
69+
if err := json.Unmarshal([]byte(jsonResponse), &result); err != nil {
70+
log.Fatal(err)
71+
}
72+
73+
if result.Response == "" {
74+
log.Fatal("Response field is missing or not a string")
75+
}
76+
77+
return result
78+
}
79+
80+
func responseString(resp *genai.GenerateContentResponse) string {
81+
var b strings.Builder
82+
for i, cand := range resp.Candidates {
83+
if len(resp.Candidates) > 1 {
84+
fmt.Fprintf(&b, "%d:", i+1)
85+
}
86+
b.WriteString(contentString(cand.Content))
87+
}
88+
return b.String()
89+
}
90+
91+
func contentString(c *genai.Content) string {
92+
var b strings.Builder
93+
if c == nil || c.Parts == nil {
94+
return ""
95+
}
96+
for i, part := range c.Parts {
97+
if i > 0 {
98+
fmt.Fprintf(&b, ";")
99+
}
100+
fmt.Fprintf(&b, "%v", part)
101+
}
102+
return b.String()
103+
}

go.mod

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module github.com/4nkitd/gemini-cli
2+
3+
go 1.23.4
4+
5+
require (
6+
github.com/google/generative-ai-go v0.19.0
7+
github.com/spf13/cobra v1.8.1
8+
google.golang.org/api v0.186.0
9+
)
10+
11+
require (
12+
cloud.google.com/go v0.115.0 // indirect
13+
cloud.google.com/go/ai v0.8.0 // indirect
14+
cloud.google.com/go/auth v0.6.0 // indirect
15+
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
16+
cloud.google.com/go/compute/metadata v0.3.0 // indirect
17+
cloud.google.com/go/longrunning v0.5.7 // indirect
18+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
19+
github.com/charmbracelet/bubbletea v1.2.4 // indirect
20+
github.com/charmbracelet/lipgloss v1.0.0 // indirect
21+
github.com/charmbracelet/x/ansi v0.4.5 // indirect
22+
github.com/charmbracelet/x/term v0.2.1 // indirect
23+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
24+
github.com/felixge/httpsnoop v1.0.4 // indirect
25+
github.com/go-logr/logr v1.4.1 // indirect
26+
github.com/go-logr/stdr v1.2.2 // indirect
27+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
28+
github.com/golang/protobuf v1.5.4 // indirect
29+
github.com/google/s2a-go v0.1.7 // indirect
30+
github.com/google/uuid v1.6.0 // indirect
31+
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
32+
github.com/googleapis/gax-go/v2 v2.12.5 // indirect
33+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
34+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
35+
github.com/mattn/go-isatty v0.0.20 // indirect
36+
github.com/mattn/go-localereader v0.0.1 // indirect
37+
github.com/mattn/go-runewidth v0.0.15 // indirect
38+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
39+
github.com/muesli/cancelreader v0.2.2 // indirect
40+
github.com/muesli/termenv v0.15.2 // indirect
41+
github.com/rivo/uniseg v0.4.7 // indirect
42+
github.com/spf13/pflag v1.0.5 // indirect
43+
go.opencensus.io v0.24.0 // indirect
44+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 // indirect
45+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
46+
go.opentelemetry.io/otel v1.26.0 // indirect
47+
go.opentelemetry.io/otel/metric v1.26.0 // indirect
48+
go.opentelemetry.io/otel/trace v1.26.0 // indirect
49+
golang.org/x/crypto v0.24.0 // indirect
50+
golang.org/x/net v0.26.0 // indirect
51+
golang.org/x/oauth2 v0.21.0 // indirect
52+
golang.org/x/sync v0.9.0 // indirect
53+
golang.org/x/sys v0.27.0 // indirect
54+
golang.org/x/text v0.16.0 // indirect
55+
golang.org/x/time v0.5.0 // indirect
56+
google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect
57+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
58+
google.golang.org/grpc v1.64.1 // indirect
59+
google.golang.org/protobuf v1.34.2 // indirect
60+
)

0 commit comments

Comments
 (0)