summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.golangci.yml32
-rw-r--r--Makefile2
-rw-r--r--bot.go72
-rw-r--r--main.go1
-rw-r--r--session.go5
-rw-r--r--storage/storage.go1
-rw-r--r--tools.go9
-rw-r--r--tui.go45
9 files changed, 109 insertions, 59 deletions
diff --git a/.gitignore b/.gitignore
index 9c37cd9..4ffe02b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ testlog
elefant
history/
*.db
+config.toml
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..66732bf
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,32 @@
+run:
+ timeout: 1m
+ concurrency: 2
+ tests: false
+
+linters:
+ enable-all: false
+ disable-all: true
+ enable:
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - typecheck
+ - unused
+ - prealloc
+ presets:
+ - performance
+
+linters-settings:
+ funlen:
+ lines: 80
+ statements: 50
+ lll:
+ line-length: 80
+
+issues:
+ exclude:
+ # Display all issues
+ max-issues-per-linter: 0
+ max-same-issues: 0
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..41d7962
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+lint: ## Run linters. Use make install-linters first.
+ golangci-lint run -c .golangci.yml ./...
diff --git a/bot.go b/bot.go
index 6820b64..fcad46f 100644
--- a/bot.go
+++ b/bot.go
@@ -53,15 +53,15 @@ func formMsg(chatBody *models.ChatBody, newMsg, role string) io.Reader {
}
// func sendMsgToLLM(body io.Reader) (*models.LLMRespChunk, error) {
-func sendMsgToLLM(body io.Reader) (any, error) {
+func sendMsgToLLM(body io.Reader) {
+ // nolint
resp, err := httpClient.Post(cfg.APIURL, "application/json", body)
if err != nil {
logger.Error("llamacpp api", "error", err)
- return nil, err
+ return
}
defer resp.Body.Close()
- llmResp := []models.LLMRespChunk{}
- // chunkChan <- cfg.AssistantIcon
+ // llmResp := []models.LLMRespChunk{}
reader := bufio.NewReader(resp.Body)
counter := 0
for {
@@ -90,9 +90,9 @@ func sendMsgToLLM(body io.Reader) (any, error) {
if err := json.Unmarshal(line, &llmchunk); err != nil {
logger.Error("failed to decode", "error", err, "line", string(line))
streamDone <- true
- return nil, err
+ return
}
- llmResp = append(llmResp, llmchunk)
+ // llmResp = append(llmResp, llmchunk)
// logger.Info("streamview", "chunk", llmchunk)
// if llmchunk.Choices[len(llmchunk.Choices)-1].FinishReason != "chat.completion.chunk" {
if llmchunk.Choices[len(llmchunk.Choices)-1].FinishReason == "stop" {
@@ -105,7 +105,6 @@ func sendMsgToLLM(body io.Reader) (any, error) {
answerText := strings.ReplaceAll(llmchunk.Choices[0].Delta.Content, "\n\n", "\n")
chunkChan <- answerText
}
- return llmResp, nil
}
func chatRound(userMsg, role string, tv *tview.TextView) {
@@ -117,8 +116,8 @@ func chatRound(userMsg, role string, tv *tview.TextView) {
}
go sendMsgToLLM(reader)
if userMsg != "" { // no need to write assistant icon since we continue old message
- fmt.Fprintf(tv, fmt.Sprintf("(%d) ", len(chatBody.Messages)))
- fmt.Fprintf(tv, cfg.AssistantIcon)
+ fmt.Fprintf(tv, "(%d) ", len(chatBody.Messages))
+ fmt.Fprint(tv, cfg.AssistantIcon)
}
respText := strings.Builder{}
out:
@@ -126,7 +125,7 @@ out:
select {
case chunk := <-chunkChan:
// fmt.Printf(chunk)
- fmt.Fprintf(tv, chunk)
+ fmt.Fprint(tv, chunk)
respText.WriteString(chunk)
tv.ScrollToEnd()
case <-streamDone:
@@ -163,7 +162,7 @@ func findCall(msg string, tv *tview.TextView) {
// call a func
f, ok := fnMap[fc.Name]
if !ok {
- m := fmt.Sprintf("%s is not implemented", fc.Name)
+ m := fc.Name + "%s is not implemented"
chatRound(m, cfg.ToolRole, tv)
return
}
@@ -188,30 +187,30 @@ func chatToText(showSys bool) string {
return strings.Join(s, "")
}
-func textToMsg(rawMsg string) models.MessagesStory {
- msg := models.MessagesStory{}
- // system and tool?
- if strings.HasPrefix(rawMsg, cfg.AssistantIcon) {
- msg.Role = cfg.AssistantRole
- msg.Content = strings.TrimPrefix(rawMsg, cfg.AssistantIcon)
- return msg
- }
- if strings.HasPrefix(rawMsg, cfg.UserIcon) {
- msg.Role = cfg.UserRole
- msg.Content = strings.TrimPrefix(rawMsg, cfg.UserIcon)
- return msg
- }
- return msg
-}
+// func textToMsg(rawMsg string) models.MessagesStory {
+// msg := models.MessagesStory{}
+// // system and tool?
+// if strings.HasPrefix(rawMsg, cfg.AssistantIcon) {
+// msg.Role = cfg.AssistantRole
+// msg.Content = strings.TrimPrefix(rawMsg, cfg.AssistantIcon)
+// return msg
+// }
+// if strings.HasPrefix(rawMsg, cfg.UserIcon) {
+// msg.Role = cfg.UserRole
+// msg.Content = strings.TrimPrefix(rawMsg, cfg.UserIcon)
+// return msg
+// }
+// return msg
+// }
-func textSliceToChat(chat []string) []models.MessagesStory {
- resp := make([]models.MessagesStory, len(chat))
- for i, rawMsg := range chat {
- msg := textToMsg(rawMsg)
- resp[i] = msg
- }
- return resp
-}
+// func textSliceToChat(chat []string) []models.MessagesStory {
+// resp := make([]models.MessagesStory, len(chat))
+// for i, rawMsg := range chat {
+// msg := textToMsg(rawMsg)
+// resp[i] = msg
+// }
+// return resp
+// }
func init() {
cfg = config.LoadConfigOrDefault("config.example.toml")
@@ -233,7 +232,10 @@ func init() {
store = storage.NewProviderSQL("test.db", logger)
// https://github.com/coreydaley/ggerganov-llama.cpp/blob/master/examples/server/README.md
// load all chats in memory
- loadHistoryChats()
+ if _, err := loadHistoryChats(); err != nil {
+ logger.Error("failed to load chat", "error", err)
+ return
+ }
lastChat := loadOldChatOrGetNew()
logger.Info("loaded history")
chatBody = &models.ChatBody{
diff --git a/main.go b/main.go
index 12575f0..4b21457 100644
--- a/main.go
+++ b/main.go
@@ -9,7 +9,6 @@ import (
var (
botRespMode = false
editMode = false
- botMsg = "no"
selectedIndex = int(-1)
indexLine = "F12 to show keys help; bot resp mode: %v; current chat: %s"
focusSwitcher = map[tview.Primitive]tview.Primitive{}
diff --git a/session.go b/session.go
index 7c035fa..ee448cc 100644
--- a/session.go
+++ b/session.go
@@ -3,6 +3,7 @@ package main
import (
"elefant/models"
"encoding/json"
+ "errors"
"fmt"
"os/exec"
"strings"
@@ -19,7 +20,7 @@ func historyToSJSON(msgs []models.MessagesStory) (string, error) {
return "", err
}
if data == nil {
- return "", fmt.Errorf("nil data")
+ return "", errors.New("nil data")
}
return string(data), nil
}
@@ -61,7 +62,7 @@ func loadHistoryChats() ([]string, error) {
func loadHistoryChat(chatName string) ([]models.MessagesStory, error) {
chat, ok := chatMap[chatName]
if !ok {
- err := fmt.Errorf("failed to read chat")
+ err := errors.New("failed to read chat")
logger.Error("failed to read chat", "name", chatName)
return nil, err
}
diff --git a/storage/storage.go b/storage/storage.go
index c863799..66640fd 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -55,6 +55,7 @@ func (p ProviderSQL) UpsertChat(chat *models.Chat) (*models.Chat, error) {
if err != nil {
return nil, err
}
+ defer stmt.Close()
// Execute the query and scan the result into a new chat object
var resp models.Chat
err = stmt.Get(&resp, chat)
diff --git a/tools.go b/tools.go
index af4356e..44df9f5 100644
--- a/tools.go
+++ b/tools.go
@@ -73,8 +73,11 @@ func memorise(args ...string) []byte {
Mind: args[1],
UpdatedAt: time.Now(),
}
- store.Memorise(memory)
- msg := fmt.Sprintf("info saved under the topic: %s", args[0])
+ if _, err := store.Memorise(memory); err != nil {
+ logger.Error("failed to save memory", "err", err, "memoory", memory)
+ return []byte("failed to save info")
+ }
+ msg := "info saved under the topic:" + args[0]
return []byte(msg)
}
@@ -104,7 +107,7 @@ func recallTopics(args ...string) []byte {
return []byte(joinedS)
}
-func fullMemoryLoad() {}
+// func fullMemoryLoad() {}
type fnSig func(...string) []byte
diff --git a/tui.go b/tui.go
index 7cf87cc..62b00b2 100644
--- a/tui.go
+++ b/tui.go
@@ -11,15 +11,15 @@ import (
)
var (
- app *tview.Application
- pages *tview.Pages
- textArea *tview.TextArea
- editArea *tview.TextArea
- textView *tview.TextView
- position *tview.TextView
- helpView *tview.TextView
- flex *tview.Flex
- chatActModal *tview.Modal
+ app *tview.Application
+ pages *tview.Pages
+ textArea *tview.TextArea
+ editArea *tview.TextArea
+ textView *tview.TextView
+ position *tview.TextView
+ helpView *tview.TextView
+ flex *tview.Flex
+ // chatActModal *tview.Modal
sysModal *tview.Modal
indexPickWindow *tview.InputField
renameWindow *tview.InputField
@@ -145,7 +145,9 @@ func init() {
if event.Key() == tcell.KeyEscape && editMode {
editedMsg := editArea.GetText()
if editedMsg == "" {
- notifyUser("edit", "no edit provided")
+ if err := notifyUser("edit", "no edit provided"); err != nil {
+ logger.Error("failed to send notification", "error", err)
+ }
pages.RemovePage("editArea")
editMode = false
return nil
@@ -165,7 +167,6 @@ func init() {
SetAcceptanceFunc(tview.InputFieldInteger).
SetDoneFunc(func(key tcell.Key) {
pages.RemovePage("getIndex")
- return
})
indexPickWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
si := indexPickWindow.GetText()
@@ -183,9 +184,13 @@ func init() {
editArea.SetText(m.Content, true)
}
if !editMode && event.Key() == tcell.KeyEnter {
- copyToClipboard(m.Content)
+ if err := copyToClipboard(m.Content); err != nil {
+ logger.Error("failed to copy to clipboard", "error", err)
+ }
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
- notifyUser("copied", notification)
+ if err := notifyUser("copied", notification); err != nil {
+ logger.Error("failed to send notification", "error", err)
+ }
}
return event
})
@@ -196,7 +201,6 @@ func init() {
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 {
@@ -214,14 +218,15 @@ func init() {
logger.Error("failed to upsert chat", "error", err, "chat", currentChat)
}
notification := fmt.Sprintf("renamed chat to '%s'", activeChatName)
- notifyUser("renamed", notification)
+ if err := notifyUser("renamed", notification); err != nil {
+ logger.Error("failed to send notification", "error", err)
+ }
}
return event
})
//
helpView = tview.NewTextView().SetDynamicColors(true).SetText(helpText).SetDoneFunc(func(key tcell.Key) {
pages.RemovePage("helpView")
- return
})
helpView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
@@ -281,9 +286,13 @@ func init() {
// copy msg to clipboard
editMode = false
m := chatBody.Messages[len(chatBody.Messages)-1]
- copyToClipboard(m.Content)
+ if err := copyToClipboard(m.Content); err != nil {
+ logger.Error("failed to copy to clipboard", "error", err)
+ }
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:30])
- notifyUser("copied", notification)
+ if err := notifyUser("copied", notification); err != nil {
+ logger.Error("failed to send notification", "error", err)
+ }
return nil
}
if event.Key() == tcell.KeyF8 {