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:
MichaelandClaude Opus 5.5 committed 2026-10-07 09:28:42 +02:00
1 parent 4a9a5a1712
commit 127013b32b
16 files changed
+479 -34

No files matched your search

+18 -1
View File
@@ -53,7 +53,9 @@ func capsFromBody(body chatReq) Caps {
func sseHeartbeat(w http.ResponseWriter, flusher http.Flusher) (*sync.Mutex, func()) {
mu := &sync.Mutex{}
done := make(chan struct{})
exited := make(chan struct{})
go func() {
defer close(exited)
// 4 s (et non 15) : borne le temps qu'un dernier bout de flux peut rester
// coincé dans un buffer proxy (Cloudflare) faute d'octets pour le pousser.
t := time.NewTicker(4 * time.Second)
@@ -64,6 +66,15 @@ func sseHeartbeat(w http.ResponseWriter, flusher http.Flusher) (*sync.Mutex, fun
return
case <-t.C:
mu.Lock()
// Arrêt demandé pendant l'attente du verrou : le handler peut déjà
// être revenu, et écrire dans son ResponseWriter fait planter le
// process (amont #105).
select {
case <-done:
mu.Unlock()
return
default:
}
_, err := w.Write([]byte(": ping\n\n"))
if flusher != nil {
flusher.Flush()
@@ -75,7 +86,13 @@ func sseHeartbeat(w http.ResponseWriter, flusher http.Flusher) (*sync.Mutex, fun
}
}
}()
return mu, func() { close(done) }
var once sync.Once
// stop attend la fin de la goroutine : après son retour, plus aucune
// écriture ne peut partir vers w.
return mu, func() {
once.Do(func() { close(done) })
<-exited
}
}
// runChatStream est désormais un pur ABONNÉ au journal de la conversation serveur :