mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-20 21:48:47 +02:00
v0.9.3 : statut moteur plus précis + réglages d'interface
- statut : la pastille ne dit plus toujours « modèle incompatible » (prêt / chargement… / erreur / arrêté) ; le détail n'accuse l'incompatibilité que quand le journal le montre (quant/architecture), sinon renvoie au journal - panneau Actions : bouton « refresh » retiré ; mise à jour + exporter sur une ligne, bench + clear chat sur l'autre - modale preset : titre sans le mot « Preset » redondant (juste le nom) - mémoire : « auto (proactive) » → « auto »
This commit is contained in:
1 parent
e3957fa749
commit
d4989f2991
10 files changed
+54
-55
No files matched your search
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const Version = "0.9.2"
|
||||
const Version = "0.9.3"
|
||||
|
||||
// Main est le vrai main() du binaire (cmd/ajean ne fait que l'appeler).
|
||||
func Main() {
|
||||
|
||||
@@ -1249,7 +1249,7 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
||||
<div class="slist">
|
||||
<label class="switchrow"><span>mode</span>
|
||||
<select id="mem-mode" onchange="setMemMode()" class="sctl">
|
||||
<option value="always">auto (proactive)</option>
|
||||
<option value="always">auto</option>
|
||||
<option value="ondemand">sur demande</option>
|
||||
<option value="off">désactivée</option>
|
||||
</select>
|
||||
@@ -1460,23 +1460,17 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
||||
</details>
|
||||
<details id="upd-details"><summary><span class="stitle">Actions</span></summary>
|
||||
<div class="slist"><div class="rowbody">
|
||||
<!-- Ligne 1 : mise à jour + export du fil. Depuis la 0.8 la conversation vit
|
||||
dans ajean.db (bbolt, verrouillé tant que le service tourne) : sans le
|
||||
bouton exporter, plus personne ne peut relire/archiver ses échanges. -->
|
||||
<div class="row" style="margin:0">
|
||||
<button id="upd-check" onclick="checkUpdate()">↥ Vérifier les mises à jour</button>
|
||||
</div>
|
||||
<div id="upd-msg" class="muted"></div>
|
||||
<!-- Export du fil. Depuis la 0.8 la conversation vit dans ajean.db (bbolt,
|
||||
binaire et verrouillé tant que le service tourne) : sans ce bouton,
|
||||
plus personne ne peut relire ni archiver ses échanges, ce que
|
||||
permettait l'ancien conversation.json. -->
|
||||
<div class="row" style="margin-bottom:0">
|
||||
<button onclick="loadAll()">↻ refresh</button>
|
||||
<button id="btn-bench" onclick="runBenchUI()">bench</button>
|
||||
<button onclick="openExportModal()" title="choisir le format et ce qu'on emporte">⤓ exporter…</button>
|
||||
</div>
|
||||
<!-- « clear chat » est en DERNIER, et seul sur sa ligne : c'est la seule
|
||||
action destructive du panneau, elle ne doit pas se trouver sous le
|
||||
doigt qui visait « refresh ». -->
|
||||
<div id="upd-msg" class="muted"></div>
|
||||
<!-- Ligne 2 : bench + clear chat (seule action destructive, gardée en dernier). -->
|
||||
<div class="row" style="margin-bottom:0">
|
||||
<button id="btn-bench" onclick="runBenchUI()">bench</button>
|
||||
<button onclick="resetChat()">⌫ clear chat</button>
|
||||
</div>
|
||||
</div></div>
|
||||
@@ -2280,9 +2274,12 @@ async function loadStatus(){
|
||||
const el=document.getElementById('status-svc');
|
||||
// Trois états : service coupé (err) · service actif mais modèle pas encore
|
||||
// chargé (loading, llama-server renvoie 503) · modèle prêt (ok).
|
||||
let cls='err', txt=s.state;
|
||||
// Pastille COURTE et honnête. Le détail (cause exacte) va dans #model-err
|
||||
// dessous : la pastille ne doit pas affirmer « incompatible » quand l'échec
|
||||
// peut être tout autre chose.
|
||||
let cls='err', txt='arrêté';
|
||||
if(s.active && s.health){ cls='ok'; txt='prêt'; }
|
||||
else if(s.load_error){ cls='err'; txt='modèle incompatible'; }
|
||||
else if(s.load_error){ cls='err'; txt='erreur'; }
|
||||
else if(s.active){ cls='loading'; txt='chargement…'; }
|
||||
el.className='statuspill '+cls;
|
||||
el.innerHTML='<span class="dot"></span>'+txt;
|
||||
@@ -3020,7 +3017,7 @@ const KINDS = {
|
||||
// skills keep name-as-identity (param 'name').
|
||||
// newLabel / nameHint : « Nouveau Page » et « Nom du preset » dans l'éditeur de
|
||||
// mémoire venaient d'un libellé unique décliné mécaniquement.
|
||||
preset: {label:'Preset', newLabel:'Nouveau preset', nameHint:'Nom du preset',
|
||||
preset: {label:'', newLabel:'Nouveau preset', nameHint:'Nom du preset',
|
||||
param:'id', getUrl:'/api/preset', saveUrl:'/api/preset/save', delUrl:'/api/preset/delete', reload:()=>loadPresets()},
|
||||
mem: {label:'Page', newLabel:'Nouvelle page', nameHint:'Nom de la page',
|
||||
param:'name', getUrl:'/api/mem', saveUrl:'/api/mem/save', delUrl:'/api/mem/delete', reload:()=>loadMem()},
|
||||
@@ -3039,7 +3036,7 @@ async function openItem(kind, key){
|
||||
const K = KINDS[kind];
|
||||
const seq = ++openSeq;
|
||||
editingKind = kind; editingKey = key || '';
|
||||
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + key) : K.newLabel;
|
||||
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + key : key) : K.newLabel;
|
||||
document.getElementById('m-name').value = key || '';
|
||||
document.getElementById('m-name').placeholder = K.nameHint;
|
||||
document.getElementById('m-content').value = '';
|
||||
@@ -3091,7 +3088,7 @@ async function openItem(kind, key){
|
||||
const d = await r.json();
|
||||
if(seq !== openSeq) return; // une autre ouverture a pris la main
|
||||
const display = d.name || key || '';
|
||||
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + display) : K.newLabel;
|
||||
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + display : display) : K.newLabel;
|
||||
document.getElementById('m-name').value = display;
|
||||
document.getElementById('m-content').value = d.content || '';
|
||||
if(kind === 'preset'){
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div class="slist">
|
||||
<label class="switchrow"><span>mode</span>
|
||||
<select id="mem-mode" onchange="setMemMode()" class="sctl">
|
||||
<option value="always">auto (proactive)</option>
|
||||
<option value="always">auto</option>
|
||||
<option value="ondemand">sur demande</option>
|
||||
<option value="off">désactivée</option>
|
||||
</select>
|
||||
@@ -290,23 +290,17 @@
|
||||
</details>
|
||||
<details id="upd-details"><summary><span class="stitle">Actions</span></summary>
|
||||
<div class="slist"><div class="rowbody">
|
||||
<!-- Ligne 1 : mise à jour + export du fil. Depuis la 0.8 la conversation vit
|
||||
dans ajean.db (bbolt, verrouillé tant que le service tourne) : sans le
|
||||
bouton exporter, plus personne ne peut relire/archiver ses échanges. -->
|
||||
<div class="row" style="margin:0">
|
||||
<button id="upd-check" onclick="checkUpdate()">↥ Vérifier les mises à jour</button>
|
||||
</div>
|
||||
<div id="upd-msg" class="muted"></div>
|
||||
<!-- Export du fil. Depuis la 0.8 la conversation vit dans ajean.db (bbolt,
|
||||
binaire et verrouillé tant que le service tourne) : sans ce bouton,
|
||||
plus personne ne peut relire ni archiver ses échanges, ce que
|
||||
permettait l'ancien conversation.json. -->
|
||||
<div class="row" style="margin-bottom:0">
|
||||
<button onclick="loadAll()">↻ refresh</button>
|
||||
<button id="btn-bench" onclick="runBenchUI()">bench</button>
|
||||
<button onclick="openExportModal()" title="choisir le format et ce qu'on emporte">⤓ exporter…</button>
|
||||
</div>
|
||||
<!-- « clear chat » est en DERNIER, et seul sur sa ligne : c'est la seule
|
||||
action destructive du panneau, elle ne doit pas se trouver sous le
|
||||
doigt qui visait « refresh ». -->
|
||||
<div id="upd-msg" class="muted"></div>
|
||||
<!-- Ligne 2 : bench + clear chat (seule action destructive, gardée en dernier). -->
|
||||
<div class="row" style="margin-bottom:0">
|
||||
<button id="btn-bench" onclick="runBenchUI()">bench</button>
|
||||
<button onclick="resetChat()">⌫ clear chat</button>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
@@ -3,9 +3,12 @@ async function loadStatus(){
|
||||
const el=document.getElementById('status-svc');
|
||||
// Trois états : service coupé (err) · service actif mais modèle pas encore
|
||||
// chargé (loading, llama-server renvoie 503) · modèle prêt (ok).
|
||||
let cls='err', txt=s.state;
|
||||
// Pastille COURTE et honnête. Le détail (cause exacte) va dans #model-err
|
||||
// dessous : la pastille ne doit pas affirmer « incompatible » quand l'échec
|
||||
// peut être tout autre chose.
|
||||
let cls='err', txt='arrêté';
|
||||
if(s.active && s.health){ cls='ok'; txt='prêt'; }
|
||||
else if(s.load_error){ cls='err'; txt='modèle incompatible'; }
|
||||
else if(s.load_error){ cls='err'; txt='erreur'; }
|
||||
else if(s.active){ cls='loading'; txt='chargement…'; }
|
||||
el.className='statuspill '+cls;
|
||||
el.innerHTML='<span class="dot"></span>'+txt;
|
||||
|
||||
@@ -74,7 +74,7 @@ const KINDS = {
|
||||
// skills keep name-as-identity (param 'name').
|
||||
// newLabel / nameHint : « Nouveau Page » et « Nom du preset » dans l'éditeur de
|
||||
// mémoire venaient d'un libellé unique décliné mécaniquement.
|
||||
preset: {label:'Preset', newLabel:'Nouveau preset', nameHint:'Nom du preset',
|
||||
preset: {label:'', newLabel:'Nouveau preset', nameHint:'Nom du preset',
|
||||
param:'id', getUrl:'/api/preset', saveUrl:'/api/preset/save', delUrl:'/api/preset/delete', reload:()=>loadPresets()},
|
||||
mem: {label:'Page', newLabel:'Nouvelle page', nameHint:'Nom de la page',
|
||||
param:'name', getUrl:'/api/mem', saveUrl:'/api/mem/save', delUrl:'/api/mem/delete', reload:()=>loadMem()},
|
||||
@@ -93,7 +93,7 @@ async function openItem(kind, key){
|
||||
const K = KINDS[kind];
|
||||
const seq = ++openSeq;
|
||||
editingKind = kind; editingKey = key || '';
|
||||
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + key) : K.newLabel;
|
||||
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + key : key) : K.newLabel;
|
||||
document.getElementById('m-name').value = key || '';
|
||||
document.getElementById('m-name').placeholder = K.nameHint;
|
||||
document.getElementById('m-content').value = '';
|
||||
@@ -145,7 +145,7 @@ async function openItem(kind, key){
|
||||
const d = await r.json();
|
||||
if(seq !== openSeq) return; // une autre ouverture a pris la main
|
||||
const display = d.name || key || '';
|
||||
document.getElementById('modal-title').textContent = key ? (K.label + ' · ' + display) : K.newLabel;
|
||||
document.getElementById('modal-title').textContent = key ? (K.label ? K.label + ' · ' + display : display) : K.newLabel;
|
||||
document.getElementById('m-name').value = display;
|
||||
document.getElementById('m-content').value = d.content || '';
|
||||
if(kind === 'preset'){
|
||||
|
||||
@@ -102,8 +102,19 @@ func modelLoadError() string {
|
||||
if loaded || reason == "" {
|
||||
return ""
|
||||
}
|
||||
return "Le modèle n'a pas pu être chargé : " + reason +
|
||||
". Il est probablement incompatible avec le moteur sélectionné — choisis un autre backend pour ce modèle (édite le modèle → section Moteur)."
|
||||
// Message PRÉCIS selon la cause : n'affirmer l'incompatibilité que quand le
|
||||
// journal la montre vraiment (quant/architecture). Un échec générique de
|
||||
// chargement peut avoir bien d'autres causes (mémoire, fichier, tenseur) — on
|
||||
// renvoie alors vers le journal plutôt que d'accuser à tort le moteur.
|
||||
switch reason {
|
||||
case "format de quantification non reconnu par ce moteur",
|
||||
"type/architecture de modèle inconnu de ce moteur":
|
||||
return "Modèle incompatible avec le moteur : " + reason +
|
||||
". Choisis un autre backend (édite le modèle → Moteur)."
|
||||
default:
|
||||
return "Le modèle n'a pas pu être chargé (" + reason +
|
||||
"). Ouvre le journal du moteur pour le détail."
|
||||
}
|
||||
}
|
||||
|
||||
// handleServiceLog (GET /api/service/log) : dernières lignes du journal du
|
||||
|
||||
Reference in new issue
Block a user