summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrail Finder <wohilas@gmail.com>2024-11-16 16:19:27 +0300
committerGrail Finder <wohilas@gmail.com>2024-11-16 16:19:27 +0300
commitb2c86989264f329bcd102eee7de5d91649643215 (patch)
tree133f3cbac06534846544236e6177ec69a526ba7d
parent1fe807de8eff13c41c8c7dd1dd6f4c4efca21244 (diff)
Feat: add msg index
-rw-r--r--README.md14
-rw-r--r--bot.go5
-rw-r--r--main.go57
-rw-r--r--models/models.go10
4 files changed, 64 insertions, 22 deletions
diff --git a/README.md b/README.md
index 167f8df..e918dee 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
### TODO:
-- scrolling chat history; (somewhat works out of box);
-- log errors to file;
-- give serial id to each msg in chat to track it;
-- regen last message;
-- delete last message
+- scrolling chat history; (somewhat works out of box); +
+- log errors to file; +
+- give serial id to each msg in chat to track it; (use slice index) +
+- show msg id next to the msg; +
+- regen last message; +
+- delete last message; +
- edit message? (including from bot);
- use chatml template (but do not show it to the user);
-- use mistral template;
- ability to copy message;
- aility to copy selected text;
-- menu with old chats (chat files);
+- menu with old chats (chat files); +
diff --git a/bot.go b/bot.go
index 5522a20..8a09e24 100644
--- a/bot.go
+++ b/bot.go
@@ -162,6 +162,7 @@ func chatRound(userMsg, role string, tv *tview.TextView) {
botRespMode = true
reader := formMsg(chatBody, userMsg, role)
go sendMsgToLLM(reader)
+ fmt.Fprintf(tv, fmt.Sprintf("(%d) ", len(chatBody.Messages)))
fmt.Fprintf(tv, assistantIcon)
respText := strings.Builder{}
out:
@@ -171,6 +172,7 @@ out:
// fmt.Printf(chunk)
fmt.Fprintf(tv, chunk)
respText.WriteString(chunk)
+ tv.ScrollToEnd()
case <-streamDone:
break out
}
@@ -179,7 +181,6 @@ out:
chatBody.Messages = append(chatBody.Messages, models.MessagesStory{
Role: assistantRole, Content: respText.String(),
})
- // TODO:
// bot msg is done;
// now check it for func call
logChat(chatFileLoaded, chatBody.Messages)
@@ -299,7 +300,7 @@ func chatToTextSlice(showSys bool) []string {
if !showSys && (msg.Role != assistantRole && msg.Role != userRole) {
continue
}
- resp[i] = msg.ToText()
+ resp[i] = msg.ToText(i)
}
return resp
}
diff --git a/main.go b/main.go
index 65d5378..672c02a 100644
--- a/main.go
+++ b/main.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"path"
+ "strconv"
"time"
"unicode"
@@ -11,10 +12,11 @@ import (
)
var (
- normalMode = false
- botRespMode = false
- botMsg = "no"
- indexLine = "Row: [yellow]%d[white], Column: [yellow]%d; normal mode: %v"
+ normalMode = false
+ botRespMode = false
+ botMsg = "no"
+ selectedIndex = int(-1)
+ indexLine = "manage chats: F1; regen last: F2; delete msg menu: F3; Row: [yellow]%d[white], Column: [yellow]%d; normal mode: %v"
)
func isASCII(s string) bool {
@@ -51,7 +53,7 @@ func main() {
if fromRow == toRow && fromColumn == toColumn {
position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, normalMode))
} else {
- 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))
+ position.SetText(fmt.Sprintf("manage chats: F1; regen last: F2; delete msg menu: F3; [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"}
@@ -60,7 +62,7 @@ func main() {
panic(err)
}
chatOpts = append(chatOpts, fList...)
- modal := tview.NewModal().
+ chatActModal := tview.NewModal().
SetText("Chat actions:").
AddButtons(chatOpts).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
@@ -93,9 +95,29 @@ func main() {
return
}
})
+ indexPickWindow := tview.NewInputField().
+ SetLabel("Enter a msg index: ").
+ SetFieldWidth(4).
+ SetAcceptanceFunc(tview.InputFieldInteger).
+ SetDoneFunc(func(key tcell.Key) {
+ pages.RemovePage("getIndex")
+ return
+ })
+ indexPickWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ if event.Key() == tcell.KeyEnter {
+ si := indexPickWindow.GetText()
+ selectedIndex, err = strconv.Atoi(si)
+ if err != nil {
+ logger.Error("failed to convert provided index", "error", err, "si", si)
+ }
+ }
+ return event
+ })
+ //
textArea.SetMovedFunc(updateStatusLine)
updateStatusLine()
textView.SetText(chatToText(showSystemMsgs))
+ textView.ScrollToEnd()
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if botRespMode {
// do nothing while bot typing
@@ -107,17 +129,36 @@ func main() {
panic(err)
}
chatOpts = append(chatOpts, fList...)
- pages.AddPage("history", modal, true, true)
+ pages.AddPage("history", chatActModal, true, true)
return nil
}
+ if event.Key() == tcell.KeyF2 {
+ // regen last msg
+ chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
+ textView.SetText(chatToText(showSystemMsgs))
+ go chatRound("", userRole, textView)
+ return nil
+ }
+ if event.Key() == tcell.KeyF3 {
+ // TODO: delete last n messages
+ // modal window with input field
+ chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
+ textView.SetText(chatToText(showSystemMsgs))
+ return nil
+ }
+ if event.Key() == tcell.KeyF4 {
+ // edit msg
+ pages.AddPage("getIndex", indexPickWindow, true, true)
+ }
if event.Key() == tcell.KeyEscape {
fromRow, fromColumn, _, _ := textArea.GetCursor()
position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, normalMode))
// read all text into buffer
msgText := textArea.GetText()
if msgText != "" {
- fmt.Fprintf(textView, "\n<user>: %s\n", msgText)
+ fmt.Fprintf(textView, "\n(%d) <user>: %s\n", len(chatBody.Messages), msgText)
textArea.SetText("", true)
+ textView.ScrollToEnd()
}
// update statue line
go chatRound(msgText, userRole, textView)
diff --git a/models/models.go b/models/models.go
index 30ba548..880779f 100644
--- a/models/models.go
+++ b/models/models.go
@@ -61,17 +61,17 @@ type MessagesStory struct {
Content string `json:"content"`
}
-func (m MessagesStory) ToText() string {
+func (m MessagesStory) ToText(i int) string {
icon := ""
switch m.Role {
case "assistant":
- icon = "<🤖>: "
+ icon = fmt.Sprintf("(%d) <🤖>: ", i)
case "user":
- icon = "<user>: "
+ icon = fmt.Sprintf("(%d) <user>: ", i)
case "system":
- icon = "<system>: "
+ icon = fmt.Sprintf("(%d) <system>: ", i)
case "tool":
- icon = "<tool>: "
+ icon = fmt.Sprintf("(%d) <tool>: ", i)
}
textMsg := fmt.Sprintf("%s%s\n", icon, m.Content)
return strings.ReplaceAll(textMsg, "\n\n", "\n")