mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 06:58:14 +02:00
gestion du backend llama.cpp depuis l'UI web : statut (commit, retard, binaire, accelerateur detecte), verification des maj (git fetch), install / update / recompilation en job asynchrone avec phases, compteur de fichiers compiles et logs de build streames (poll /api/llamacpp/job) ; le service est arrete pendant le build puis relance, BIN repointe automatiquement
This commit is contained in:
1 parent
29f249be09
commit
7ac571974f
8 files changed
+841
-4
No files matched your search
@@ -116,6 +116,21 @@
|
||||
<button onclick="apiKeyAction('clear')">retirer</button>
|
||||
</div>
|
||||
</details>
|
||||
<details id="lc-details"><summary>Backend llama.cpp <span id="lc-badge" style="margin-left:auto;margin-right:12px;font-size:10px"></span></summary>
|
||||
<div id="lc-status" class="muted" style="font-size:12px;line-height:1.6">…</div>
|
||||
<div class="row" id="lc-actions" style="margin-top:8px;flex-wrap:wrap">
|
||||
<button id="lc-install" onclick="lcInstall()" style="display:none;border-color:var(--accent);color:var(--accent)">⬇ installer</button>
|
||||
<button id="lc-check" onclick="lcCheck()">↥ vérifier les maj</button>
|
||||
<button id="lc-update" onclick="lcUpdate(false)" style="display:none;border-color:var(--accent);color:var(--accent)">⬆ mettre à jour</button>
|
||||
<button id="lc-rebuild" onclick="lcUpdate(true)" style="display:none">🔧 recompiler</button>
|
||||
</div>
|
||||
<div id="lc-check-msg" class="muted" style="font-size:11px;margin-top:6px;line-height:1.5"></div>
|
||||
<div id="lc-job" style="display:none;margin-top:8px">
|
||||
<div id="lc-job-phase" style="font-size:12px;display:flex;align-items:center;gap:6px"></div>
|
||||
<div class="lc-logbar" onclick="lcToggleLog()"><span id="lc-log-caret">▸</span> logs du build</div>
|
||||
<pre id="lc-log" hidden></pre>
|
||||
</div>
|
||||
</details>
|
||||
<details><summary>Service</summary>
|
||||
<div class="row">
|
||||
<button onclick="act('start')">start</button>
|
||||
|
||||
@@ -216,5 +216,5 @@ async function saveCrawlUrl(){
|
||||
const url=document.getElementById('crawl-url').value.trim();
|
||||
renderInternet(await jpost('/api/internet',{url}));
|
||||
}
|
||||
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs()]); }
|
||||
async function loadAll(){ await Promise.all([loadStatus(),loadVram(),loadCfg(),loadPresets(),loadAgent(),loadInternet(),loadApiKey(),loadPrefs(),loadLlamacpp()]); }
|
||||
async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); }
|
||||
@@ -0,0 +1,140 @@
|
||||
// Backend llama.cpp : statut, vérification des maj, install / update / rebuild
|
||||
// en job asynchrone côté serveur (logs + progression pollés sur /api/llamacpp/job).
|
||||
let lcState = null, lcPoll = null, lcLogNext = 0;
|
||||
|
||||
function lcBadge(html){ document.getElementById('lc-badge').innerHTML = html; }
|
||||
|
||||
async function loadLlamacpp(){
|
||||
let s;
|
||||
try{ s = await jget('/api/llamacpp'); }catch(_){ return; }
|
||||
lcState = s;
|
||||
const st = document.getElementById('lc-status');
|
||||
const parts = [];
|
||||
if(!s.installed){
|
||||
parts.push('<span style="color:var(--dim)">llama.cpp n\'est pas encore installé sur cette machine.</span>');
|
||||
parts.push('<span style="color:var(--dim)">L\'installation clone le dépôt, détecte le GPU et compile <code>llama-server</code> automatiquement.</span>');
|
||||
lcBadge('<span class="tag" style="opacity:.6">absent</span>');
|
||||
} else {
|
||||
const esc = t=>String(t||'').replace(/[<>&]/g,c=>({'<':'<','>':'>','&':'&'}[c]));
|
||||
parts.push('commit <b style="color:var(--text)">'+esc(s.commit)+'</b>'+(s.branch?' <span style="opacity:.7">('+esc(s.branch)+')</span>':''));
|
||||
if(s.commit_date) parts.push('<span style="opacity:.8">'+esc(String(s.commit_date).slice(0,16))+'</span> — '+esc(s.commit_msg));
|
||||
if(s.bin){
|
||||
parts.push('binaire : <span style="color:var(--ok)">✓ compilé</span>'+(s.in_use?' · <span style="color:var(--accent)">utilisé par la config</span>':' · <span style="opacity:.7">non utilisé par la config (BIN pointe ailleurs)</span>'));
|
||||
} else {
|
||||
parts.push('binaire : <span style="color:var(--err)">absent (pas encore compilé)</span>');
|
||||
}
|
||||
if(s.behind > 0) lcBadge('<span class="tag" style="color:var(--accent);border-color:var(--accent)">maj dispo</span>');
|
||||
else if(s.bin) lcBadge('<span class="tag ok">ok</span>');
|
||||
else lcBadge('<span class="tag err">à compiler</span>');
|
||||
}
|
||||
if(s.plan){
|
||||
const p = s.plan;
|
||||
parts.push('accélérateur détecté : <b style="color:var(--text)">'+p.backend.toUpperCase()+'</b>'+(p.arch?' <span style="opacity:.7">(arch '+p.arch+')</span>':'')+' · '+p.jobs+' jobs');
|
||||
}
|
||||
st.innerHTML = parts.join('<br>');
|
||||
document.getElementById('lc-install').style.display = s.installed ? 'none' : '';
|
||||
document.getElementById('lc-check').style.display = s.installed ? '' : 'none';
|
||||
document.getElementById('lc-update').style.display = (s.installed && (s.behind>0 || !s.bin)) ? '' : 'none';
|
||||
document.getElementById('lc-rebuild').style.display = s.installed ? '' : 'none';
|
||||
// Job en cours (page rechargée pendant un build) → on raccroche le polling.
|
||||
if(s.job && s.job.exists && s.job.running && !lcPoll){
|
||||
document.getElementById('lc-details').open = true;
|
||||
lcStartPolling();
|
||||
}
|
||||
}
|
||||
|
||||
async function lcCheck(){
|
||||
const btn = document.getElementById('lc-check');
|
||||
const msg = document.getElementById('lc-check-msg');
|
||||
btn.disabled = true; btn.textContent = '⏳ vérification…';
|
||||
try{
|
||||
const r = await jpost('/api/llamacpp/check');
|
||||
if(!r.ok){ msg.innerHTML = '<span style="color:var(--err)">'+(r.error||'erreur')+'</span>'; return; }
|
||||
if(r.behind > 0){
|
||||
msg.innerHTML = '<b style="color:var(--accent)">'+r.behind+' commit(s) de retard</b> sur origin/'+r.branch+'<br>'+
|
||||
'dernier distant : <b>'+r.remote+'</b> — '+String(r.remote_msg||'').replace(/[<>&]/g,'');
|
||||
document.getElementById('lc-update').style.display = '';
|
||||
lcBadge('<span class="tag" style="color:var(--accent);border-color:var(--accent)">maj dispo</span>');
|
||||
} else if(!r.has_binary){
|
||||
msg.innerHTML = 'sources à jour mais <b>binaire absent</b> — lance une recompilation.';
|
||||
} else {
|
||||
msg.innerHTML = '<span style="color:var(--ok)">✓ à jour</span> ('+r.local+')';
|
||||
}
|
||||
} finally { btn.disabled = false; btn.textContent = '↥ vérifier les maj'; }
|
||||
}
|
||||
|
||||
async function lcInstall(){
|
||||
if(!await askConfirm('Cloner llama.cpp puis compiler llama-server pour cette machine (détection GPU automatique). La compilation peut prendre de longues minutes (surtout en CUDA).', {title:'Installer llama.cpp ?', okText:'Installer'})) return;
|
||||
const r = await jpost('/api/llamacpp/install', {});
|
||||
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
|
||||
lcStartPolling();
|
||||
}
|
||||
|
||||
async function lcUpdate(clean){
|
||||
const msg = clean
|
||||
? 'Recompiler llama.cpp from scratch (build/ supprimé). Le service sera arrêté pendant le build puis redémarré.'
|
||||
: 'Mettre à jour llama.cpp (git pull) et recompiler. Le service sera arrêté pendant le build puis redémarré.';
|
||||
if(!await askConfirm(msg, {title: clean ? 'Recompiler llama.cpp ?' : 'Mettre à jour llama.cpp ?', okText: clean ? 'Recompiler' : 'Mettre à jour'})) return;
|
||||
const r = await jpost('/api/llamacpp/update', {clean: !!clean});
|
||||
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
|
||||
lcStartPolling();
|
||||
}
|
||||
|
||||
function lcSetButtons(disabled){
|
||||
['lc-install','lc-check','lc-update','lc-rebuild'].forEach(id=>{
|
||||
const b=document.getElementById(id); if(b) b.disabled = disabled;
|
||||
});
|
||||
}
|
||||
|
||||
function lcStartPolling(){
|
||||
const jobBox = document.getElementById('lc-job');
|
||||
jobBox.style.display = '';
|
||||
document.getElementById('lc-log').textContent = '';
|
||||
lcLogNext = 0;
|
||||
lcSetButtons(true);
|
||||
lcBadge('<span class="tag" style="color:var(--accent);border-color:var(--accent)"><span class="lc-spin">⏳</span> build</span>');
|
||||
if(lcPoll) clearInterval(lcPoll);
|
||||
lcPoll = setInterval(lcPollJob, 1000);
|
||||
lcPollJob();
|
||||
}
|
||||
|
||||
async function lcPollJob(){
|
||||
let j;
|
||||
try{ j = await jget('/api/llamacpp/job?from='+lcLogNext); }catch(_){ return; }
|
||||
if(!j.exists) return;
|
||||
const phaseEl = document.getElementById('lc-job-phase');
|
||||
// Logs incrémentaux (offset absolu — le serveur tronque le début si besoin).
|
||||
if(j.lines && j.lines.length){
|
||||
const pre = document.getElementById('lc-log');
|
||||
const stick = pre.scrollTop + pre.clientHeight >= pre.scrollHeight - 20;
|
||||
pre.textContent += j.lines.join('\n') + '\n';
|
||||
if(stick) pre.scrollTop = pre.scrollHeight;
|
||||
}
|
||||
if(typeof j.next === 'number') lcLogNext = j.next;
|
||||
if(j.running){
|
||||
phaseEl.innerHTML = '<span class="lc-spin">⏳</span> <span>'+String(j.phase||'…').replace(/[<>&]/g,'')+'</span>';
|
||||
return;
|
||||
}
|
||||
// Terminé.
|
||||
clearInterval(lcPoll); lcPoll = null;
|
||||
lcSetButtons(false);
|
||||
if(j.error){
|
||||
phaseEl.innerHTML = '<span style="color:var(--err)">✗ '+String(j.error).replace(/[<>&]/g,'')+'</span>';
|
||||
// Ouvre les logs pour que l'erreur réelle soit visible tout de suite.
|
||||
const pre = document.getElementById('lc-log');
|
||||
if(pre.hasAttribute('hidden')) lcToggleLog();
|
||||
pre.scrollTop = pre.scrollHeight;
|
||||
toast('build llama.cpp en échec');
|
||||
} else {
|
||||
phaseEl.innerHTML = '<span style="color:var(--ok)">✓ '+String(j.phase||'terminé').replace(/[<>&]/g,'')+'</span>';
|
||||
toast('llama.cpp : '+(j.phase||'terminé'));
|
||||
}
|
||||
loadAll(); // rafraîchit tout (config, statut service… et ce panneau)
|
||||
}
|
||||
|
||||
function lcToggleLog(){
|
||||
const pre = document.getElementById('lc-log');
|
||||
const bar = document.querySelector('.lc-logbar');
|
||||
if(pre.hasAttribute('hidden')){ pre.removeAttribute('hidden'); bar.classList.add('open'); pre.scrollTop = pre.scrollHeight; }
|
||||
else { pre.setAttribute('hidden',''); bar.classList.remove('open'); }
|
||||
}
|
||||
@@ -271,3 +271,9 @@ button:disabled{opacity:.5;cursor:not-allowed}
|
||||
h2,details>summary{font-size:10px}
|
||||
#menubtn{width:32px;height:32px;font-size:15px;top:calc(6px + env(safe-area-inset-top))}
|
||||
}
|
||||
/* --- Backend llama.cpp (gestion install/update depuis l'UI) --------------- */
|
||||
.lc-logbar{display:flex;align-items:center;gap:6px;cursor:pointer;user-select:none;font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:6px 0;margin-top:4px}
|
||||
.lc-logbar #lc-log-caret{font-size:9px;transition:transform .12s;display:inline-block}
|
||||
.lc-logbar.open #lc-log-caret{transform:rotate(90deg)}
|
||||
#lc-log{background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:8px;font-size:10px;line-height:1.45;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-all;margin:0}
|
||||
.lc-spin{display:inline-block;animation:spin 1s linear infinite}
|
||||
Reference in new issue
Block a user