Feat: rename chat
This commit is contained in:
249
main.go
249
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 {
|
||||
|
||||
Reference in New Issue
Block a user