Presets : fini le benchmark fantôme

Repris d'AJEAN 0.16.3. Les benchmarks sont rangés par id de preset. Un
preset dont on changeait le modèle — ou supprimé puis recréé sous le même
nom — affichait les mesures d'un AUTRE modèle, qui n'avaient rien à voir.

- benchMatchesPreset : un bench n'est affiché que si le modèle mesuré est
  celui du preset (le nom de fichier est enregistré avec la mesure depuis
  toujours, il ne servait simplement à rien).
- DeletePreset oublie le bench, comme il oubliait déjà le prompt système.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-02 23:04:51 +02:00
1 parent 97378da7af
commit f117a466af
4 files changed
+41 -2

No files matched your search

+3
View File
@@ -432,6 +432,9 @@ func DeletePreset(id string) error {
// sans ce ménage, il resterait orphelin et ressusciterait sur un preset recréé
// sous le même id.
_ = putStr(bkState, sysPromptKeyPrefix+id, "")
// Même ménage pour son benchmark : un preset recréé sous cet id en
// hériterait, alors qu'il a été mesuré sur un autre modèle.
deletePresetBench(id)
return nil
}
+18
View File
@@ -158,6 +158,24 @@ func loadLastBench() *savedBench {
return &sb
}
// benchMatchesPreset : le bench a-t-il été mesuré sur le modèle ACTUEL du
// preset ? Les benchs sont rangés par id de preset : sans ce contrôle, un
// preset dont le modèle a changé affichait les mesures d'un autre modèle.
// Repris d'AJEAN 0.16.3.
func benchMatchesPreset(sb savedBench, cfg map[string]string) bool {
m := strings.TrimSpace(cfg["MODEL"])
return m != "" && sb.Model == filepath.Base(m)
}
// deletePresetBench oublie le bench d'un preset supprimé.
func deletePresetBench(id string) {
m := loadBenchStore()
if _, ok := m[id]; ok {
delete(m, id)
_ = putJSON(bkState, "bench_presets", m)
}
}
// loadBenchStore renvoie les benchmarks par preset (vide s'il n'y en a pas).
func loadBenchStore() map[string]savedBench {
m := map[string]savedBench{}
+17
View File
@@ -0,0 +1,17 @@
package loki
import "testing"
// Un bench n'est affiché que pour le modèle sur lequel il a été mesuré.
func TestBenchMatchesPreset(t *testing.T) {
sb := savedBench{Model: "Qwen3-27B-Q4_K_M.gguf"}
if !benchMatchesPreset(sb, map[string]string{"MODEL": "/models/Qwen3-27B-Q4_K_M.gguf"}) {
t.Fatal("même modèle : le bench doit s'afficher")
}
if benchMatchesPreset(sb, map[string]string{"MODEL": "/models/Autre.gguf"}) {
t.Fatal("autre modèle : le bench ne doit pas s'afficher")
}
if benchMatchesPreset(sb, map[string]string{}) {
t.Fatal("preset sans modèle : pas de bench")
}
}
+3 -2
View File
@@ -399,7 +399,8 @@ func handlePresets(w http.ResponseWriter, r *http.Request) {
out := []map[string]any{}
for _, p := range list {
item := map[string]any{"id": p.ID, "name": p.Name, "active": p.Active}
if content, err := ReadPreset(p.ID); err == nil {
content, _ := ReadPreset(p.ID)
if content != "" {
// Preset externe : ni quant, ni raisonnement local à annoncer — on
// l'étiquette et on donne le nom du modèle distant à afficher.
if cfg := parseEnv(content); isExternalConfig(cfg) {
@@ -417,7 +418,7 @@ func handlePresets(w http.ResponseWriter, r *http.Request) {
item["reasoning"] = strings.ToLower(r)
}
}
if sb, ok := store[p.ID]; ok {
if sb, ok := store[p.ID]; ok && benchMatchesPreset(sb, parseEnv(content)) {
item["bench"] = map[string]any{
"prefill": sb.Result.PromptPerSecond,
"decode": sb.Result.PredictedPerSec,