grokkit/cmd/chat.go

125 lines
3.4 KiB
Go
Raw Normal View History

2026-02-28 18:03:12 +00:00
package cmd
2026-02-28 18:28:27 +00:00
2026-02-28 18:41:20 +00:00
import (
"bufio"
"encoding/json"
"fmt"
2026-02-28 19:56:23 +00:00
"os"
"path/filepath"
2026-02-28 19:56:23 +00:00
"strings"
"github.com/fatih/color"
2026-02-28 18:41:20 +00:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gmgauthier.com/grokkit/config"
2026-02-28 18:41:20 +00:00
"gmgauthier.com/grokkit/internal/grok"
)
2026-02-28 18:28:27 +00:00
type ChatHistory struct {
Messages []map[string]string `json:"messages"`
}
func loadChatHistory() []map[string]string {
histFile := getChatHistoryFile()
data, err := os.ReadFile(histFile)
if err != nil {
return nil
}
var hist ChatHistory
if err := json.Unmarshal(data, &hist); err != nil {
return nil
}
return hist.Messages
}
func saveChatHistory(messages []map[string]string) error {
histFile := getChatHistoryFile()
hist := ChatHistory{Messages: messages}
data, err := json.MarshalIndent(hist, "", " ")
if err != nil {
return err
}
return os.WriteFile(histFile, data, 0644)
}
func getChatHistoryFile() string {
configFile := viper.GetString("chat.history_file")
if configFile != "" {
return configFile
}
home, _ := os.UserHomeDir()
if home == "" {
home = "."
}
histDir := filepath.Join(home, ".config", "grokkit")
_ = os.MkdirAll(histDir, 0755) // Ignore error, WriteFile will catch it
return filepath.Join(histDir, "chat_history.json")
}
var chatCmd = &cobra.Command{
Use: "chat",
Short: "Simple interactive CLI chat with Grok (full history + streaming)",
Run: func(cmd *cobra.Command, args []string) {
modelFlag, _ := cmd.Flags().GetString("model")
model := config.GetModel(modelFlag)
client := grok.NewClient()
// Strong system prompt to lock in correct model identity
systemPrompt := map[string]string{
"role": "system",
"content": fmt.Sprintf("You are Grok 4, the latest and most powerful model from xAI (2026). You are currently running as `%s`. Be helpful, truthful, and a little irreverent. Never claim to be an older model.", model),
}
// Load history or start fresh
history := loadChatHistory()
if history == nil {
history = []map[string]string{systemPrompt}
} else {
// Update system prompt in loaded history
if len(history) > 0 && history[0]["role"] == "system" {
history[0] = systemPrompt
} else {
history = append([]map[string]string{systemPrompt}, history...)
}
}
color.Cyan("┌──────────────────────────────────────────────────────────────┐")
color.Cyan("│ Grokkit Chat — Model: %s │", model)
color.Cyan("│ Type /quit or Ctrl+C to exit │")
color.Cyan("└──────────────────────────────────────────────────────────────┘\n")
scanner := bufio.NewScanner(os.Stdin)
for {
color.Yellow("You > ")
if !scanner.Scan() {
break
}
input := strings.TrimSpace(scanner.Text())
if input == "" {
continue
2026-02-28 19:56:23 +00:00
}
if input == "/quit" || input == "/q" || input == "exit" {
color.Cyan("\nGoodbye 👋\n")
break
2026-02-28 19:56:23 +00:00
}
history = append(history, map[string]string{"role": "user", "content": input})
color.Green("Grok > ")
reply := client.Stream(history, model)
history = append(history, map[string]string{"role": "assistant", "content": reply})
// Save history after each exchange
_ = saveChatHistory(history)
fmt.Println()
}
},
}