// Backend llama.cpp — vue simple : deux modes au choix.
// ⚡ Version rapide = binaires officiels précompilés (aucune compilation)
// 🔧 Version optimisée = compilée pour la machine
// Un clic sur une carte l'installe (ou l'active si déjà installée). La carte
// active propose « mettre à jour ». Aucun détail technique affiché.
let lcState = null, lcPoll = null, lcLogNext = 0;
async function loadLlamacpp(){
let s;
try{ s = await jget('/api/llamacpp'); }catch(_){ return; }
lcState = s;
const pb = s.prebuilt || {};
const fastActive = !!pb.in_use;
const optActive = s.installed && s.in_use && !pb.in_use;
const head = document.getElementById('lc-status');
if(!fastActive && !optActive){
head.innerHTML = 'Le moteur d\'IA n\'est pas encore installé. Choisis une version ci-dessous — la rapide convient à presque tout le monde.';
} else if(fastActive){
head.innerHTML = 'Moteur actif : version rapide.';
} else {
head.innerHTML = 'Moteur actif : version optimisée.';
}
lcRenderMode('fast', fastActive, !!pb.bin);
lcRenderMode('opt', optActive, !!s.bin);
// Job en cours (page rechargée pendant une install) → on raccroche l'affichage.
if(s.job && s.job.exists && s.job.running && !lcPoll){
document.getElementById('lc-details').open = true;
lcStartPolling();
}
}
function lcRenderMode(mode, active, installed){
const card = document.getElementById(mode==='fast' ? 'lc-mode-fast' : 'lc-mode-opt');
const state = document.getElementById(mode==='fast' ? 'lc-fast-state' : 'lc-opt-state');
card.classList.toggle('active', active);
if(active){
state.innerHTML = '✓ Actif'
+ '↻ mettre à jour';
} else if(installed){
state.innerHTML = '→ cliquer pour l\'activer';
} else {
state.innerHTML = '→ cliquer pour installer';
}
}
// Clic sur une carte : activer / installer le mode correspondant.
async function lcPick(mode){
const s = lcState || {}, pb = s.prebuilt || {};
if(mode === 'fast'){
if(pb.in_use) return; // déjà actif
if(pb.bin){ // déjà téléchargée → simple bascule
if(!await askConfirm('Basculer sur la version rapide (déjà installée) ? Le moteur va redémarrer.', {title:'Version rapide', okText:'Basculer'})) return;
return lcUse('fast');
}
if(!await askConfirm('Installer la version rapide de llama.cpp : téléchargement prêt à l\'emploi (~2 min, aucune compilation). Le moteur va redémarrer à la fin.', {title:'Version rapide', okText:'Installer'})) return;
const r = await jpost('/api/llamacpp/prebuilt', {});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
lcStartPolling();
} else {
if(s.installed && s.in_use && !pb.in_use) return; // déjà actif
if(s.bin){ // déjà compilée → simple bascule
if(!await askConfirm('Basculer sur la version optimisée (déjà compilée) ? Le moteur va redémarrer.', {title:'Version optimisée', okText:'Basculer'})) return;
return lcUse('opt');
}
if(!await askConfirm('Compiler la version optimisée pour ta machine. Ça peut prendre de longues minutes (surtout avec une carte NVIDIA). Le moteur va redémarrer à la fin.', {title:'Version optimisée', okText:'Compiler'})) return;
const r = await jpost('/api/llamacpp/install', {});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
lcStartPolling();
}
}
// Bascule instantanée entre deux versions déjà installées (pas de recompilation).
async function lcUse(mode){
toast('bascule…');
const r = await jpost('/api/llamacpp/use', {mode});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
toast(mode==='fast' ? 'version rapide activée' : 'version optimisée activée');
setTimeout(loadAll, 1500);
}
// « Mettre à jour » sur la carte active.
async function lcUpdateActive(){
const s = lcState || {}, pb = s.prebuilt || {};
if(pb.in_use){
if(!await askConfirm('Vérifier et installer la dernière version rapide. Le moteur va redémarrer.', {title:'Mettre à jour', okText:'Mettre à jour'})) return;
const r = await jpost('/api/llamacpp/prebuilt', {});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
} else {
if(!await askConfirm('Vérifier et installer la dernière version optimisée (recompilation si besoin). Le moteur va redémarrer.', {title:'Mettre à jour', okText:'Mettre à jour'})) return;
const r = await jpost('/api/llamacpp/update', {clean:false});
if(!r.ok){ toast('erreur : '+(r.error||'')); return; }
}
lcStartPolling();
}
// --- Progression de l'installation (téléchargement / compilation) ----------
function lcBusy(on){ document.querySelector('.lc-modes').classList.toggle('busy', on); }
function lcStartPolling(){
document.getElementById('lc-job').style.display = '';
document.getElementById('lc-log').textContent = '';
lcLogNext = 0;
lcBusy(true);
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');
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 = '⏳ '+String(j.phase||'…').replace(/[<>&]/g,'')+'';
return;
}
clearInterval(lcPoll); lcPoll = null;
lcBusy(false);
if(j.error){
phaseEl.innerHTML = '✗ '+String(j.error).replace(/[<>&]/g,'')+'';
const pre = document.getElementById('lc-log');
if(pre.hasAttribute('hidden')) lcToggleLog();
pre.scrollTop = pre.scrollHeight;
toast('échec — voir les détails');
} else {
phaseEl.innerHTML = '✓ '+String(j.phase||'terminé').replace(/[<>&]/g,'')+'';
toast('c\'est prêt ✓');
}
loadAll();
}
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'); }
}