feat: pictures for the assistant - the models make and edit them by themselves through the Vertex API (a new picture, or the user's attached photo, or the last picture made), with an API key in Настройки and a switch for the prompt improver; folded descriptions of pictures and searches; the name of an attached file opens or saves it; a deleted chat is wiped from the database files, attachments included
This commit is contained in:
1 parent
c72fcfebf3
commit
dd1244a169
13 files changed
+925
-20
No files matched your search
@@ -0,0 +1,89 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A chat deleted takes with it what the user attached to it: the text of
|
||||
// its files lives in the messages, and must be gone from the database
|
||||
// files too - not just from the tables (SQLite leaves deleted rows in its
|
||||
// free pages and in the write-ahead log).
|
||||
func TestDeleteChatWipesAttachments(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "t.db")
|
||||
db, err := OpenDB(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := New(Options{DB: db, DistDir: t.TempDir()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hash, _ := hashPassword("Passw0rd12345")
|
||||
if err := db.CreateAdmin("adm", hash); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
adm, _ := db.AdminByUsername("adm")
|
||||
me := adm.ID
|
||||
const secret = "TOP-SECRET-CONTENT-OF-AN-ATTACHED-FILE-7731"
|
||||
chat := s.aiNewChat(me)
|
||||
other := s.aiNewChat(me)
|
||||
s.aiAppendTo(me, chat, "user", "посмотри\n\n[Вложение: notes.txt]\nСодержимое файла:\n"+secret)
|
||||
s.aiAppendTo(me, chat, "result", "Картинка готова [картинка: https://s2.x-grk.com/uploads/userphoto/ai/zzz-7731.png]")
|
||||
s.aiAppendTo(me, other, "user", "другой чат, остаётся")
|
||||
|
||||
s.aiDeleteChat(me, chat)
|
||||
|
||||
var n int
|
||||
_ = db.sql.QueryRow(`SELECT COUNT(*) FROM ai_messages WHERE chat_id = ?`, chat).Scan(&n)
|
||||
if n != 0 {
|
||||
t.Fatalf("%d messages of the deleted chat remain", n)
|
||||
}
|
||||
_ = db.sql.QueryRow(`SELECT COUNT(*) FROM ai_messages WHERE chat_id = ?`, other).Scan(&n)
|
||||
if n != 1 {
|
||||
t.Fatalf("the other chat has %d messages, want 1", n)
|
||||
}
|
||||
for _, f := range []string{path, path + "-wal"} {
|
||||
b, _ := os.ReadFile(f)
|
||||
if bytes.Contains(b, []byte(secret)) || bytes.Contains(b, []byte("zzz-7731")) {
|
||||
t.Fatalf("the deleted chat's content is still in %s", filepath.Base(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The oldest chats go past the limit the same way: nothing of them is kept.
|
||||
func TestOldChatsWipedToo(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "t.db")
|
||||
db, err := OpenDB(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := New(Options{DB: db, DistDir: t.TempDir()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hash, _ := hashPassword("Passw0rd12345")
|
||||
if err := db.CreateAdmin("adm", hash); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
adm, _ := db.AdminByUsername("adm")
|
||||
me := adm.ID
|
||||
first := s.aiNewChat(me)
|
||||
s.aiAppendTo(me, first, "user", "[Вложение: a.txt]\nСодержимое файла:\nOLD-ATTACHMENT-TEXT-5512")
|
||||
for i := 0; i < aiChatsKeep; i++ {
|
||||
s.aiNewChat(me)
|
||||
}
|
||||
if s.aiOwns(me, first) {
|
||||
t.Fatal("the oldest chat is kept past the limit")
|
||||
}
|
||||
for _, f := range []string{path, path + "-wal"} {
|
||||
b, _ := os.ReadFile(f)
|
||||
if bytes.Contains(b, []byte("OLD-ATTACHMENT-TEXT-5512")) {
|
||||
t.Fatalf("the old chat's content is still in %s", filepath.Base(f))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user