mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 06:58:14 +02:00
Merge branch 'claude/ajean-loki-container-fork-aep9r2'
This commit is contained in:
5 files changed
+166
-56
No files matched your search
+60
-28
@@ -1210,11 +1210,12 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
|||||||
<!-- Avertissement de lancement (App Translocation macOS) — masqué par défaut. -->
|
<!-- Avertissement de lancement (App Translocation macOS) — masqué par défaut. -->
|
||||||
<div id="app-warn" class="muted" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)"></div>
|
<div id="app-warn" class="muted" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)"></div>
|
||||||
<div id="model-err" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--err);border:1px solid color-mix(in srgb,var(--err) 45%,transparent);background:color-mix(in srgb,var(--err) 12%,transparent)"></div>
|
<div id="model-err" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--err);border:1px solid color-mix(in srgb,var(--err) 45%,transparent);background:color-mix(in srgb,var(--err) 12%,transparent)"></div>
|
||||||
<!-- Journal du moteur : replié par défaut, ouvert au clic sur la pastille d'état.
|
<!-- Journal du moteur : replié par défaut, ouvert au clic sur la pastille d'état
|
||||||
|
OU par son propre chevron — c'est une section comme les autres, sinon on ne
|
||||||
|
trouvait pas comment la refermer.
|
||||||
C'est le seul endroit où l'on voit pourquoi un modèle refuse de charger. -->
|
C'est le seul endroit où l'on voit pourquoi un modèle refuse de charger. -->
|
||||||
<div id="svc-log-box" style="display:none;margin:0 0 10px">
|
<details id="svc-log-box" ontoggle="if(this.open){loadSvcLog();showPaths()}"><summary><span class="stitle">Journal du moteur</span></summary>
|
||||||
<div class="row" style="justify-content:space-between;align-items:center">
|
<div class="row" style="justify-content:flex-end;align-items:center">
|
||||||
<span class="io-cap">Journal du moteur</span>
|
|
||||||
<button onclick="loadSvcLog()" title="rafraîchir">↻</button>
|
<button onclick="loadSvcLog()" title="rafraîchir">↻</button>
|
||||||
</div>
|
</div>
|
||||||
<pre id="svc-log" class="muted" style="font-size:10px;line-height:1.45;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:6px 0 0"></pre>
|
<pre id="svc-log" class="muted" style="font-size:10px;line-height:1.45;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:6px 0 0"></pre>
|
||||||
@@ -1224,7 +1225,7 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
|||||||
<span class="io-cap">Emplacements</span>
|
<span class="io-cap">Emplacements</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="paths-msg" class="muted" style="font-size:10px;line-height:1.5"></div>
|
<div id="paths-msg" class="muted" style="font-size:10px;line-height:1.5"></div>
|
||||||
</div>
|
</details>
|
||||||
<!-- GPU et RAM décrivent la même chose (les ressources de la machine) :
|
<!-- GPU et RAM décrivent la même chose (les ressources de la machine) :
|
||||||
une seule section, deux blocs de statistique dans la même carte. -->
|
une seule section, deux blocs de statistique dans la même carte. -->
|
||||||
<details open><summary><span class="stitle">Machine</span></summary>
|
<details open><summary><span class="stitle">Machine</span></summary>
|
||||||
@@ -1419,6 +1420,15 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
|||||||
même sujet. Les trois modes sont des LIGNES de cette carte (elles
|
même sujet. Les trois modes sont des LIGNES de cette carte (elles
|
||||||
étaient des cartes dans une carte). -->
|
étaient des cartes dans une carte). -->
|
||||||
<div class="slist">
|
<div class="slist">
|
||||||
|
<!-- Moteur fourni par l'image Docker : aucun des trois modes ne s'applique
|
||||||
|
(rien à installer, et l'image n'embarque ni cmake ni compilateur). -->
|
||||||
|
<div id="lc-provided" class="rowbody" style="display:none">
|
||||||
|
<div style="font-size:12px;line-height:1.5">Moteur <b>fourni par l'image Docker</b> — llama.cpp officiel, déjà compilé.
|
||||||
|
<div class="muted" style="margin-top:4px">Rien à installer ni à mettre à jour ici : le moteur suit l'image.
|
||||||
|
Pour en changer (version épinglée, CPU, Vulkan), reconstruis l'image avec le build-arg <code>LLAMACPP_IMAGE</code>.</div>
|
||||||
|
<div class="muted" style="margin-top:4px"><code id="lc-provided-bin" style="word-break:break-all"></code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- La pastille « conseillé » n'est PAS écrite ici : le bon choix dépend de
|
<!-- La pastille « conseillé » n'est PAS écrite ici : le bon choix dépend de
|
||||||
la machine (voir lcRenderReco). Sur Linux + NVIDIA le précompilé ne
|
la machine (voir lcRenderReco). Sur Linux + NVIDIA le précompilé ne
|
||||||
donne que du Vulkan — llama.cpp ne publie aucun binaire CUDA Linux —
|
donne que du Vulkan — llama.cpp ne publie aucun binaire CUDA Linux —
|
||||||
@@ -2311,13 +2321,13 @@ async function loadStatus(){
|
|||||||
else { me.style.display='none'; }
|
else { me.style.display='none'; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Journal du moteur — replié par défaut, on l'ouvre en cliquant la pastille.
|
// Journal du moteur — section repliable comme les autres. La pastille d'état
|
||||||
|
// reste un raccourci ; le chargement du journal est déclenché par l'événement
|
||||||
|
// `toggle` du <details>, qu'on l'ouvre par la pastille ou par son chevron.
|
||||||
function toggleSvcLog(){
|
function toggleSvcLog(){
|
||||||
const box=document.getElementById('svc-log-box');
|
const box=document.getElementById('svc-log-box');
|
||||||
if(!box) return;
|
if(!box) return;
|
||||||
const show = box.style.display==='none';
|
box.open = !box.open;
|
||||||
box.style.display = show ? '' : 'none';
|
|
||||||
if(show){ loadSvcLog(); showPaths(); }
|
|
||||||
}
|
}
|
||||||
async function loadSvcLog(){
|
async function loadSvcLog(){
|
||||||
const el=document.getElementById('svc-log');
|
const el=document.getElementById('svc-log');
|
||||||
@@ -4607,27 +4617,34 @@ async function loadLlamacpp(){
|
|||||||
const fastInstalled = !!pb.bin;
|
const fastInstalled = !!pb.bin;
|
||||||
const optInstalled = !!s.bin;
|
const optInstalled = !!s.bin;
|
||||||
|
|
||||||
lcRenderReco(s.reco);
|
// Moteur fourni par l'image Docker : les trois modes d'installation n'ont
|
||||||
lcRenderMode('fast', fastInstalled);
|
// aucun sens (rien à installer, aucun compilateur dans l'image). On affiche
|
||||||
lcRenderMode('opt', optInstalled);
|
// l'état réel à la place — les boutons du service, eux, restent utiles.
|
||||||
lcRenderCustomCard();
|
lcRenderProvided(s);
|
||||||
|
|
||||||
// Job en cours (page rechargée pendant une install) → on raccroche l'affichage.
|
if(!s.provided){
|
||||||
if(s.job && s.job.exists && s.job.running && !lcPoll){
|
lcRenderReco(s.reco);
|
||||||
document.getElementById('lc-details').open = true;
|
lcRenderMode('fast', fastInstalled);
|
||||||
lcStartPolling();
|
lcRenderMode('opt', optInstalled);
|
||||||
|
lcRenderCustomCard();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
// Job terminé/interrompu qu'on n'a pas encore montré (rechargement APRÈS coup,
|
||||||
|
// typiquement quand le service a redémarré) : on l'affiche sans polling.
|
||||||
|
else if(s.job && s.job.exists && !s.job.running && !lcPoll && s.job.error && !lcEndShown){
|
||||||
|
document.getElementById('lc-details').open = true;
|
||||||
|
document.getElementById('lc-job').style.display = '';
|
||||||
|
lcLogNext = 0;
|
||||||
|
document.getElementById('lc-log').textContent = '';
|
||||||
|
lcEndShown = true;
|
||||||
|
lcPollJob(true); // quiet : simple rattrapage, pas de toast ni de rechargement
|
||||||
|
}
|
||||||
|
lcChipSync(s.job);
|
||||||
}
|
}
|
||||||
// Job terminé/interrompu qu'on n'a pas encore montré (rechargement APRÈS coup,
|
|
||||||
// typiquement quand le service a redémarré) : on l'affiche sans polling.
|
|
||||||
else if(s.job && s.job.exists && !s.job.running && !lcPoll && s.job.error && !lcEndShown){
|
|
||||||
document.getElementById('lc-details').open = true;
|
|
||||||
document.getElementById('lc-job').style.display = '';
|
|
||||||
lcLogNext = 0;
|
|
||||||
document.getElementById('lc-log').textContent = '';
|
|
||||||
lcEndShown = true;
|
|
||||||
lcPollJob(true); // quiet : simple rattrapage, pas de toast ni de rechargement
|
|
||||||
}
|
|
||||||
lcChipSync(s.job);
|
|
||||||
// Préchauffe la liste des cartes du moteur actif : interroger le moteur prend
|
// Préchauffe la liste des cartes du moteur actif : interroger le moteur prend
|
||||||
// 1 à 3 s (init CUDA/Vulkan), et sans ça l'encart « cartes graphiques » de
|
// 1 à 3 s (init CUDA/Vulkan), et sans ça l'encart « cartes graphiques » de
|
||||||
// l'éditeur apparaissait après coup, une fois le reste déjà affiché.
|
// l'éditeur apparaissait après coup, une fois le reste déjà affiché.
|
||||||
@@ -4682,6 +4699,21 @@ function lcRenderReco(reco){
|
|||||||
if(desc && reco && reco.why) desc.textContent = reco.why;
|
if(desc && reco && reco.why) desc.textContent = reco.why;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bascule entre « moteur de l'image » (une ligne d'état) et les trois modes
|
||||||
|
// d'installation gérés par Loki.
|
||||||
|
function lcRenderProvided(s){
|
||||||
|
const box = document.getElementById('lc-provided');
|
||||||
|
const modes = document.querySelector('.lc-modes');
|
||||||
|
if(!box || !modes) return;
|
||||||
|
box.style.display = s.provided ? '' : 'none';
|
||||||
|
modes.style.display = s.provided ? 'none' : '';
|
||||||
|
if(!s.provided) return;
|
||||||
|
const bin = document.getElementById('lc-provided-bin');
|
||||||
|
if(bin) bin.textContent = s.config_bin || '';
|
||||||
|
const job = document.getElementById('lc-job');
|
||||||
|
if(job) job.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
function lcRenderMode(mode, installed){
|
function lcRenderMode(mode, installed){
|
||||||
const card = document.getElementById(mode==='fast' ? 'lc-mode-fast' : 'lc-mode-opt');
|
const card = document.getElementById(mode==='fast' ? 'lc-mode-fast' : 'lc-mode-opt');
|
||||||
const state = document.getElementById(mode==='fast' ? 'lc-fast-state' : 'lc-opt-state');
|
const state = document.getElementById(mode==='fast' ? 'lc-fast-state' : 'lc-opt-state');
|
||||||
|
|||||||
@@ -40,11 +40,12 @@
|
|||||||
<!-- Avertissement de lancement (App Translocation macOS) — masqué par défaut. -->
|
<!-- Avertissement de lancement (App Translocation macOS) — masqué par défaut. -->
|
||||||
<div id="app-warn" class="muted" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)"></div>
|
<div id="app-warn" class="muted" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn) 45%,transparent);background:color-mix(in srgb,var(--warn) 12%,transparent)"></div>
|
||||||
<div id="model-err" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--err);border:1px solid color-mix(in srgb,var(--err) 45%,transparent);background:color-mix(in srgb,var(--err) 12%,transparent)"></div>
|
<div id="model-err" style="display:none;font-size:11px;line-height:1.5;margin:0 0 10px;padding:8px 10px;border-radius:8px;color:var(--err);border:1px solid color-mix(in srgb,var(--err) 45%,transparent);background:color-mix(in srgb,var(--err) 12%,transparent)"></div>
|
||||||
<!-- Journal du moteur : replié par défaut, ouvert au clic sur la pastille d'état.
|
<!-- Journal du moteur : replié par défaut, ouvert au clic sur la pastille d'état
|
||||||
|
OU par son propre chevron — c'est une section comme les autres, sinon on ne
|
||||||
|
trouvait pas comment la refermer.
|
||||||
C'est le seul endroit où l'on voit pourquoi un modèle refuse de charger. -->
|
C'est le seul endroit où l'on voit pourquoi un modèle refuse de charger. -->
|
||||||
<div id="svc-log-box" style="display:none;margin:0 0 10px">
|
<details id="svc-log-box" ontoggle="if(this.open){loadSvcLog();showPaths()}"><summary><span class="stitle">Journal du moteur</span></summary>
|
||||||
<div class="row" style="justify-content:space-between;align-items:center">
|
<div class="row" style="justify-content:flex-end;align-items:center">
|
||||||
<span class="io-cap">Journal du moteur</span>
|
|
||||||
<button onclick="loadSvcLog()" title="rafraîchir">↻</button>
|
<button onclick="loadSvcLog()" title="rafraîchir">↻</button>
|
||||||
</div>
|
</div>
|
||||||
<pre id="svc-log" class="muted" style="font-size:10px;line-height:1.45;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:6px 0 0"></pre>
|
<pre id="svc-log" class="muted" style="font-size:10px;line-height:1.45;max-height:220px;overflow:auto;white-space:pre-wrap;word-break:break-word;margin:6px 0 0"></pre>
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
<span class="io-cap">Emplacements</span>
|
<span class="io-cap">Emplacements</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="paths-msg" class="muted" style="font-size:10px;line-height:1.5"></div>
|
<div id="paths-msg" class="muted" style="font-size:10px;line-height:1.5"></div>
|
||||||
</div>
|
</details>
|
||||||
<!-- GPU et RAM décrivent la même chose (les ressources de la machine) :
|
<!-- GPU et RAM décrivent la même chose (les ressources de la machine) :
|
||||||
une seule section, deux blocs de statistique dans la même carte. -->
|
une seule section, deux blocs de statistique dans la même carte. -->
|
||||||
<details open><summary><span class="stitle">Machine</span></summary>
|
<details open><summary><span class="stitle">Machine</span></summary>
|
||||||
@@ -249,6 +250,15 @@
|
|||||||
même sujet. Les trois modes sont des LIGNES de cette carte (elles
|
même sujet. Les trois modes sont des LIGNES de cette carte (elles
|
||||||
étaient des cartes dans une carte). -->
|
étaient des cartes dans une carte). -->
|
||||||
<div class="slist">
|
<div class="slist">
|
||||||
|
<!-- Moteur fourni par l'image Docker : aucun des trois modes ne s'applique
|
||||||
|
(rien à installer, et l'image n'embarque ni cmake ni compilateur). -->
|
||||||
|
<div id="lc-provided" class="rowbody" style="display:none">
|
||||||
|
<div style="font-size:12px;line-height:1.5">Moteur <b>fourni par l'image Docker</b> — llama.cpp officiel, déjà compilé.
|
||||||
|
<div class="muted" style="margin-top:4px">Rien à installer ni à mettre à jour ici : le moteur suit l'image.
|
||||||
|
Pour en changer (version épinglée, CPU, Vulkan), reconstruis l'image avec le build-arg <code>LLAMACPP_IMAGE</code>.</div>
|
||||||
|
<div class="muted" style="margin-top:4px"><code id="lc-provided-bin" style="word-break:break-all"></code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- La pastille « conseillé » n'est PAS écrite ici : le bon choix dépend de
|
<!-- La pastille « conseillé » n'est PAS écrite ici : le bon choix dépend de
|
||||||
la machine (voir lcRenderReco). Sur Linux + NVIDIA le précompilé ne
|
la machine (voir lcRenderReco). Sur Linux + NVIDIA le précompilé ne
|
||||||
donne que du Vulkan — llama.cpp ne publie aucun binaire CUDA Linux —
|
donne que du Vulkan — llama.cpp ne publie aucun binaire CUDA Linux —
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ async function loadStatus(){
|
|||||||
else { me.style.display='none'; }
|
else { me.style.display='none'; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Journal du moteur — replié par défaut, on l'ouvre en cliquant la pastille.
|
// Journal du moteur — section repliable comme les autres. La pastille d'état
|
||||||
|
// reste un raccourci ; le chargement du journal est déclenché par l'événement
|
||||||
|
// `toggle` du <details>, qu'on l'ouvre par la pastille ou par son chevron.
|
||||||
function toggleSvcLog(){
|
function toggleSvcLog(){
|
||||||
const box=document.getElementById('svc-log-box');
|
const box=document.getElementById('svc-log-box');
|
||||||
if(!box) return;
|
if(!box) return;
|
||||||
const show = box.style.display==='none';
|
box.open = !box.open;
|
||||||
box.style.display = show ? '' : 'none';
|
|
||||||
if(show){ loadSvcLog(); showPaths(); }
|
|
||||||
}
|
}
|
||||||
async function loadSvcLog(){
|
async function loadSvcLog(){
|
||||||
const el=document.getElementById('svc-log');
|
const el=document.getElementById('svc-log');
|
||||||
|
|||||||
@@ -15,27 +15,34 @@ async function loadLlamacpp(){
|
|||||||
const fastInstalled = !!pb.bin;
|
const fastInstalled = !!pb.bin;
|
||||||
const optInstalled = !!s.bin;
|
const optInstalled = !!s.bin;
|
||||||
|
|
||||||
lcRenderReco(s.reco);
|
// Moteur fourni par l'image Docker : les trois modes d'installation n'ont
|
||||||
lcRenderMode('fast', fastInstalled);
|
// aucun sens (rien à installer, aucun compilateur dans l'image). On affiche
|
||||||
lcRenderMode('opt', optInstalled);
|
// l'état réel à la place — les boutons du service, eux, restent utiles.
|
||||||
lcRenderCustomCard();
|
lcRenderProvided(s);
|
||||||
|
|
||||||
// Job en cours (page rechargée pendant une install) → on raccroche l'affichage.
|
if(!s.provided){
|
||||||
if(s.job && s.job.exists && s.job.running && !lcPoll){
|
lcRenderReco(s.reco);
|
||||||
document.getElementById('lc-details').open = true;
|
lcRenderMode('fast', fastInstalled);
|
||||||
lcStartPolling();
|
lcRenderMode('opt', optInstalled);
|
||||||
|
lcRenderCustomCard();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
// Job terminé/interrompu qu'on n'a pas encore montré (rechargement APRÈS coup,
|
||||||
|
// typiquement quand le service a redémarré) : on l'affiche sans polling.
|
||||||
|
else if(s.job && s.job.exists && !s.job.running && !lcPoll && s.job.error && !lcEndShown){
|
||||||
|
document.getElementById('lc-details').open = true;
|
||||||
|
document.getElementById('lc-job').style.display = '';
|
||||||
|
lcLogNext = 0;
|
||||||
|
document.getElementById('lc-log').textContent = '';
|
||||||
|
lcEndShown = true;
|
||||||
|
lcPollJob(true); // quiet : simple rattrapage, pas de toast ni de rechargement
|
||||||
|
}
|
||||||
|
lcChipSync(s.job);
|
||||||
}
|
}
|
||||||
// Job terminé/interrompu qu'on n'a pas encore montré (rechargement APRÈS coup,
|
|
||||||
// typiquement quand le service a redémarré) : on l'affiche sans polling.
|
|
||||||
else if(s.job && s.job.exists && !s.job.running && !lcPoll && s.job.error && !lcEndShown){
|
|
||||||
document.getElementById('lc-details').open = true;
|
|
||||||
document.getElementById('lc-job').style.display = '';
|
|
||||||
lcLogNext = 0;
|
|
||||||
document.getElementById('lc-log').textContent = '';
|
|
||||||
lcEndShown = true;
|
|
||||||
lcPollJob(true); // quiet : simple rattrapage, pas de toast ni de rechargement
|
|
||||||
}
|
|
||||||
lcChipSync(s.job);
|
|
||||||
// Préchauffe la liste des cartes du moteur actif : interroger le moteur prend
|
// Préchauffe la liste des cartes du moteur actif : interroger le moteur prend
|
||||||
// 1 à 3 s (init CUDA/Vulkan), et sans ça l'encart « cartes graphiques » de
|
// 1 à 3 s (init CUDA/Vulkan), et sans ça l'encart « cartes graphiques » de
|
||||||
// l'éditeur apparaissait après coup, une fois le reste déjà affiché.
|
// l'éditeur apparaissait après coup, une fois le reste déjà affiché.
|
||||||
@@ -90,6 +97,21 @@ function lcRenderReco(reco){
|
|||||||
if(desc && reco && reco.why) desc.textContent = reco.why;
|
if(desc && reco && reco.why) desc.textContent = reco.why;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bascule entre « moteur de l'image » (une ligne d'état) et les trois modes
|
||||||
|
// d'installation gérés par Loki.
|
||||||
|
function lcRenderProvided(s){
|
||||||
|
const box = document.getElementById('lc-provided');
|
||||||
|
const modes = document.querySelector('.lc-modes');
|
||||||
|
if(!box || !modes) return;
|
||||||
|
box.style.display = s.provided ? '' : 'none';
|
||||||
|
modes.style.display = s.provided ? 'none' : '';
|
||||||
|
if(!s.provided) return;
|
||||||
|
const bin = document.getElementById('lc-provided-bin');
|
||||||
|
if(bin) bin.textContent = s.config_bin || '';
|
||||||
|
const job = document.getElementById('lc-job');
|
||||||
|
if(job) job.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
function lcRenderMode(mode, installed){
|
function lcRenderMode(mode, installed){
|
||||||
const card = document.getElementById(mode==='fast' ? 'lc-mode-fast' : 'lc-mode-opt');
|
const card = document.getElementById(mode==='fast' ? 'lc-mode-fast' : 'lc-mode-opt');
|
||||||
const state = document.getElementById(mode==='fast' ? 'lc-fast-state' : 'lc-opt-state');
|
const state = document.getElementById(mode==='fast' ? 'lc-fast-state' : 'lc-opt-state');
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ func handleLlamacpp(w http.ResponseWriter, r *http.Request) {
|
|||||||
cfgBin := ReadConfig()["BIN"]
|
cfgBin := ReadConfig()["BIN"]
|
||||||
out["config_bin"] = cfgBin
|
out["config_bin"] = cfgBin
|
||||||
out["in_use"] = bin != "" && samePath(bin, cfgBin)
|
out["in_use"] = bin != "" && samePath(bin, cfgBin)
|
||||||
|
// Moteur livré par l'image Docker : il n'y a rien à installer, et l'image
|
||||||
|
// ne contient ni cmake ni compilateur. L'UI masque alors les trois modes.
|
||||||
|
out["provided"] = engineProvided(cfgBin)
|
||||||
|
|
||||||
plan := detectBuildPlan()
|
plan := detectBuildPlan()
|
||||||
out["plan"] = map[string]any{
|
out["plan"] = map[string]any{
|
||||||
@@ -186,6 +189,40 @@ func handleLlamacpp(w http.ResponseWriter, r *http.Request) {
|
|||||||
sendJSON(w, 200, out)
|
sendJSON(w, 200, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// engineProvided : le moteur est-il fourni par l'image Docker ? Vrai quand on
|
||||||
|
// tourne en conteneur et que BIN désigne un exécutable existant SITUÉ HORS de
|
||||||
|
// LOKI_HOME — donc ni le dépôt cloné, ni les binaires précompilés, ni les
|
||||||
|
// backends custom, qui vivent tous sous LOKI_HOME et sont gérés par Loki.
|
||||||
|
//
|
||||||
|
// Sans cette distinction, l'UI proposait d'installer un moteur déjà présent, et
|
||||||
|
// l'utilisateur tombait sur « outils manquants : cmake » — l'image ne contient
|
||||||
|
// volontairement ni cmake ni compilateur, puisqu'elle part de l'image officielle
|
||||||
|
// llama.cpp où llama-server est déjà compilé.
|
||||||
|
func engineProvided(cfgBin string) bool {
|
||||||
|
if os.Getenv("LOKI_CONTAINER") != "1" || strings.TrimSpace(cfgBin) == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
bin := prebuiltResolveBin(cfgBin)
|
||||||
|
if st, err := os.Stat(bin); err != nil || st.IsDir() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
rel, err := filepath.Rel(LokiHome(), bin)
|
||||||
|
return err != nil || strings.HasPrefix(rel, "..")
|
||||||
|
}
|
||||||
|
|
||||||
|
// refuseIfProvided coupe court aux jobs d'installation/compilation quand le
|
||||||
|
// moteur vient de l'image : rien à installer, et aucun compilateur disponible.
|
||||||
|
// Renvoie true si la requête a été refusée (l'appelant doit sortir).
|
||||||
|
func refuseIfProvided(w http.ResponseWriter) bool {
|
||||||
|
if !engineProvided(ReadConfig()["BIN"]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sendJSON(w, 409, map[string]any{"ok": false, "error": "Le moteur est fourni par l'image Docker (" +
|
||||||
|
ReadConfig()["BIN"] + ") : il n'y a rien à installer ici, et l'image ne contient ni cmake ni compilateur. " +
|
||||||
|
"Pour changer de moteur, reconstruis l'image avec un autre build-arg LLAMACPP_IMAGE."})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// samePath compare deux chemins en neutralisant séparateurs, symlinks et casse
|
// samePath compare deux chemins en neutralisant séparateurs, symlinks et casse
|
||||||
// (Windows).
|
// (Windows).
|
||||||
func samePath(a, b string) bool {
|
func samePath(a, b string) bool {
|
||||||
@@ -237,6 +274,9 @@ func handleLlamacppCheck(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// handleLlamacppInstall lance le job d'installation (clone + build + BIN).
|
// handleLlamacppInstall lance le job d'installation (clone + build + BIN).
|
||||||
func handleLlamacppInstall(w http.ResponseWriter, r *http.Request) {
|
func handleLlamacppInstall(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if refuseIfProvided(w) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var req struct {
|
var req struct {
|
||||||
Force bool `json:"force"`
|
Force bool `json:"force"`
|
||||||
}
|
}
|
||||||
@@ -253,6 +293,9 @@ func handleLlamacppInstall(w http.ResponseWriter, r *http.Request) {
|
|||||||
// compilé pour la machine, SANS toucher au BIN global. Il apparaît ensuite dans
|
// compilé pour la machine, SANS toucher au BIN global. Il apparaît ensuite dans
|
||||||
// /api/backends et se choisit par modèle (éditeur de preset → Moteur).
|
// /api/backends et se choisit par modèle (éditeur de preset → Moteur).
|
||||||
func handleLlamacppInstallCustom(w http.ResponseWriter, r *http.Request) {
|
func handleLlamacppInstallCustom(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if refuseIfProvided(w) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var req struct {
|
var req struct {
|
||||||
Repo string `json:"repo"`
|
Repo string `json:"repo"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -286,6 +329,9 @@ func lcRunCustomInstall(url, name, ref string) {
|
|||||||
// handleLlamacppUpdate lance le job de mise à jour (pull + rebuild + restart).
|
// handleLlamacppUpdate lance le job de mise à jour (pull + rebuild + restart).
|
||||||
// {clean:true} force une recompilation from scratch même sans nouveau commit.
|
// {clean:true} force une recompilation from scratch même sans nouveau commit.
|
||||||
func handleLlamacppUpdate(w http.ResponseWriter, r *http.Request) {
|
func handleLlamacppUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if refuseIfProvided(w) {
|
||||||
|
return
|
||||||
|
}
|
||||||
var req struct {
|
var req struct {
|
||||||
Clean bool `json:"clean"`
|
Clean bool `json:"clean"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user