initial client and helper skeletons
This commit is contained in:
parent
e5c2fae925
commit
4498f6fdf9
@ -1,11 +1,16 @@
|
||||
package cmd
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"gmgauthier.com/grokkit/internal/grok"
|
||||
)
|
||||
|
||||
var chatCmd = &cobra.Command{
|
||||
Use: "chat",
|
||||
Short: "Interactive streaming chat with Grok",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// TODO: implement
|
||||
client := grok.NewClient()
|
||||
// TODO: add history + loop (we can expand this later)
|
||||
// For now, basic streaming chat can be added in next iteration
|
||||
},
|
||||
}
|
||||
|
||||
8
go.mod
8
go.mod
@ -2,9 +2,15 @@ module gmgauthier.com/grokkit
|
||||
|
||||
go 1.24
|
||||
|
||||
require github.com/spf13/cobra v1.9.1
|
||||
require (
|
||||
github.com/fatih/color v1.18.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
)
|
||||
|
||||
11
go.sum
11
go.sum
@ -1,10 +1,21 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Run(args []string) string {
|
||||
out, _ := exec.Command("git", args...).Output()
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
|
||||
func IsRepo() bool {
|
||||
_, err := exec.Command("git", "rev-parse", "--is-inside-work-tree").Output()
|
||||
return err == nil
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package grok
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
_ "io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
APIKey string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
func NewClient() *Client {
|
||||
key := os.Getenv("XAI_API_KEY")
|
||||
if key == "" {
|
||||
color.Red("Error: XAI_API_KEY environment variable not set")
|
||||
os.Exit(1)
|
||||
}
|
||||
return &Client{
|
||||
APIKey: key,
|
||||
BaseURL: "https://api.x.ai/v1",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Stream(messages []map[string]string, model string) string {
|
||||
url := c.BaseURL + "/chat/completions"
|
||||
payload := map[string]interface{}{
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
"temperature": 0.7,
|
||||
"stream": true,
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(payload)
|
||||
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+c.APIKey)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var fullReply strings.Builder
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "data: ") {
|
||||
data := line[6:]
|
||||
if data == "[DONE]" {
|
||||
break
|
||||
}
|
||||
var chunk map[string]interface{}
|
||||
if json.Unmarshal([]byte(data), &chunk) == nil {
|
||||
if choices, ok := chunk["choices"].([]interface{}); ok && len(choices) > 0 {
|
||||
if delta, ok := choices[0].(map[string]interface{})["delta"].(map[string]interface{}); ok {
|
||||
if content, ok := delta["content"].(string); ok {
|
||||
fmt.Print(content)
|
||||
fullReply.WriteString(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
return fullReply.String()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user