Feat: shift syscard to first msg option

This commit is contained in:
Grail Finder
2025-02-24 18:57:31 +03:00
parent 71987d25e9
commit 97a1fc507e
3 changed files with 102 additions and 97 deletions

View File

@@ -3,16 +3,13 @@ package storage
import ( import (
"elefant/models" "elefant/models"
"fmt" "fmt"
"log"
"log/slog" "log/slog"
"os" "os"
"testing" "testing"
"time" "time"
sqlite_vec "github.com/asg017/sqlite-vec-go-bindings/ncruces"
_ "github.com/glebarez/go-sqlite" _ "github.com/glebarez/go-sqlite"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/ncruces/go-sqlite3"
) )
func TestMemories(t *testing.T) { func TestMemories(t *testing.T) {
@@ -177,87 +174,87 @@ func TestChatHistory(t *testing.T) {
} }
} }
func TestVecTable(t *testing.T) { // func TestVecTable(t *testing.T) {
// healthcheck // // healthcheck
db, err := sqlite3.Open(":memory:") // db, err := sqlite3.Open(":memory:")
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
stmt, _, err := db.Prepare(`SELECT sqlite_version(), vec_version()`) // stmt, _, err := db.Prepare(`SELECT sqlite_version(), vec_version()`)
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
stmt.Step() // stmt.Step()
log.Printf("sqlite_version=%s, vec_version=%s\n", stmt.ColumnText(0), stmt.ColumnText(1)) // log.Printf("sqlite_version=%s, vec_version=%s\n", stmt.ColumnText(0), stmt.ColumnText(1))
stmt.Close() // stmt.Close()
// migration // // migration
err = db.Exec("CREATE VIRTUAL TABLE vec_items USING vec0(embedding float[4], chat_name TEXT NOT NULL)") // err = db.Exec("CREATE VIRTUAL TABLE vec_items USING vec0(embedding float[4], chat_name TEXT NOT NULL)")
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
// data prep and insert // // data prep and insert
items := map[int][]float32{ // items := map[int][]float32{
1: {0.1, 0.1, 0.1, 0.1}, // 1: {0.1, 0.1, 0.1, 0.1},
2: {0.2, 0.2, 0.2, 0.2}, // 2: {0.2, 0.2, 0.2, 0.2},
3: {0.3, 0.3, 0.3, 0.3}, // 3: {0.3, 0.3, 0.3, 0.3},
4: {0.4, 0.4, 0.4, 0.4}, // 4: {0.4, 0.4, 0.4, 0.4},
5: {0.5, 0.5, 0.5, 0.5}, // 5: {0.5, 0.5, 0.5, 0.5},
} // }
q := []float32{0.28, 0.3, 0.3, 0.3} // q := []float32{0.4, 0.3, 0.3, 0.3}
stmt, _, err = db.Prepare("INSERT INTO vec_items(rowid, embedding, chat_name) VALUES (?, ?, ?)") // stmt, _, err = db.Prepare("INSERT INTO vec_items(rowid, embedding, chat_name) VALUES (?, ?, ?)")
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
for id, values := range items { // for id, values := range items {
v, err := sqlite_vec.SerializeFloat32(values) // v, err := sqlite_vec.SerializeFloat32(values)
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
stmt.BindInt(1, id) // stmt.BindInt(1, id)
stmt.BindBlob(2, v) // stmt.BindBlob(2, v)
stmt.BindText(3, "some_chat") // stmt.BindText(3, "some_chat")
err = stmt.Exec() // err = stmt.Exec()
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
stmt.Reset() // stmt.Reset()
} // }
stmt.Close() // stmt.Close()
// select | vec search // // select | vec search
stmt, _, err = db.Prepare(` // stmt, _, err = db.Prepare(`
SELECT // SELECT
rowid, // rowid,
distance, // distance,
embedding // embedding
FROM vec_items // FROM vec_items
WHERE embedding MATCH ? // WHERE embedding MATCH ?
ORDER BY distance // ORDER BY distance
LIMIT 3 // LIMIT 3
`) // `)
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
query, err := sqlite_vec.SerializeFloat32(q) // query, err := sqlite_vec.SerializeFloat32(q)
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
stmt.BindBlob(1, query) // stmt.BindBlob(1, query)
for stmt.Step() { // for stmt.Step() {
rowid := stmt.ColumnInt64(0) // rowid := stmt.ColumnInt64(0)
distance := stmt.ColumnFloat(1) // distance := stmt.ColumnFloat(1)
emb := stmt.ColumnRawText(2) // emb := stmt.ColumnRawText(2)
floats := decodeUnsafe(emb) // floats := decodeUnsafe(emb)
log.Printf("rowid=%d, distance=%f, floats=%v\n", rowid, distance, floats) // log.Printf("rowid=%d, distance=%f, floats=%v\n", rowid, distance, floats)
} // }
if err := stmt.Err(); err != nil { // if err := stmt.Err(); err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
err = stmt.Close() // err = stmt.Close()
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
err = db.Close() // err = db.Close()
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
} // }

View File

@@ -16,7 +16,7 @@ import (
) )
func makeChatTable(chatMap map[string]models.Chat) *tview.Table { func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
actions := []string{"load", "rename", "delete", "update card"} actions := []string{"load", "rename", "delete", "update card", "move sysprompt onto 1st msg"}
chatList := make([]string, len(chatMap)) chatList := make([]string, len(chatMap))
i := 0 i := 0
for name := range chatMap { for name := range chatMap {
@@ -26,9 +26,7 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
rows, cols := len(chatMap), len(actions)+2 rows, cols := len(chatMap), len(actions)+2
chatActTable := tview.NewTable(). chatActTable := tview.NewTable().
SetBorders(true) SetBorders(true)
// for chatName, chat := range chatMap {
for r := 0; r < rows; r++ { for r := 0; r < rows; r++ {
// r := 0
for c := 0; c < cols; c++ { for c := 0; c < cols; c++ {
color := tcell.ColorWhite color := tcell.ColorWhite
switch c { switch c {
@@ -49,7 +47,6 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
SetAlign(tview.AlignCenter)) SetAlign(tview.AlignCenter))
} }
} }
// r++
} }
chatActTable.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) { chatActTable.Select(0, 0).SetFixed(1, 1).SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEsc || key == tcell.KeyF1 { if key == tcell.KeyEsc || key == tcell.KeyF1 {
@@ -65,7 +62,6 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
chatActTable.SetSelectable(false, false) chatActTable.SetSelectable(false, false)
selectedChat := chatList[row] selectedChat := chatList[row]
defer pages.RemovePage(historyPage) defer pages.RemovePage(historyPage)
// notification := fmt.Sprintf("chat: %s; action: %s", selectedChat, tc.Text)
switch tc.Text { switch tc.Text {
case "load": case "load":
history, err := loadHistoryChat(selectedChat) history, err := loadHistoryChat(selectedChat)
@@ -128,6 +124,13 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
"error", err) "error", err)
} }
return return
case "move sysprompt onto 1st msg":
chatBody.Messages[1].Content = chatBody.Messages[0].Content + chatBody.Messages[1].Content
chatBody.Messages[0].Content = rpDefenitionSysMsg
textView.SetText(chatToText(cfg.ShowSys))
activeChatName = selectedChat
pages.RemovePage(historyPage)
return
default: default:
return return
} }

View File

@@ -14,6 +14,11 @@ var (
starRE = regexp.MustCompile(`(\*.*?\*)`) starRE = regexp.MustCompile(`(\*.*?\*)`)
thinkRE = regexp.MustCompile(`(<think>\s*([\s\S]*?)</think>)`) thinkRE = regexp.MustCompile(`(<think>\s*([\s\S]*?)</think>)`)
codeBlockRE = regexp.MustCompile(`(?s)\x60{3}(?:.*?)\n(.*?)\n\s*\x60{3}\s*`) codeBlockRE = regexp.MustCompile(`(?s)\x60{3}(?:.*?)\n(.*?)\n\s*\x60{3}\s*`)
rpDefenitionSysMsg = `
For this roleplay immersion is at most importance.
Every character thinks and acts based on their personality and setting of the roleplay.
Meta discussions outside of roleplay is allowed if clearly labeled as out of character, for example: (ooc: {msg}) or <ooc>{msg}</ooc>.
`
basicSysMsg = `Large Language Model that helps user with any of his requests.` basicSysMsg = `Large Language Model that helps user with any of his requests.`
toolSysMsg = `You can do functions call if needed. toolSysMsg = `You can do functions call if needed.
Your current tools: Your current tools: