summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--main.go249
-rw-r--r--session.go1
-rw-r--r--storage/memory.go4
-rw-r--r--storage/storage.go8
-rw-r--r--tui.go311
6 files changed, 327 insertions, 249 deletions
diff --git a/README.md b/README.md
index 7736358..cfbe3a5 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
- consider adding use /completion of llamacpp, since openai endpoint clearly has template|format issues;
- change temp, min-p and other params from tui;
- help page with all key bindings;
+- rename current chat;
### FIX:
- bot responding (or haninging) blocks everything; +
@@ -30,4 +31,4 @@
- empty input to continue bot msg gens new msg index and bot icon;
- sometimes bots put additional info around the tool call, have a regexp to match tool call; +
- remove all panics from code; +
-- new chat is not saved in db;
+- new chat replaces old ones in db;
diff --git a/main.go b/main.go
index e8f9f3a..46cb42c 100644
--- a/main.go
+++ b/main.go
@@ -1,13 +1,8 @@
package main
import (
- "elefant/models"
- "fmt"
- "strconv"
- "time"
"unicode"
- "github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@@ -16,7 +11,7 @@ var (
editMode = false
botMsg = "no"
selectedIndex = int(-1)
- indexLine = "Esc: send msg; PgUp/Down: switch focus; F1: manage chats; F2: regen last; F3:delete last msg; F4: edit msg; F5: toggle system; F6: interrupt bot resp; Row: [yellow]%d[white], Column: [yellow]%d; bot resp mode: %v"
+ indexLine = "Esc: send msg; PgUp/Down: switch focus; F1: manage chats; F2: regen last; F3:delete last msg; F4: edit msg; F5: toggle system; F6: interrupt bot resp; bot resp mode: %v; current chat: %s"
focusSwitcher = map[tview.Primitive]tview.Primitive{}
)
@@ -30,248 +25,6 @@ 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")
- textView := tview.NewTextView().
- SetDynamicColors(true).
- SetRegions(true).
- SetChangedFunc(func() {
- app.Draw()
- })
- textView.SetBorder(true).SetTitle("chat")
- focusSwitcher[textArea] = textView
- focusSwitcher[textView] = textArea
- position := tview.NewTextView().
- SetDynamicColors(true).
- SetTextAlign(tview.AlignCenter)
- flex := tview.NewFlex().SetDirection(tview.FlexRow).
- AddItem(textView, 0, 40, false).
- AddItem(textArea, 0, 10, true).
- AddItem(position, 0, 1, false)
- updateStatusLine := func() {
- fromRow, fromColumn, toRow, toColumn := textArea.GetCursor()
- if fromRow == toRow && fromColumn == toColumn {
- position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, botRespMode))
- } else {
- position.SetText(fmt.Sprintf("Esc: send msg; PgUp/Down: switch focus; F1: manage chats; F2: regen last; F3:delete last msg; F4: edit msg; F5: toggle system; F6: interrupt bot resp; Row: [yellow]%d[white], Column: [yellow]%d[white] - [red]To[white] Row: [yellow]%d[white], To Column: [yellow]%d; bot resp mode: %v", fromRow, fromColumn, toRow, toColumn, botRespMode))
- }
- }
- chatOpts := []string{"cancel", "new"}
- fList, err := loadHistoryChats()
- if err != nil {
- logger.Error("failed to load chat history", "error", err)
- }
- chatOpts = append(chatOpts, fList...)
- chatActModal := 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))
- newChat := &models.Chat{
- Name: fmt.Sprintf("%v_%v", "new", time.Now().Unix()),
- Msgs: string(defaultStarterBytes),
- }
- // activeChatName = path.Join(historyDir, fmt.Sprintf("%d_chat.json", time.Now().Unix()))
- activeChatName = newChat.Name
- chatMap[newChat.Name] = newChat
- pages.RemovePage("history")
- return
- // set text
- case "cancel":
- pages.RemovePage("history")
- return
- default:
- fn := buttonLabel
- history, err := loadHistoryChat(fn)
- if err != nil {
- logger.Error("failed to read history file", "filename", fn)
- pages.RemovePage("history")
- return
- }
- chatBody.Messages = history
- textView.SetText(chatToText(showSystemMsgs))
- activeChatName = fn
- pages.RemovePage("history")
- return
- }
- })
- sysModal := tview.NewModal().
- SetText("Switch sys msg:").
- AddButtons(sysLabels).
- SetDoneFunc(func(buttonIndex int, buttonLabel string) {
- switch buttonLabel {
- case "cancel":
- pages.RemovePage("sys")
- return
- default:
- sysMsg, ok := sysMap[buttonLabel]
- if !ok {
- logger.Warn("no such sys msg", "name", buttonLabel)
- pages.RemovePage("sys")
- return
- }
- chatBody.Messages[0].Content = sysMsg
- // replace textview
- textView.SetText(chatToText(showSystemMsgs))
- pages.RemovePage("sys")
- }
- })
- editArea := tview.NewTextArea().
- SetPlaceholder("Replace msg...")
- editArea.SetBorder(true).SetTitle("input")
- editArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
- if event.Key() == tcell.KeyEscape && editMode {
- editedMsg := editArea.GetText()
- if editedMsg == "" {
- notifyUser("edit", "no edit provided")
- pages.RemovePage("editArea")
- editMode = false
- return nil
- }
- chatBody.Messages[selectedIndex].Content = editedMsg
- // change textarea
- textView.SetText(chatToText(showSystemMsgs))
- pages.RemovePage("editArea")
- editMode = false
- return nil
- }
- return event
- })
- 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 {
- si := indexPickWindow.GetText()
- selectedIndex, err = strconv.Atoi(si)
- if err != nil {
- logger.Error("failed to convert provided index", "error", err, "si", si)
- }
- if len(chatBody.Messages) <= selectedIndex && selectedIndex < 0 {
- logger.Warn("chosen index is out of bounds", "index", selectedIndex)
- return nil
- }
- m := chatBody.Messages[selectedIndex]
- if editMode && event.Key() == tcell.KeyEnter {
- pages.AddPage("editArea", editArea, true, true)
- editArea.SetText(m.Content, true)
- }
- if !editMode && event.Key() == tcell.KeyEnter {
- copyToClipboard(m.Content)
- notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
- notifyUser("copied", notification)
- }
- return event
- })
- //
- textArea.SetMovedFunc(updateStatusLine)
- updateStatusLine()
- textView.SetText(chatToText(showSystemMsgs))
- textView.ScrollToEnd()
- app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
- if event.Key() == tcell.KeyF1 {
- fList, err := loadHistoryChats()
- if err != nil {
- logger.Error("failed to load chat history", "error", err)
- return nil
- }
- chatOpts = append(chatOpts, fList...)
- 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 {
- // delete last msg
- chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
- textView.SetText(chatToText(showSystemMsgs))
- botRespMode = false // hmmm; is that correct?
- return nil
- }
- if event.Key() == tcell.KeyF4 {
- // edit msg
- editMode = true
- pages.AddPage("getIndex", indexPickWindow, true, true)
- return nil
- }
- if event.Key() == tcell.KeyF5 {
- // switch showSystemMsgs
- showSystemMsgs = !showSystemMsgs
- textView.SetText(chatToText(showSystemMsgs))
- }
- if event.Key() == tcell.KeyF6 {
- interruptResp = true
- botRespMode = false
- return nil
- }
- if event.Key() == tcell.KeyF7 {
- // copy msg to clipboard
- editMode = false
- m := chatBody.Messages[len(chatBody.Messages)-1]
- copyToClipboard(m.Content)
- notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
- notifyUser("copied", notification)
- return nil
- }
- if event.Key() == tcell.KeyF8 {
- // copy msg to clipboard
- editMode = false
- pages.AddPage("getIndex", indexPickWindow, true, true)
- return nil
- }
- if event.Key() == tcell.KeyCtrlE {
- textArea.SetText("pressed ctrl+e", true)
- return nil
- }
- if event.Key() == tcell.KeyCtrlS {
- // switch sys prompt
- pages.AddPage("sys", sysModal, true, true)
- return nil
- }
- // cannot send msg in editMode or botRespMode
- if event.Key() == tcell.KeyEscape && !editMode && !botRespMode {
- fromRow, fromColumn, _, _ := textArea.GetCursor()
- position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, botRespMode))
- // read all text into buffer
- msgText := textArea.GetText()
- if 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)
- return nil
- }
- if event.Key() == tcell.KeyPgUp || event.Key() == tcell.KeyPgDn {
- currentF := app.GetFocus()
- app.SetFocus(focusSwitcher[currentF])
- return nil
- }
- if isASCII(string(event.Rune())) && !botRespMode {
- // botRespMode = false
- // fromRow, fromColumn, _, _ := textArea.GetCursor()
- // position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, botRespMode))
- return event
- }
- return event
- })
pages.AddPage("main", flex, true, true)
if err := app.SetRoot(pages,
true).EnableMouse(true).Run(); err != nil {
diff --git a/session.go b/session.go
index 23d725d..7c035fa 100644
--- a/session.go
+++ b/session.go
@@ -37,6 +37,7 @@ func updateStorageChat(name string, msgs []models.MessagesStory) error {
return err
}
chat.UpdatedAt = time.Now()
+ // if new chat will create id
_, err = store.UpsertChat(chat)
return err
}
diff --git a/storage/memory.go b/storage/memory.go
index a7bf8cc..088ce1c 100644
--- a/storage/memory.go
+++ b/storage/memory.go
@@ -12,12 +12,14 @@ func (p ProviderSQL) Memorise(m *models.Memory) (*models.Memory, error) {
query := "INSERT INTO memories (agent, topic, mind) VALUES (:agent, :topic, :mind) RETURNING *;"
stmt, err := p.db.PrepareNamed(query)
if err != nil {
+ p.logger.Error("failed to prepare stmt", "query", query, "error", err)
return nil, err
}
defer stmt.Close()
var memory models.Memory
err = stmt.Get(&memory, m)
if err != nil {
+ p.logger.Error("failed to insert memory", "query", query, "error", err)
return nil, err
}
return &memory, nil
@@ -28,6 +30,7 @@ func (p ProviderSQL) Recall(agent, topic string) (string, error) {
var mind string
err := p.db.Get(&mind, query, agent, topic)
if err != nil {
+ p.logger.Error("failed to get memory", "query", query, "error", err)
return "", err
}
return mind, nil
@@ -38,6 +41,7 @@ func (p ProviderSQL) RecallTopics(agent string) ([]string, error) {
var topics []string
err := p.db.Select(&topics, query, agent)
if err != nil {
+ p.logger.Error("failed to get topics", "query", query, "error", err)
return nil, err
}
return topics, nil
diff --git a/storage/storage.go b/storage/storage.go
index 08cd81a..c863799 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -19,6 +19,7 @@ type ChatHistory interface {
GetLastChat() (*models.Chat, error)
UpsertChat(chat *models.Chat) (*models.Chat, error)
RemoveChat(id uint32) error
+ ChatGetMaxID() (uint32, error)
}
type ProviderSQL struct {
@@ -66,6 +67,13 @@ func (p ProviderSQL) RemoveChat(id uint32) error {
return err
}
+func (p ProviderSQL) ChatGetMaxID() (uint32, error) {
+ query := "SELECT MAX(id) FROM chats;"
+ var id uint32
+ err := p.db.Get(&id, query)
+ return id, err
+}
+
func NewProviderSQL(dbPath string, logger *slog.Logger) FullRepo {
db, err := sqlx.Open("sqlite", dbPath)
if err != nil {
diff --git a/tui.go b/tui.go
new file mode 100644
index 0000000..ba12e6d
--- /dev/null
+++ b/tui.go
@@ -0,0 +1,311 @@
+package main
+
+import (
+ "elefant/models"
+ "fmt"
+ "strconv"
+ "time"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/rivo/tview"
+)
+
+var (
+ app *tview.Application
+ pages *tview.Pages
+ textArea *tview.TextArea
+ editArea *tview.TextArea
+ textView *tview.TextView
+ position *tview.TextView
+ flex *tview.Flex
+ chatActModal *tview.Modal
+ sysModal *tview.Modal
+ indexPickWindow *tview.InputField
+ renameWindow *tview.InputField
+)
+
+func init() {
+ app = tview.NewApplication()
+ pages = tview.NewPages()
+ textArea = tview.NewTextArea().
+ SetPlaceholder("Type your prompt...")
+ textArea.SetBorder(true).SetTitle("input")
+ textView = tview.NewTextView().
+ SetDynamicColors(true).
+ SetRegions(true).
+ SetChangedFunc(func() {
+ app.Draw()
+ })
+ textView.SetBorder(true).SetTitle("chat")
+ focusSwitcher[textArea] = textView
+ focusSwitcher[textView] = textArea
+ position = tview.NewTextView().
+ SetDynamicColors(true).
+ SetTextAlign(tview.AlignCenter)
+ flex = tview.NewFlex().SetDirection(tview.FlexRow).
+ AddItem(textView, 0, 40, false).
+ AddItem(textArea, 0, 10, true).
+ AddItem(position, 0, 1, false)
+ updateStatusLine := func() {
+ fromRow, fromColumn, toRow, toColumn := textArea.GetCursor()
+ if fromRow == toRow && fromColumn == toColumn {
+ position.SetText(fmt.Sprintf(indexLine, botRespMode, activeChatName))
+ } else {
+ position.SetText(fmt.Sprintf("Esc: send msg; PgUp/Down: switch focus; F1: manage chats; F2: regen last; F3:delete last msg; F4: edit msg; F5: toggle system; F6: interrupt bot resp; Row: [yellow]%d[white], Column: [yellow]%d[white] - [red]To[white] Row: [yellow]%d[white], To Column: [yellow]%d; bot resp mode: %v", fromRow, fromColumn, toRow, toColumn, botRespMode))
+ }
+ }
+ chatOpts := []string{"cancel", "new", "rename current"}
+ chatList, err := loadHistoryChats()
+ if err != nil {
+ logger.Error("failed to load chat history", "error", err)
+ chatList = []string{}
+ }
+ chatActModal := tview.NewModal().
+ SetText("Chat actions:").
+ AddButtons(append(chatOpts, chatList...)).
+ SetDoneFunc(func(buttonIndex int, buttonLabel string) {
+ switch buttonLabel {
+ case "new":
+ id, err := store.ChatGetMaxID()
+ if err != nil {
+ logger.Error("failed to get chat id", "error", err)
+ }
+ // set chat body
+ chatBody.Messages = defaultStarter
+ textView.SetText(chatToText(showSystemMsgs))
+ newChat := &models.Chat{
+ ID: id,
+ Name: fmt.Sprintf("%v_%v", "new", time.Now().Unix()),
+ Msgs: string(defaultStarterBytes),
+ }
+ // activeChatName = path.Join(historyDir, fmt.Sprintf("%d_chat.json", time.Now().Unix()))
+ activeChatName = newChat.Name
+ chatMap[newChat.Name] = newChat
+ pages.RemovePage("history")
+ return
+ // set text
+ case "cancel":
+ pages.RemovePage("history")
+ return
+ case "rename current":
+ // add input field
+ pages.RemovePage("history")
+ pages.AddPage("renameW", renameWindow, true, true)
+ return
+ default:
+ fn := buttonLabel
+ history, err := loadHistoryChat(fn)
+ if err != nil {
+ logger.Error("failed to read history file", "chat", fn)
+ pages.RemovePage("history")
+ return
+ }
+ chatBody.Messages = history
+ textView.SetText(chatToText(showSystemMsgs))
+ activeChatName = fn
+ pages.RemovePage("history")
+ return
+ }
+ })
+ sysModal = tview.NewModal().
+ SetText("Switch sys msg:").
+ AddButtons(sysLabels).
+ SetDoneFunc(func(buttonIndex int, buttonLabel string) {
+ switch buttonLabel {
+ case "cancel":
+ pages.RemovePage("sys")
+ return
+ default:
+ sysMsg, ok := sysMap[buttonLabel]
+ if !ok {
+ logger.Warn("no such sys msg", "name", buttonLabel)
+ pages.RemovePage("sys")
+ return
+ }
+ chatBody.Messages[0].Content = sysMsg
+ // replace textview
+ textView.SetText(chatToText(showSystemMsgs))
+ pages.RemovePage("sys")
+ }
+ })
+ editArea = tview.NewTextArea().
+ SetPlaceholder("Replace msg...")
+ editArea.SetBorder(true).SetTitle("input")
+ editArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ if event.Key() == tcell.KeyEscape && editMode {
+ editedMsg := editArea.GetText()
+ if editedMsg == "" {
+ notifyUser("edit", "no edit provided")
+ pages.RemovePage("editArea")
+ editMode = false
+ return nil
+ }
+ chatBody.Messages[selectedIndex].Content = editedMsg
+ // change textarea
+ textView.SetText(chatToText(showSystemMsgs))
+ pages.RemovePage("editArea")
+ editMode = false
+ return nil
+ }
+ return event
+ })
+ 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 {
+ si := indexPickWindow.GetText()
+ selectedIndex, err = strconv.Atoi(si)
+ if err != nil {
+ logger.Error("failed to convert provided index", "error", err, "si", si)
+ }
+ if len(chatBody.Messages) <= selectedIndex && selectedIndex < 0 {
+ logger.Warn("chosen index is out of bounds", "index", selectedIndex)
+ return nil
+ }
+ m := chatBody.Messages[selectedIndex]
+ if editMode && event.Key() == tcell.KeyEnter {
+ pages.AddPage("editArea", editArea, true, true)
+ editArea.SetText(m.Content, true)
+ }
+ if !editMode && event.Key() == tcell.KeyEnter {
+ copyToClipboard(m.Content)
+ notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
+ notifyUser("copied", notification)
+ }
+ return event
+ })
+ //
+ renameWindow = tview.NewInputField().
+ SetLabel("Enter a msg index: ").
+ SetFieldWidth(20).
+ SetAcceptanceFunc(tview.InputFieldMaxLength(100)).
+ SetDoneFunc(func(key tcell.Key) {
+ pages.RemovePage("renameW")
+ return
+ })
+ renameWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ if event.Key() == tcell.KeyEnter {
+ nname := renameWindow.GetText()
+ if nname == "" {
+ return event
+ }
+ currentChat := chatMap[activeChatName]
+ delete(chatMap, activeChatName)
+ currentChat.Name = nname
+ activeChatName = nname
+ chatMap[activeChatName] = currentChat
+ _, err := store.UpsertChat(currentChat)
+ if err != nil {
+ logger.Error("failed to upsert chat", "error", err, "chat", currentChat)
+ }
+ notification := fmt.Sprintf("renamed chat to '%s'", activeChatName)
+ notifyUser("renamed", notification)
+ }
+ return event
+ })
+ //
+ textArea.SetMovedFunc(updateStatusLine)
+ updateStatusLine()
+ textView.SetText(chatToText(showSystemMsgs))
+ textView.ScrollToEnd()
+ app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ if event.Key() == tcell.KeyF1 {
+ chatList, err := loadHistoryChats()
+ if err != nil {
+ logger.Error("failed to load chat history", "error", err)
+ return nil
+ }
+ chatOpts := append(chatOpts, chatList...)
+ chatActModal.ClearButtons()
+ chatActModal.AddButtons(chatOpts)
+ 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 {
+ // delete last msg
+ chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
+ textView.SetText(chatToText(showSystemMsgs))
+ botRespMode = false // hmmm; is that correct?
+ return nil
+ }
+ if event.Key() == tcell.KeyF4 {
+ // edit msg
+ editMode = true
+ pages.AddPage("getIndex", indexPickWindow, true, true)
+ return nil
+ }
+ if event.Key() == tcell.KeyF5 {
+ // switch showSystemMsgs
+ showSystemMsgs = !showSystemMsgs
+ textView.SetText(chatToText(showSystemMsgs))
+ }
+ if event.Key() == tcell.KeyF6 {
+ interruptResp = true
+ botRespMode = false
+ return nil
+ }
+ if event.Key() == tcell.KeyF7 {
+ // copy msg to clipboard
+ editMode = false
+ m := chatBody.Messages[len(chatBody.Messages)-1]
+ copyToClipboard(m.Content)
+ notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
+ notifyUser("copied", notification)
+ return nil
+ }
+ if event.Key() == tcell.KeyF8 {
+ // copy msg to clipboard
+ editMode = false
+ pages.AddPage("getIndex", indexPickWindow, true, true)
+ return nil
+ }
+ if event.Key() == tcell.KeyCtrlE {
+ textArea.SetText("pressed ctrl+e", true)
+ return nil
+ }
+ if event.Key() == tcell.KeyCtrlS {
+ // switch sys prompt
+ pages.AddPage("sys", sysModal, true, true)
+ return nil
+ }
+ // cannot send msg in editMode or botRespMode
+ if event.Key() == tcell.KeyEscape && !editMode && !botRespMode {
+ fromRow, fromColumn, _, _ := textArea.GetCursor()
+ position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, botRespMode))
+ // read all text into buffer
+ msgText := textArea.GetText()
+ if 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)
+ return nil
+ }
+ if event.Key() == tcell.KeyPgUp || event.Key() == tcell.KeyPgDn {
+ currentF := app.GetFocus()
+ app.SetFocus(focusSwitcher[currentF])
+ return nil
+ }
+ if isASCII(string(event.Rune())) && !botRespMode {
+ // botRespMode = false
+ // fromRow, fromColumn, _, _ := textArea.GetCursor()
+ // position.SetText(fmt.Sprintf(indexLine, fromRow, fromColumn, botRespMode))
+ return event
+ }
+ return event
+ })
+}