mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Sélecteur de moteur par modèle : « Image » en conteneur, et mention du fork
Le sélecteur de l'éditeur de modèle proposait encore « Précompilé » et « Compilé » — deux installations que Loki ne fait pas en conteneur : cliquer répondait « installez d'abord llama.cpp… ». Pire, le moteur de l'image ne correspondant à aucun des deux, il était classé « Personnalisé ». En conteneur, ces deux options laissent place à « Image » (sélectionnée par défaut, y compris pour un preset sans BIN) ; « Personnalisé » reste pour un binaire déposé dans /data/backends. Le moteur de l'image est désormais déclaré par l'image elle-même via LOKI_ENGINE_BIN (Dockerfile + entrypoint) au lieu d'être deviné d'après le chemin : /api/llamacpp expose provided et provided_bin. Attribution : sous le nom Loki, « fork de AJEAN » avec lien vers le dépôt d'origine. Vérifié dans l'image : provided=true, provided_bin=/app/llama-server, BIN semé identique ; build, vet et tests verts.
This commit is contained in:
7 files changed
+88
-31
No files matched your search
@@ -47,6 +47,7 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh && mkdir -p /data /models
|
||||
ENV LOKI_CONTAINER=1 \
|
||||
LOKI_HOME=/data \
|
||||
LOKI_MODEL_DIRS=/models \
|
||||
LOKI_ENGINE_BIN=/app/llama-server \
|
||||
LD_LIBRARY_PATH=/app \
|
||||
NVIDIA_VISIBLE_DEVICES=all \
|
||||
NVIDIA_DRIVER_CAPABILITIES=compute,utility
|
||||
|
||||
@@ -9,7 +9,7 @@ mkdir -p "$LOKI_HOME"
|
||||
# Le chemin du moteur est imposé par l'image (llama-server précompilé de
|
||||
# l'image officielle llama.cpp, dans /app) : on le (re)pose à chaque boot,
|
||||
# une mise à jour de l'image ne doit pas laisser un BIN obsolète en base.
|
||||
loki config set "BIN=/app/llama-server"
|
||||
loki config set "BIN=${LOKI_ENGINE_BIN:-/app/llama-server}"
|
||||
|
||||
# Les autres clés ne sont semées QUE si absentes : ce que l'utilisateur règle
|
||||
# ensuite dans l'UI (modèle, contexte…) est conservé d'un redémarrage à l'autre.
|
||||
|
||||
@@ -133,7 +133,12 @@ h1{margin:0;font-size:18px;color:var(--accent)}
|
||||
#brand svg{height:10px;width:auto;display:block;shape-rendering:crispEdges;fill:currentColor}
|
||||
#brand-word{display:inline-flex;color:var(--accent)}
|
||||
#ver{font-size:10px;font-weight:400;color:var(--dim);margin-left:7px;letter-spacing:0;align-self:flex-end;line-height:1;position:relative;top:1px}
|
||||
.sidehead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:18px}
|
||||
.sidehead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
|
||||
/* Attribution : Loki est un fork d'AJEAN (MIT). Discrète mais permanente, et le
|
||||
nom du projet d'origine renvoie à son dépôt. */
|
||||
.brand-fork{font-size:10px;color:var(--dim);margin:0 0 14px;line-height:1.3}
|
||||
.brand-fork a{color:var(--dim);text-decoration:underline;text-underline-offset:2px}
|
||||
.brand-fork a:hover{color:var(--accent)}
|
||||
/* pastille d'état service, en haut à droite de la barre latérale */
|
||||
.statuspill{display:inline-flex;align-items:center;gap:6px;font-size:11px;padding:3px 10px;border-radius:999px;border:1px solid var(--border);background:var(--panel);color:var(--dim);font-weight:600;white-space:nowrap;cursor:pointer}
|
||||
.statuspill.ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}
|
||||
@@ -1207,6 +1212,7 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
||||
<h1 id="brand" aria-label="loki" title="Loki — fork d'AJEAN (github.com/nathaninline/ajean, MIT)"><span id="brand-a"><svg viewBox="0 0 4 5" shape-rendering="crispEdges" fill="currentColor"><rect x="0" y="0" width="1" height="5"/><rect x="1" y="4" width="3" height="1"/></svg></span><span id="brand-word"><svg viewBox="0 0 11 5" shape-rendering="crispEdges" fill="currentColor"><rect x="0" y="0" width="3" height="1"/><rect x="0" y="1" width="1" height="3"/><rect x="2" y="1" width="1" height="3"/><rect x="0" y="4" width="3" height="1"/><rect x="4" y="0" width="1" height="5"/><rect x="6" y="0" width="1" height="2"/><rect x="5" y="2" width="1" height="1"/><rect x="6" y="3" width="1" height="2"/><rect x="8" y="0" width="3" height="1"/><rect x="9" y="1" width="1" height="3"/><rect x="8" y="4" width="3" height="1"/></svg></span><span id="ver"></span></h1>
|
||||
<span id="status-svc" class="statuspill" onclick="toggleSvcLog()" title="voir le journal du moteur">…</span>
|
||||
</div>
|
||||
<div class="brand-fork">fork de <a href="https://github.com/nathaninline/ajean" target="_blank" rel="noopener noreferrer" title="AJEAN par nathaninline — licence MIT">AJEAN</a></div>
|
||||
<!-- 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="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>
|
||||
@@ -1839,9 +1845,13 @@ button:hover{border-color:var(--dim);color:var(--text)}
|
||||
|
||||
<div class="pe-group">
|
||||
<div class="pe-gh">Moteur</div>
|
||||
<!-- « Image » n'apparaît qu'en conteneur (moteur fourni), où
|
||||
« Précompilé » et « Compilé » sont au contraire masqués : ils
|
||||
désignent des installations que Loki ne fait pas ici. -->
|
||||
<div class="pe-seg">
|
||||
<label><input type="radio" name="m-be" value="fast" onchange="onBackendMode('fast')"><span>Précompilé</span><span class="be-note" id="be-fast-note"></span></label>
|
||||
<label><input type="radio" name="m-be" value="opt" onchange="onBackendMode('opt')"><span>Compilé</span><span class="be-note" id="be-opt-note"></span></label>
|
||||
<label id="be-lab-image" style="display:none"><input type="radio" name="m-be" value="image" onchange="onBackendMode('image')"><span>Image</span><span class="be-note" id="be-image-note"></span></label>
|
||||
<label id="be-lab-fast"><input type="radio" name="m-be" value="fast" onchange="onBackendMode('fast')"><span>Précompilé</span><span class="be-note" id="be-fast-note"></span></label>
|
||||
<label id="be-lab-opt"><input type="radio" name="m-be" value="opt" onchange="onBackendMode('opt')"><span>Compilé</span><span class="be-note" id="be-opt-note"></span></label>
|
||||
<label><input type="radio" name="m-be" value="custom" onchange="onBackendMode('custom')"><span>Personnalisé</span></label>
|
||||
</div>
|
||||
<div id="m-backend-custom" class="pe-list" style="display:none;margin-top:8px">
|
||||
@@ -3341,13 +3351,21 @@ function underDir(p, dir){
|
||||
const n = x => String(x||'').replace(/\\/g,'/').replace(/\/+$/,'').toLowerCase();
|
||||
return !!p && !!dir && n(p).startsWith(n(dir)+'/');
|
||||
}
|
||||
let beFastPath = '', beOptPath = '', beFastDir = '';
|
||||
let beFastPath = '', beOptPath = '', beFastDir = '', beImagePath = '';
|
||||
async function populateBackend(){
|
||||
// Chemins des deux moteurs gérés + liste des backends détectés (dossier loki).
|
||||
let lc = {}; try{ lc = await jget('/api/llamacpp'); }catch(_){}
|
||||
beFastPath = (lc.prebuilt && lc.prebuilt.bin) || '';
|
||||
beFastDir = (lc.prebuilt && lc.prebuilt.dir) || '';
|
||||
beOptPath = lc.bin || '';
|
||||
// Conteneur : le moteur vient de l'image. « Précompilé » et « Compilé »
|
||||
// désignent des installations que Loki ne fait pas ici — les proposer ne
|
||||
// menait qu'à « installez d'abord… ». On les remplace par « Image ».
|
||||
beImagePath = lc.provided ? (lc.provided_bin || '') : '';
|
||||
document.getElementById('be-lab-image').style.display = beImagePath ? '' : 'none';
|
||||
document.getElementById('be-lab-fast').style.display = beImagePath ? 'none' : '';
|
||||
document.getElementById('be-lab-opt').style.display = beImagePath ? 'none' : '';
|
||||
document.getElementById('be-image-note').textContent = beImagePath ? 'llama.cpp officiel' : '';
|
||||
// Menu « backend détecté » du mode personnalisé : tout ce qu'on trouve dans
|
||||
// le dossier backends de loki (l'utilisateur peut y déposer son propre build).
|
||||
const detected = await jget('/api/backends');
|
||||
@@ -3360,7 +3378,10 @@ async function populateBackend(){
|
||||
// Sélectionne l'option correspondant au BIN actuel du preset.
|
||||
const cur = currentBinInTextarea();
|
||||
let mode = 'custom';
|
||||
if(sameBinPath(cur, beFastPath) || underDir(cur, beFastDir)) mode = 'fast';
|
||||
// Un preset sans BIN hérite du moteur global : en conteneur c'est celui de
|
||||
// l'image, qu'on affiche comme tel plutôt qu'en « personnalisé ».
|
||||
if(beImagePath && (sameBinPath(cur, beImagePath) || !cur)) mode = 'image';
|
||||
else if(sameBinPath(cur, beFastPath) || underDir(cur, beFastDir)) mode = 'fast';
|
||||
else if(sameBinPath(cur, beOptPath)) mode = 'opt';
|
||||
const radio = document.querySelector('input[name=m-be][value='+mode+']');
|
||||
if(radio) radio.checked = true;
|
||||
@@ -3376,7 +3397,11 @@ function toggleBackendCustom(mode){
|
||||
}
|
||||
function onBackendMode(mode){
|
||||
toggleBackendCustom(mode);
|
||||
if(mode === 'fast'){
|
||||
if(mode === 'image'){
|
||||
if(!beImagePath){ toast('aucun moteur fourni par l\'image'); return; }
|
||||
setBinInTextarea(beImagePath); toast('moteur : llama.cpp de l\'image');
|
||||
loadGpuDevices();
|
||||
} else if(mode === 'fast'){
|
||||
if(!beFastPath){ toast('installez d\'abord llama.cpp précompilé (section MOTEUR)'); return; }
|
||||
setBinInTextarea(beFastPath); toast('moteur : llama.cpp précompilé');
|
||||
loadGpuDevices();
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<h1 id="brand" aria-label="loki" title="Loki — fork d'AJEAN (github.com/nathaninline/ajean, MIT)"><span id="brand-a"><svg viewBox="0 0 4 5" shape-rendering="crispEdges" fill="currentColor"><rect x="0" y="0" width="1" height="5"/><rect x="1" y="4" width="3" height="1"/></svg></span><span id="brand-word"><svg viewBox="0 0 11 5" shape-rendering="crispEdges" fill="currentColor"><rect x="0" y="0" width="3" height="1"/><rect x="0" y="1" width="1" height="3"/><rect x="2" y="1" width="1" height="3"/><rect x="0" y="4" width="3" height="1"/><rect x="4" y="0" width="1" height="5"/><rect x="6" y="0" width="1" height="2"/><rect x="5" y="2" width="1" height="1"/><rect x="6" y="3" width="1" height="2"/><rect x="8" y="0" width="3" height="1"/><rect x="9" y="1" width="1" height="3"/><rect x="8" y="4" width="3" height="1"/></svg></span><span id="ver"></span></h1>
|
||||
<span id="status-svc" class="statuspill" onclick="toggleSvcLog()" title="voir le journal du moteur">…</span>
|
||||
</div>
|
||||
<div class="brand-fork">fork de <a href="https://github.com/nathaninline/ajean" target="_blank" rel="noopener noreferrer" title="AJEAN par nathaninline — licence MIT">AJEAN</a></div>
|
||||
<!-- 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="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>
|
||||
@@ -669,9 +670,13 @@
|
||||
|
||||
<div class="pe-group">
|
||||
<div class="pe-gh">Moteur</div>
|
||||
<!-- « Image » n'apparaît qu'en conteneur (moteur fourni), où
|
||||
« Précompilé » et « Compilé » sont au contraire masqués : ils
|
||||
désignent des installations que Loki ne fait pas ici. -->
|
||||
<div class="pe-seg">
|
||||
<label><input type="radio" name="m-be" value="fast" onchange="onBackendMode('fast')"><span>Précompilé</span><span class="be-note" id="be-fast-note"></span></label>
|
||||
<label><input type="radio" name="m-be" value="opt" onchange="onBackendMode('opt')"><span>Compilé</span><span class="be-note" id="be-opt-note"></span></label>
|
||||
<label id="be-lab-image" style="display:none"><input type="radio" name="m-be" value="image" onchange="onBackendMode('image')"><span>Image</span><span class="be-note" id="be-image-note"></span></label>
|
||||
<label id="be-lab-fast"><input type="radio" name="m-be" value="fast" onchange="onBackendMode('fast')"><span>Précompilé</span><span class="be-note" id="be-fast-note"></span></label>
|
||||
<label id="be-lab-opt"><input type="radio" name="m-be" value="opt" onchange="onBackendMode('opt')"><span>Compilé</span><span class="be-note" id="be-opt-note"></span></label>
|
||||
<label><input type="radio" name="m-be" value="custom" onchange="onBackendMode('custom')"><span>Personnalisé</span></label>
|
||||
</div>
|
||||
<div id="m-backend-custom" class="pe-list" style="display:none;margin-top:8px">
|
||||
|
||||
@@ -384,13 +384,21 @@ function underDir(p, dir){
|
||||
const n = x => String(x||'').replace(/\\/g,'/').replace(/\/+$/,'').toLowerCase();
|
||||
return !!p && !!dir && n(p).startsWith(n(dir)+'/');
|
||||
}
|
||||
let beFastPath = '', beOptPath = '', beFastDir = '';
|
||||
let beFastPath = '', beOptPath = '', beFastDir = '', beImagePath = '';
|
||||
async function populateBackend(){
|
||||
// Chemins des deux moteurs gérés + liste des backends détectés (dossier loki).
|
||||
let lc = {}; try{ lc = await jget('/api/llamacpp'); }catch(_){}
|
||||
beFastPath = (lc.prebuilt && lc.prebuilt.bin) || '';
|
||||
beFastDir = (lc.prebuilt && lc.prebuilt.dir) || '';
|
||||
beOptPath = lc.bin || '';
|
||||
// Conteneur : le moteur vient de l'image. « Précompilé » et « Compilé »
|
||||
// désignent des installations que Loki ne fait pas ici — les proposer ne
|
||||
// menait qu'à « installez d'abord… ». On les remplace par « Image ».
|
||||
beImagePath = lc.provided ? (lc.provided_bin || '') : '';
|
||||
document.getElementById('be-lab-image').style.display = beImagePath ? '' : 'none';
|
||||
document.getElementById('be-lab-fast').style.display = beImagePath ? 'none' : '';
|
||||
document.getElementById('be-lab-opt').style.display = beImagePath ? 'none' : '';
|
||||
document.getElementById('be-image-note').textContent = beImagePath ? 'llama.cpp officiel' : '';
|
||||
// Menu « backend détecté » du mode personnalisé : tout ce qu'on trouve dans
|
||||
// le dossier backends de loki (l'utilisateur peut y déposer son propre build).
|
||||
const detected = await jget('/api/backends');
|
||||
@@ -403,7 +411,10 @@ async function populateBackend(){
|
||||
// Sélectionne l'option correspondant au BIN actuel du preset.
|
||||
const cur = currentBinInTextarea();
|
||||
let mode = 'custom';
|
||||
if(sameBinPath(cur, beFastPath) || underDir(cur, beFastDir)) mode = 'fast';
|
||||
// Un preset sans BIN hérite du moteur global : en conteneur c'est celui de
|
||||
// l'image, qu'on affiche comme tel plutôt qu'en « personnalisé ».
|
||||
if(beImagePath && (sameBinPath(cur, beImagePath) || !cur)) mode = 'image';
|
||||
else if(sameBinPath(cur, beFastPath) || underDir(cur, beFastDir)) mode = 'fast';
|
||||
else if(sameBinPath(cur, beOptPath)) mode = 'opt';
|
||||
const radio = document.querySelector('input[name=m-be][value='+mode+']');
|
||||
if(radio) radio.checked = true;
|
||||
@@ -419,7 +430,11 @@ function toggleBackendCustom(mode){
|
||||
}
|
||||
function onBackendMode(mode){
|
||||
toggleBackendCustom(mode);
|
||||
if(mode === 'fast'){
|
||||
if(mode === 'image'){
|
||||
if(!beImagePath){ toast('aucun moteur fourni par l\'image'); return; }
|
||||
setBinInTextarea(beImagePath); toast('moteur : llama.cpp de l\'image');
|
||||
loadGpuDevices();
|
||||
} else if(mode === 'fast'){
|
||||
if(!beFastPath){ toast('installez d\'abord llama.cpp précompilé (section MOTEUR)'); return; }
|
||||
setBinInTextarea(beFastPath); toast('moteur : llama.cpp précompilé');
|
||||
loadGpuDevices();
|
||||
|
||||
@@ -107,7 +107,12 @@ h1{margin:0;font-size:18px;color:var(--accent)}
|
||||
#brand svg{height:10px;width:auto;display:block;shape-rendering:crispEdges;fill:currentColor}
|
||||
#brand-word{display:inline-flex;color:var(--accent)}
|
||||
#ver{font-size:10px;font-weight:400;color:var(--dim);margin-left:7px;letter-spacing:0;align-self:flex-end;line-height:1;position:relative;top:1px}
|
||||
.sidehead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:18px}
|
||||
.sidehead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
|
||||
/* Attribution : Loki est un fork d'AJEAN (MIT). Discrète mais permanente, et le
|
||||
nom du projet d'origine renvoie à son dépôt. */
|
||||
.brand-fork{font-size:10px;color:var(--dim);margin:0 0 14px;line-height:1.3}
|
||||
.brand-fork a{color:var(--dim);text-decoration:underline;text-underline-offset:2px}
|
||||
.brand-fork a:hover{color:var(--accent)}
|
||||
/* pastille d'état service, en haut à droite de la barre latérale */
|
||||
.statuspill{display:inline-flex;align-items:center;gap:6px;font-size:11px;padding:3px 10px;border-radius:999px;border:1px solid var(--border);background:var(--panel);color:var(--dim);font-weight:600;white-space:nowrap;cursor:pointer}
|
||||
.statuspill.ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent);background:color-mix(in srgb,var(--ok) 12%,transparent)}
|
||||
|
||||
@@ -163,8 +163,11 @@ func handleLlamacpp(w http.ResponseWriter, r *http.Request) {
|
||||
out["config_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)
|
||||
// ne contient ni cmake ni compilateur. L'UI masque alors les trois modes,
|
||||
// et le sélecteur par modèle propose « Image » au lieu de « Précompilé /
|
||||
// Compilé », qui ne désignent rien ici.
|
||||
out["provided"] = engineProvided()
|
||||
out["provided_bin"] = providedEngineBin()
|
||||
|
||||
plan := detectBuildPlan()
|
||||
out["plan"] = map[string]any{
|
||||
@@ -189,36 +192,39 @@ func handleLlamacpp(w http.ResponseWriter, r *http.Request) {
|
||||
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.
|
||||
// providedEngineBin renvoie le moteur livré par l'image Docker, ou "" hors
|
||||
// conteneur. L'image le déclare elle-même via LOKI_ENGINE_BIN (voir Dockerfile
|
||||
// et docker-entrypoint.sh) : pas de chemin en dur ici, et n'importe quelle image
|
||||
// de base convient tant qu'elle pose cette variable.
|
||||
//
|
||||
// Sans cette distinction, l'UI proposait d'installer un moteur déjà présent, et
|
||||
// Sans cette notion, 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
|
||||
func providedEngineBin() string {
|
||||
p := strings.TrimSpace(os.Getenv("LOKI_ENGINE_BIN"))
|
||||
if p == "" {
|
||||
return ""
|
||||
}
|
||||
bin := prebuiltResolveBin(cfgBin)
|
||||
if st, err := os.Stat(bin); err != nil || st.IsDir() {
|
||||
return false
|
||||
if st, err := os.Stat(prebuiltResolveBin(p)); err != nil || st.IsDir() {
|
||||
return ""
|
||||
}
|
||||
rel, err := filepath.Rel(LokiHome(), bin)
|
||||
return err != nil || strings.HasPrefix(rel, "..")
|
||||
return p
|
||||
}
|
||||
|
||||
// engineProvided : le moteur vient-il de l'image ? (raccourci de lecture)
|
||||
func engineProvided() bool { return providedEngineBin() != "" }
|
||||
|
||||
// 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"]) {
|
||||
bin := providedEngineBin()
|
||||
if 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. " +
|
||||
sendJSON(w, 409, map[string]any{"ok": false, "error": "Le moteur est fourni par l'image Docker (" + 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
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user