summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrail Finder <wohilas@gmail.com>2024-11-16 14:01:11 +0300
committerGrail Finder <wohilas@gmail.com>2024-11-16 14:01:11 +0300
commit1fe807de8eff13c41c8c7dd1dd6f4c4efca21244 (patch)
tree351eebc7b9af1bed792e7b25d5d59d9b9862af9e
parent84b06c0da5854f153aa31b668f60914e4bb74fc5 (diff)
Feat: add modal window to choose chat file to load
-rw-r--r--bot.go59
-rw-r--r--main.go64
2 files changed, 96 insertions, 27 deletions
diff --git a/bot.go b/bot.go
index 09d3e62..5522a20 100644
--- a/bot.go
+++ b/bot.go
@@ -10,6 +10,7 @@ import (
"log/slog"
"net/http"
"os"
+ "path"
"strings"
"time"
@@ -21,14 +22,18 @@ var httpClient = http.Client{
}
var (
- logger *slog.Logger
- APIURL = "http://localhost:8080/v1/chat/completions"
- DB = map[string]map[string]any{}
- userRole = "user"
- assistantRole = "assistant"
- toolRole = "tool"
- assistantIcon = "<🤖>: "
- userIcon = "<user>: "
+ logger *slog.Logger
+ APIURL = "http://localhost:8080/v1/chat/completions"
+ DB = map[string]map[string]any{}
+ userRole = "user"
+ assistantRole = "assistant"
+ toolRole = "tool"
+ assistantIcon = "<🤖>: "
+ userIcon = "<user>: "
+ historyDir = "./history/"
+ // TODO: pass as an cli arg
+ showSystemMsgs bool
+ chatFileLoaded string
chunkChan = make(chan string, 10)
streamDone = make(chan bool, 1)
chatBody *models.ChatBody
@@ -177,7 +182,7 @@ out:
// TODO:
// bot msg is done;
// now check it for func call
- logChat("testlog", chatBody.Messages)
+ logChat(chatFileLoaded, chatBody.Messages)
findCall(respText.String(), tv)
}
@@ -220,11 +225,22 @@ func findCall(msg string, tv *tview.TextView) {
// return func result to the llm
}
-func findLatestChat() string {
- dir := "./history/"
+func listHistoryFiles(dir string) ([]string, error) {
files, err := os.ReadDir(dir)
if err != nil {
logger.Error("failed to readdir", "error", err)
+ return nil, err
+ }
+ resp := make([]string, len(files))
+ for i, f := range files {
+ resp[i] = path.Join(dir, f.Name())
+ }
+ return resp, nil
+}
+
+func findLatestChat(dir string) string {
+ files, err := listHistoryFiles(dir)
+ if err != nil {
panic(err)
}
var (
@@ -232,16 +248,16 @@ func findLatestChat() string {
newestTime int64
)
logger.Info("filelist", "list", files)
- for _, f := range files {
- fi, err := os.Stat(dir + f.Name())
+ for _, fn := range files {
+ fi, err := os.Stat(fn)
if err != nil {
- logger.Error("failed to get stat", "error", err, "name", f.Name())
+ logger.Error("failed to get stat", "error", err, "name", fn)
panic(err)
}
currTime := fi.ModTime().Unix()
if currTime > newestTime {
newestTime = currTime
- latestF = f.Name()
+ latestF = fn
}
}
return latestF
@@ -258,12 +274,13 @@ func readHistoryChat(fn string) ([]models.MessagesStory, error) {
logger.Error("failed to unmarshal", "error", err, "name", fn)
return nil, err
}
+ chatFileLoaded = fn
return resp, nil
}
func loadOldChatOrGetNew(fns ...string) []models.MessagesStory {
// find last chat
- fn := findLatestChat()
+ fn := findLatestChat(historyDir)
if len(fns) > 0 {
fn = fns[0]
}
@@ -276,14 +293,22 @@ func loadOldChatOrGetNew(fns ...string) []models.MessagesStory {
return history
}
-func chatToText() []string {
+func chatToTextSlice(showSys bool) []string {
resp := make([]string, len(chatBody.Messages))
for i, msg := range chatBody.Messages {
+ if !showSys && (msg.Role != assistantRole && msg.Role != userRole) {
+ continue
+ }
resp[i] = msg.ToText()
}
return resp
}
+func chatToText(showSys bool) string {
+ s := chatToTextSlice(showSys)
+ return strings.Join(s, "")
+}
+
func textToChat(chat []string) []models.MessagesStory {
resp := make([]models.MessagesStory, len(chat))
for i, rawMsg := range chat {
diff --git a/main.go b/main.go
index 472945f..65d5378 100644
--- a/main.go
+++ b/main.go
@@ -2,7 +2,8 @@ package main
import (
"fmt"
- "strings"
+ "path"
+ "time"
"unicode"
"github.com/gdamore/tcell/v2"
@@ -27,6 +28,7 @@ func isASCII(s string) bool {
func main() {
app := tview.NewApplication()
+ pages := tview.NewPages()
textArea := tview.NewTextArea().
SetPlaceholder("Type your prompt...")
textArea.SetBorder(true).SetTitle("input")
@@ -52,21 +54,62 @@ func main() {
position.SetText(fmt.Sprintf("[red]From[white] Row: [yellow]%d[white], Column: [yellow]%d[white] - [red]To[white] Row: [yellow]%d[white], To Column: [yellow]%d; normal mode: %v", fromRow, fromColumn, toRow, toColumn, normalMode))
}
}
+ chatOpts := []string{"cancel", "new"}
+ fList, err := listHistoryFiles(historyDir)
+ if err != nil {
+ panic(err)
+ }
+ chatOpts = append(chatOpts, fList...)
+ modal := tview.NewModal().
+ SetText("Chat actions:").
+ AddButtons(chatOpts).
+ SetDoneFunc(func(buttonIndex int, buttonLabel string) {
+ switch buttonLabel {
+ case "new":
+ // set chat body
+ chatBody.Messages = defaultStarter
+ textView.SetText(chatToText(showSystemMsgs))
+ chatFileLoaded = path.Join(historyDir, fmt.Sprintf("%d_chat.json", time.Now().Unix()))
+ pages.RemovePage("history")
+ return
+ // set text
+ case "cancel":
+ pages.RemovePage("history")
+ // pages.ShowPage("main")
+ return
+ default:
+ // fn := path.Join(historyDir, buttonLabel)
+ fn := buttonLabel
+ history, err := readHistoryChat(fn)
+ if err != nil {
+ logger.Error("failed to read history file", "filename", fn)
+ pages.RemovePage("history")
+ return
+ }
+ chatBody.Messages = history
+ textView.SetText(chatToText(showSystemMsgs))
+ chatFileLoaded = fn
+ pages.RemovePage("history")
+ return
+ }
+ })
textArea.SetMovedFunc(updateStatusLine)
updateStatusLine()
- history := chatToText()
- chatHistory := strings.Builder{}
- for _, m := range history {
- chatHistory.WriteString(m)
- // textView.SetText(m)
- }
- textView.SetText(chatHistory.String())
- // textView.SetText("<🤖>: Hello! What can I do for you?")
+ textView.SetText(chatToText(showSystemMsgs))
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if botRespMode {
// do nothing while bot typing
return nil
}
+ if event.Key() == tcell.KeyF1 {
+ fList, err := listHistoryFiles(historyDir)
+ if err != nil {
+ panic(err)
+ }
+ chatOpts = append(chatOpts, fList...)
+ pages.AddPage("history", modal, true, true)
+ return nil
+ }
if event.Key() == tcell.KeyEscape {
fromRow, fromColumn, _, _ := textArea.GetCursor()
position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, normalMode))
@@ -88,7 +131,8 @@ func main() {
}
return event
})
- if err := app.SetRoot(flex,
+ pages.AddPage("main", flex, true, true)
+ if err := app.SetRoot(pages,
true).EnableMouse(true).Run(); err != nil {
panic(err)
}