mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-16 03:39:29 +02:00
Trois retours d'utilisateurs apres la 0.8.3. Export de la conversation (regression de la 0.8 : conversation.json a disparu dans ajean.db, verrouille et binaire). Bouton dans l'UI + commande 'ajean export [--json] [fichier]', endpoint /api/chat/export. Ecoute reseau du moteur : interrupteur 'joignable depuis le reseau local' dans le panneau Acces OpenAI (HOST + regle de pare-feu Windows), commande 'ajean network [on|off|status]'. HOST devient un reglage de machine preserve au changement de preset. Modeles GGUF decoupes en tranches -00001-of-000NN : une famille = un modele. Telechargement de toutes les tranches depuis n'importe quel lien, sonde d'espace disque sur le total, liste et suppression regroupees, demarrage refuse avec le nom du fichier manquant.
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package ajean
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestShardInfo(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
idx, total int
|
|
ok bool
|
|
}{
|
|
{"Laguna-S-2.1-UD-IQ4_XS-00001-of-00003.gguf", 1, 3, true},
|
|
{"Laguna-S-2.1-UD-IQ4_XS-00002-of-00003.gguf", 2, 3, true},
|
|
{"m-01-of-03.gguf", 1, 3, true},
|
|
{"Qwen2.5-7B-Instruct-Q4_K_M.gguf", 0, 0, false},
|
|
{"bidon-00004-of-00003.gguf", 0, 0, false}, // numérotation incohérente
|
|
{"pas-un-gguf-00001-of-00002.bin", 0, 0, false},
|
|
}
|
|
for _, c := range cases {
|
|
idx, total, ok := shardInfo(c.name)
|
|
if idx != c.idx || total != c.total || ok != c.ok {
|
|
t.Errorf("shardInfo(%q) = %d,%d,%v ; attendu %d,%d,%v", c.name, idx, total, ok, c.idx, c.total, c.ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestShardFamilyGardeLaLargeur(t *testing.T) {
|
|
got := shardFamily("Laguna-00002-of-00003.gguf")
|
|
want := []string{
|
|
"Laguna-00001-of-00003.gguf",
|
|
"Laguna-00002-of-00003.gguf",
|
|
"Laguna-00003-of-00003.gguf",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("famille = %v ; attendu %v", got, want)
|
|
}
|
|
if solo := shardFamily("simple.gguf"); !reflect.DeepEqual(solo, []string{"simple.gguf"}) {
|
|
t.Fatalf("fichier simple = %v", solo)
|
|
}
|
|
}
|
|
|
|
// Le lien collé peut désigner n'importe quelle tranche : on remonte toujours à la
|
|
// première, et on ne réécrit QUE le nom de fichier final (le même libellé peut
|
|
// apparaître plus haut dans le chemin du dépôt).
|
|
func TestShardURLSet(t *testing.T) {
|
|
base := "https://huggingface.co/unsloth/Laguna-S-2.1-GGUF/resolve/main/UD-IQ4_XS/"
|
|
in := base + "Laguna-UD-IQ4_XS-00002-of-00003.gguf"
|
|
urls, names := shardURLSet(in, "Laguna-UD-IQ4_XS-00002-of-00003.gguf")
|
|
if len(urls) != 3 || len(names) != 3 {
|
|
t.Fatalf("attendu 3 tranches, got %d/%d", len(urls), len(names))
|
|
}
|
|
if names[0] != "Laguna-UD-IQ4_XS-00001-of-00003.gguf" {
|
|
t.Fatalf("première tranche = %q", names[0])
|
|
}
|
|
if urls[0] != base+"Laguna-UD-IQ4_XS-00001-of-00003.gguf" {
|
|
t.Fatalf("URL de la première tranche = %q", urls[0])
|
|
}
|
|
if urls[2] != base+"Laguna-UD-IQ4_XS-00003-of-00003.gguf" {
|
|
t.Fatalf("URL de la dernière tranche = %q", urls[2])
|
|
}
|
|
// Fichier simple : une seule URL, inchangée.
|
|
u, n := shardURLSet(base+"m.gguf", "m.gguf")
|
|
if len(u) != 1 || u[0] != base+"m.gguf" || n[0] != "m.gguf" {
|
|
t.Fatalf("fichier simple mal traité : %v %v", u, n)
|
|
}
|
|
}
|
|
|
|
func TestShardFamilyTailleEtManquantes(t *testing.T) {
|
|
dir := t.TempDir()
|
|
write := func(n string, size int) {
|
|
if err := os.WriteFile(filepath.Join(dir, n), make([]byte, size), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
write("m-00001-of-00003.gguf", 100)
|
|
write("m-00003-of-00003.gguf", 300)
|
|
|
|
if got := shardFamilySize(dir, "m-00001-of-00003.gguf"); got != 400 {
|
|
t.Fatalf("taille de la famille = %d ; attendu 400", got)
|
|
}
|
|
missing := shardFamilyMissing(dir, "m-00001-of-00003.gguf")
|
|
if !reflect.DeepEqual(missing, []string{"m-00002-of-00003.gguf"}) {
|
|
t.Fatalf("tranches manquantes = %v", missing)
|
|
}
|
|
write("m-00002-of-00003.gguf", 200)
|
|
if m := shardFamilyMissing(dir, "m-00001-of-00003.gguf"); len(m) != 0 {
|
|
t.Fatalf("famille complète signalée incomplète : %v", m)
|
|
}
|
|
}
|
|
|
|
// Supprimer un modèle découpé doit emporter TOUTES ses tranches, sinon des
|
|
// dizaines de Go restent sur le disque sans que rien ne sache plus les effacer.
|
|
func TestDeleteModelFileEmporteLesTranches(t *testing.T) {
|
|
testHome(t)
|
|
dir := modelsDir()
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
names := []string{"m-00001-of-00002.gguf", "m-00002-of-00002.gguf", "autre.gguf"}
|
|
for _, n := range names {
|
|
if err := os.WriteFile(filepath.Join(dir, n), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := deleteModelFile("m-00001-of-00002.gguf"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range names[:2] {
|
|
if _, err := os.Stat(filepath.Join(dir, n)); !os.IsNotExist(err) {
|
|
t.Fatalf("tranche %s non supprimée", n)
|
|
}
|
|
}
|
|
if _, err := os.Stat(filepath.Join(dir, "autre.gguf")); err != nil {
|
|
t.Fatal("un modèle sans rapport a été supprimé")
|
|
}
|
|
}
|