Skip to content

Commit 8168275

Browse files
committed
Add chat history
1 parent 7e60c02 commit 8168275

File tree

3 files changed

+411
-0
lines changed

3 files changed

+411
-0
lines changed

cmd/chat.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import (
77
"context"
88
"fmt"
99
"os"
10+
"strconv"
11+
"strings"
1012

1113
"github.com/chand1012/ottodocs/pkg/calc"
1214
"github.com/chand1012/ottodocs/pkg/config"
15+
"github.com/chand1012/ottodocs/pkg/history"
1316
"github.com/chand1012/ottodocs/pkg/utils"
1417
l "github.com/charmbracelet/log"
1518
"github.com/sashabaranov/go-openai"
@@ -42,14 +45,175 @@ No code context is passed in this mode. Emulates web chat.`,
4245
os.Exit(1)
4346
}
4447

48+
// error if read only mode set without a history file
49+
if readOnly && loadHistory == "" {
50+
log.Error("Read only mode requires a history file. Use --history to specify a history file.")
51+
os.Exit(1)
52+
}
53+
4554
// all messages in the conversation
4655
var messages []openai.ChatCompletionMessage
56+
var fileName string // history file name
4757

4858
client := openai.NewClient(conf.APIKey)
4959

60+
if displayHistory {
61+
files, err := history.ListHistoryFiles()
62+
if err != nil {
63+
log.Error(err)
64+
os.Exit(1)
65+
}
66+
67+
if len(files) == 0 {
68+
fmt.Println("No chat history found.")
69+
os.Exit(0)
70+
}
71+
72+
for i, file := range files {
73+
// load each file
74+
historyFile, err := history.LoadHistoryFile(file)
75+
if err != nil {
76+
log.Error(err)
77+
os.Exit(1)
78+
}
79+
fmt.Printf("%d. %s\n", i, historyFile.DisplayName)
80+
}
81+
os.Exit(0)
82+
}
83+
84+
if deleteHistory != "" {
85+
if strings.HasSuffix(deleteHistory, ".json") {
86+
// load the file
87+
_, err = history.LoadHistoryFile(deleteHistory)
88+
if err != nil {
89+
log.Error(err)
90+
os.Exit(1)
91+
}
92+
} else {
93+
i, err := strconv.Atoi(deleteHistory)
94+
if err != nil {
95+
log.Error(err)
96+
os.Exit(1)
97+
}
98+
files, err := history.ListHistoryFiles()
99+
if err != nil {
100+
log.Error(err)
101+
os.Exit(1)
102+
}
103+
104+
if i >= len(files) {
105+
log.Error("Index out of bounds")
106+
os.Exit(1)
107+
}
108+
109+
// load the file
110+
_, err = history.LoadHistoryFile(files[i])
111+
if err != nil {
112+
log.Error(err)
113+
os.Exit(1)
114+
}
115+
}
116+
117+
confirm, err := utils.Input("Are you sure you want to delete this history file? (y/N): ")
118+
if err != nil {
119+
log.Error(err)
120+
os.Exit(1)
121+
}
122+
123+
confirm = strings.ToLower(confirm)
124+
if confirm != "y" {
125+
os.Exit(0)
126+
}
127+
128+
err = history.DeleteHistoryFile(deleteHistory)
129+
if err != nil {
130+
log.Error(err)
131+
os.Exit(1)
132+
}
133+
134+
fmt.Println("Deleted history file.")
135+
os.Exit(0)
136+
}
137+
138+
if clearHistory {
139+
// make sure the user wants to clear the history
140+
log.Warn("This will clear all chat history. This operation cannot be undone.")
141+
confirm, err := utils.Input("Are you sure you want to clear the chat history? (y/N): ")
142+
if err != nil {
143+
log.Error(err)
144+
os.Exit(1)
145+
}
146+
147+
confirm = strings.ToLower(confirm)
148+
149+
if confirm != "y" {
150+
os.Exit(0)
151+
}
152+
153+
err = history.ClearHistory()
154+
if err != nil {
155+
log.Error(err)
156+
os.Exit(1)
157+
}
158+
159+
fmt.Println("Cleared chat history.")
160+
os.Exit(0)
161+
}
162+
50163
utils.PrintColoredText("Otto: ", conf.OttoColor)
51164
fmt.Println("Hello! I am Otto. Use Ctrl+C to exit at any time.")
52165

166+
if loadHistory != "" {
167+
var historyFile *history.HistoryFile
168+
if strings.HasSuffix(loadHistory, ".json") {
169+
// load the file
170+
historyFile, err = history.LoadHistoryFile(loadHistory)
171+
if err != nil {
172+
log.Error(err)
173+
os.Exit(1)
174+
}
175+
} else {
176+
i, err := strconv.Atoi(loadHistory)
177+
if err != nil {
178+
log.Error(err)
179+
os.Exit(1)
180+
}
181+
files, err := history.ListHistoryFiles()
182+
if err != nil {
183+
log.Error(err)
184+
os.Exit(1)
185+
}
186+
187+
if i >= len(files) {
188+
log.Error("Index out of bounds")
189+
os.Exit(1)
190+
}
191+
192+
// load the file
193+
historyFile, err = history.LoadHistoryFile(files[i])
194+
if err != nil {
195+
log.Error(err)
196+
os.Exit(1)
197+
}
198+
}
199+
200+
messages = historyFile.Messages
201+
fileName = loadHistory
202+
203+
for _, message := range messages {
204+
if message.Role == openai.ChatMessageRoleUser {
205+
utils.PrintColoredText("You: ", conf.UserColor)
206+
} else {
207+
utils.PrintColoredText("Otto: ", conf.OttoColor)
208+
}
209+
fmt.Println(message.Content)
210+
}
211+
212+
if readOnly {
213+
os.Exit(0)
214+
}
215+
}
216+
53217
for {
54218
question, err := utils.InputWithColor("You: ", conf.UserColor)
55219
if err != nil {
@@ -110,6 +274,20 @@ No code context is passed in this mode. Emulates web chat.`,
110274
Content: completeStream,
111275
Role: openai.ChatMessageRoleAssistant,
112276
})
277+
278+
if fileName == "" {
279+
fileName, err = history.SaveInitialHistory(messages, conf)
280+
if err != nil {
281+
log.Error(err)
282+
os.Exit(1)
283+
}
284+
} else {
285+
err = history.UpdateHistoryFile(messages, fileName)
286+
if err != nil {
287+
log.Error(err)
288+
os.Exit(1)
289+
}
290+
}
113291
}
114292
},
115293
}
@@ -118,4 +296,9 @@ func init() {
118296
RootCmd.AddCommand(chatCmd)
119297

120298
chatCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
299+
chatCmd.Flags().BoolVarP(&displayHistory, "history", "H", false, "Display chat history")
300+
chatCmd.Flags().BoolVarP(&readOnly, "read", "r", false, "Read the history file and exit")
301+
chatCmd.Flags().BoolVar(&clearHistory, "clear", false, "Clear chat history")
302+
chatCmd.Flags().StringVarP(&loadHistory, "load", "l", "", "Load chat history from file. Can either be a file path or an index of the chat history")
303+
chatCmd.Flags().StringVarP(&deleteHistory, "delete", "d", "", "Delete chat history from file. Can either be a file path or an index of the chat history")
121304
}

cmd/vars.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ var currentTag string
5151

5252
var contextFiles []string
5353

54+
var displayHistory bool
55+
var loadHistory string
56+
var deleteHistory string
57+
var readOnly bool
58+
var clearHistory bool
59+
5460
var log = l.NewWithOptions(os.Stderr, l.Options{
5561
Level: l.InfoLevel,
5662
ReportTimestamp: false,

0 commit comments

Comments
 (0)