mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 05:58:13 +02:00
Correctifs repris d'AJEAN : chiffrement, preset externe, heartbeat, commande du moteur
- Désactivation du chiffrement (amont cac0cda, 19918c6) : une valeur illisible ne bloque plus tout (quarantaine datée + copie du keyvault), et la reprise au démarrage déchiffre aussi les conversations au lieu de retirer la clé après les seules pages. Propre à Loki : les images de conversation (chatimg/) sont maintenant déchiffrées elles aussi — elles restaient chiffrées sans clé. Les .bak chiffrés devenus illisibles sont retirés. - Preset externe (amont #95) : `loki serve` sort sans erreur (plus de boucle systemd « MODEL non défini »), le pré-vol l'accepte, le superviseur du conteneur ne le prend plus pour un plantage. - Unité systemd du moteur : TimeoutStopSec=5 (bascule de preset bloquée 90 s en pleine génération). - Heartbeat SSE (amont #105) : plus d'écriture après le retour du handler. - Paramètres → Configuration : commande exacte du moteur copiable (clé API masquée, Strata compris) et nombre de couches du modèle à côté de NGL, lu dans l'en-tête GGUF (amont #108, #43) ; aussi dans l'éditeur de preset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4a9a5a1712
commit
127013b32b
16 files changed
+479
-34
No files matched your search
@@ -0,0 +1,87 @@
|
||||
package loki
|
||||
|
||||
// engine_cmdline.go — ce que l'interface montre du dernier lancement du moteur
|
||||
// (repris d'AJEAN, #108 et #43) :
|
||||
//
|
||||
// /api/engine/cmdline la commande exacte lancée par `loki serve` (variables
|
||||
// d'environnement posées par Loki comprises), copiable
|
||||
// pour la vérifier ou la partager ; clé API masquée
|
||||
// /api/model/layers le nombre de couches du modèle, lu dans l'en-tête
|
||||
// GGUF : la valeur de NGL qui met tout sur le GPU
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// engineCmdlineKey : dernière commande du moteur (bkState), lue par l'UI.
|
||||
const engineCmdlineKey = "engine_cmdline"
|
||||
|
||||
// engineCmdline met les arguments sous forme copiable dans un terminal :
|
||||
// variables d'environnement en tête (KEY=VAL, triées), guillemets autour de ce
|
||||
// qui contient un espace, clé API masquée.
|
||||
func engineCmdline(env map[string]string, args []string) string {
|
||||
quote := func(a string) string {
|
||||
if a == "" || strings.ContainsAny(a, " \t\"'") {
|
||||
return `"` + strings.ReplaceAll(a, `"`, `\"`) + `"`
|
||||
}
|
||||
return a
|
||||
}
|
||||
var out []string
|
||||
keys := make([]string, 0, len(env))
|
||||
for k := range env {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
out = append(out, k+"="+quote(env[k]))
|
||||
}
|
||||
for i, a := range args {
|
||||
if i > 0 && (args[i-1] == "--api-key" || args[i-1] == "--api-key-file") {
|
||||
a = "<clé masquée>"
|
||||
}
|
||||
out = append(out, quote(a))
|
||||
}
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
|
||||
// recordEngineCmdline garde la commande du lancement en cours. Jamais pour un
|
||||
// essai de l'optimiseur : il écraserait celle du vrai moteur.
|
||||
func recordEngineCmdline(env map[string]string, args []string) {
|
||||
_ = putBytes(bkState, engineCmdlineKey, []byte(engineCmdline(env, args)))
|
||||
}
|
||||
|
||||
// handleEngineCmdline (GET) : la commande du dernier lancement du moteur local.
|
||||
func handleEngineCmdline(w http.ResponseWriter, r *http.Request) {
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "cmdline": string(getBytes(bkState, engineCmdlineKey))})
|
||||
}
|
||||
|
||||
// handleModelLayers (GET ?model=…, sinon MODEL de la config) : nombre de blocs
|
||||
// du modèle. llama.cpp en offloade block_count + 1 (la couche de sortie en
|
||||
// plus) : c'est la valeur de -ngl qui met tout le modèle sur le GPU.
|
||||
func handleModelLayers(w http.ResponseWriter, r *http.Request) {
|
||||
model := strings.TrimSpace(r.URL.Query().Get("model"))
|
||||
if model == "" {
|
||||
model = strings.TrimSpace(ReadConfig()["MODEL"])
|
||||
}
|
||||
if model == "" {
|
||||
sendJSON(w, 200, map[string]any{"ok": false, "error": "aucun modèle"})
|
||||
return
|
||||
}
|
||||
path, err := resolveServeModelPath(model)
|
||||
if err != nil {
|
||||
sendJSON(w, 200, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
info, err := ggufMeta(path)
|
||||
if err != nil || info.BlockCount <= 0 {
|
||||
msg := "nombre de couches absent de l'en-tête"
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{"ok": false, "error": msg})
|
||||
return
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "layers": info.BlockCount, "ngl_max": info.BlockCount + 1})
|
||||
}
|
||||
Reference in new issue
Block a user