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

+1 -1
View File
@@ -1288,7 +1288,7 @@ document.documentElement.setAttribute('data-side',localStorage.getItem('loki-sid
</div>
<div class="pe-row">
<span class="pe-row-l">Couches sur GPU<span class="pe-sub">999 ou auto = ce qui tient en VRAM · all = tout, quitte à saturer</span></span>
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"></span>
<span class="pe-row-c"><input id="s-ngl" class="pe-val" type="text" inputmode="numeric" placeholder="999" oninput="cfgWriteKey('NGL', this.value)"><span class="pe-unit" id="s-ngl-max"></span></span>
</div>
<div class="pe-row">
<span class="pe-row-l">Experts MoE sur CPU<span class="pe-sub">vide = non · sur 2 GPU, coupe le pipeline entre cartes (prompt plus lent)</span></span>
+17 -3
View File
@@ -333,7 +333,7 @@ async function loadCfg(){
rows.push(row('EXPERTS', d.drop ? 'mlock' : d.mmap ? 'mmap' : 'RAM'));
if(d.vision_gpu) rows.push(row('VISION', 'on', d.vision_gpu));
}else if(c.CTX) rows.push(row('CTX', c.CTX));
document.getElementById('cfg').innerHTML = rows.join('');
document.getElementById('cfg').innerHTML = rows.join('') + await engineCmdlineRow();
return;
}
if(c.BIN){
@@ -357,12 +357,26 @@ async function loadCfg(){
// Le modèle chargé alimente aussi le sélecteur de l'en-tête : c'est la seule
// source qui le connaisse quand aucun preset ne correspond à la configuration.
if(typeof setLoadedModel === 'function') setLoadedModel(c.MODEL || '');
// Nombre de couches du modèle (amont #43) : NGL au-delà de ngl_max ne change
// rien, en dessous on libère de la VRAM pour le contexte et le cache KV.
const ly=c.MODEL ? await jget('/api/model/layers').catch(()=>null) : null;
['MODEL','CTX','BATCH','UBATCH','NGL'].filter(k=>c[k]).forEach(k=>{
let v=c[k]; if(k==='MODEL') v=v.split('/').pop();
let v=c[k]; if(k==='MODEL') v=v.split(/[\\/]/).pop();
if(k==='NGL' && ly && ly.ok){ rows.push(row(k, v+' / '+ly.ngl_max, ly.ngl_max+' = tout le modèle sur le GPU ('+ly.layers+' couches + la sortie)')); return; }
rows.push(row(k, v));
});
// n-cpu-moe : affiché seulement s'il est réellement présent dans EXTRA_ARGS.
const m=(c.EXTRA_ARGS||'').match(/--n-cpu-moe\s+(\d+)/);
if(m) rows.push(row('N-CPU-MOE', m[1]));
document.getElementById('cfg').innerHTML = rows.join('');
document.getElementById('cfg').innerHTML = rows.join('') + await engineCmdlineRow();
}
// Ligne de commande exacte du dernier lancement du moteur (amont #108),
// copiable pour la vérifier ou la partager. Clé API masquée côté serveur.
let ENGINE_CMDLINE='';
async function engineCmdlineRow(){
const cl=await jget('/api/engine/cmdline').catch(()=>null);
ENGINE_CMDLINE=(cl&&cl.cmdline)||'';
if(!ENGINE_CMDLINE) return '';
return '<div class="kv"><span>COMMANDE</span><span><button class="pe-link" onclick="copyText(ENGINE_CMDLINE, \'commande copiée\')" title="'
+escHtml(ENGINE_CMDLINE)+'">copier la commande du moteur</button></span></div>';
}
+15
View File
@@ -599,6 +599,20 @@ function onPickModel(){
ta.value = 'MODEL="'+val+'"\n' + ta.value;
}
toast('MODEL='+val);
showNglMax(val);
}
// Nombre de couches du modèle du preset (amont #43), lu dans son en-tête GGUF :
// affiché à côté du champ NGL (placeholder, « / N » et survol).
async function showNglMax(model){
const e=document.getElementById('s-ngl'), u=document.getElementById('s-ngl-max'); if(!e) return;
e.placeholder='999'; e.title=''; if(u) u.textContent='';
if(!model) return;
const ly=await jget('/api/model/layers?model='+encodeURIComponent(model)).catch(()=>null);
if(!ly || !ly.ok) return;
e.placeholder=String(ly.ngl_max);
if(u) u.textContent='/ '+ly.ngl_max;
e.title=ly.ngl_max+' = tout le modèle sur le GPU ('+ly.layers+' couches + la sortie)';
}
// --- Vision (projecteur multimodal --mmproj) --------------------------------
@@ -1013,6 +1027,7 @@ function populateSettings(){
const set = (id,v)=>{ const e=document.getElementById(id); if(e) e.value=v; };
set('s-ctx', cfgReadKey('CTX'));
set('s-ngl', cfgReadKey('NGL'));
showNglMax(cfgReadKey('MODEL'));
set('s-threads', cfgReadKey('THREADS'));
set('s-batch', cfgReadKey('BATCH'));
set('s-ubatch', cfgReadKey('UBATCH'));