mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Corrige la confusion : deux endroits ecrivaient la ligne BIN et se battaient (la barre laterale changeait le BIN global + redemarrait, puis selectionner un preset remettait le BIN du preset). Desormais : - la section laterale 'Backend llama.cpp' sert UNIQUEMENT a installer / mettre a jour les moteurs (rapide / optimisee), elle ne change plus le BIN actif - le choix du moteur se fait PAR MODELE, dans l'editeur de preset, avec 3 options claires : Rapide (precompile) / Optimise (compile) / Personnalise (chemin libre ou backend depose dans le dossier backends de jean, detecte) - detection auto de l'option a l'ouverture selon le BIN du preset ; l'astuce indique le dossier ou deposer un binaire custom - /api/llamacpp expose backends_dir ; l'endpoint /use n'est plus utilise par l'UI v0.4.11
252 lines
22 KiB
HTML
252 lines
22 KiB
HTML
<!doctype html>
|
||
<!-- GÉNÉRÉ depuis ui/src/ par tools/assemble-ui (go generate ./internal/jean) — NE PAS ÉDITER index.html DIRECTEMENT -->
|
||
<html lang="fr"><head>
|
||
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||
<!-- PWA standalone : "Ajouter à l'écran d'accueil" sur iPhone → app plein écran
|
||
SANS la barre d'onglets Safari (indispensable pour enregistrer des démos). -->
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||
<meta name="apple-mobile-web-app-title" content="Jean">
|
||
<title>Jean</title>
|
||
<!-- Favicon (même marque « ajean » que la landing/portail) + icône PWA (écran d'accueil
|
||
iOS). SVG inline pour le favicon, PNG 180×180 en data-URI pour apple-touch-icon
|
||
(iOS n'accepte pas le SVG pour l'icône d'accueil). Aucun fichier externe requis. -->
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><rect width='12' height='12' rx='2' ry='2' fill='%231f6feb'/><rect x='6' y='3' width='2' height='2' fill='%23fff'/><rect x='6' y='5' width='2' height='2' fill='%23fff'/><rect x='4' y='7' width='2' height='2' fill='%23fff'/></svg>">
|
||
<link rel="apple-touch-icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAIAAACyr5FlAAABa0lEQVR42u3dsQ2AIBBAUSCOYA8b4iiMSI9D2FpYGTEheW8AisvPUV7MdQR4kowAcSAOxIE4EAfiQByIA3EgDhAH4kAciANxIA7EgTgQB+IAcSAOxIE4EAfiQByIA3EgDhAH4kAciANxIA7EgTgQB+JAHCAOxMEHNiO4622f9HI5TpsD3wriQBwgDsSBOBAH4kAciANxIA7EAeJAHIgDcSAOxIE4EAfiQBwgDsSBOBAH4kAciANxIA7EgThAHIgDcSAOxIE4EAfiQByIA8SBOBAH4kAciANxIA7EgThAHIgDcSAO/rLkLXsX520OxIE4EAfiQByIA8SBOBAH4kAciANxIA7EgThAHIgDcSAOxIE4EAfiQByIA8SBOHgl5jpMAZsDcSAOxIE4EAfiQByIA3GAOBAH4kAciANxIA7EgTgQB4gDcSAOxIE4EAfiQByIA3EgDhAH4kAciANxIA7EgTgQB+IAcSAOxME0F8YvCl24O02KAAAAAElFTkSuQmCC">
|
||
<!-- Applique le thème AVANT le rendu (pas de flash) : lit le choix persisté. -->
|
||
<script>try{document.documentElement.setAttribute('data-theme',localStorage.getItem('jean-theme')||'dark');document.documentElement.setAttribute('data-display',localStorage.getItem('jean-display')||'full')}catch(e){document.documentElement.setAttribute('data-theme','dark');document.documentElement.setAttribute('data-display','full')}</script>
|
||
<style>
|
||
@@CSS@@
|
||
</style></head><body>
|
||
<button id="menubtn" onclick="toggleSide()">☰</button>
|
||
<div id="backdrop" onclick="toggleSide()"></div>
|
||
<div class="side" id="side">
|
||
<div class="sidehead">
|
||
<h1 id="brand"><span id="brand-a">a</span>jean<span id="ver"></span></h1>
|
||
<span id="status-svc" class="statuspill">…</span>
|
||
</div>
|
||
<details open><summary>GPU</summary>
|
||
<div id="vram" class="muted">…</div>
|
||
</details>
|
||
<details open id="cfg-details"><summary>Config active</summary>
|
||
<div id="cfg" class="muted">…</div>
|
||
</details>
|
||
<details><summary>Presets<button class="preset-add" onclick="event.preventDefault();event.stopPropagation();openPreset('')" title="ajouter">+</button></summary>
|
||
<div id="presets"></div>
|
||
</details>
|
||
<details><summary>Mode agent <span id="agent-badge" style="margin-left:auto;margin-right:12px;font-size:10px"></span></summary>
|
||
<label class="switchrow"><span class="switch"><input type="checkbox" id="agent-toggle" onchange="toggleAgent()"><span class="slider"></span></span> activer le mode agent<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">⚠️ active l'<b>accès machine</b> (shell complet via <b>bash</b> sur le serveur) — l'IA peut inspecter, lancer des scripts, lire/éditer des fichiers (timeout 30s, max 300s). Mémoire et accès internet ci-dessous ne fonctionnent que si le mode agent est activé.</span></span></label>
|
||
<!-- Mémoire / Accès internet / Paramètres : sous-réglages du mode agent, en cartes. Grisés/inertes quand l'agent est off (voir setAgentGate). -->
|
||
<div id="mem-block" class="gated-block">
|
||
<div class="subhead">Mémoire<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span id="mem-mode-desc" class="tip"></span></span></div>
|
||
<label class="switchrow" style="justify-content:flex-start;gap:12px"><span>mode</span>
|
||
<select id="mem-mode" onchange="setMemMode()" style="flex:1;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px">
|
||
<option value="always">auto (proactive)</option>
|
||
<option value="ondemand">sur demande</option>
|
||
<option value="off">désactivée</option>
|
||
</select>
|
||
</label>
|
||
<div id="mem-pages-bar" class="pages-bar" onclick="toggleMemPages()">
|
||
<span class="pages-caret">▸</span>
|
||
<span class="pages-title">Pages <span id="mem-count" class="mem-count"></span></span>
|
||
<button class="addbtn" onclick="event.stopPropagation();openMem('')" title="ajouter une page mémoire">+ ajouter</button>
|
||
</div>
|
||
<div id="mem-pages-body" hidden>
|
||
<input id="mem-search" class="mem-search" type="search" placeholder="filtrer la mémoire…" oninput="renderMemList()" style="display:none">
|
||
<div id="mem-list" class="mem-list muted" style="font-size:12px"></div>
|
||
</div>
|
||
</div>
|
||
<div id="net-block" class="gated-block">
|
||
<div class="subhead">Accès internet<span id="internet-badge" style="margin-left:6px;font-size:10px"></span><span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">Ajoute les outils <b>web_search / web_open / web_read / web_grep</b> via un serveur <b>Crawl4AI</b>. Actifs seulement si le serveur répond.</span></span></div>
|
||
<label class="switchrow"><span class="switch"><input type="checkbox" id="internet-toggle" onchange="toggleInternet()"><span class="slider"></span></span> donner internet à l'IA</label>
|
||
<div class="row" style="margin-top:6px">
|
||
<input id="crawl-url" type="text" placeholder="http://localhost:11235" style="flex:1;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px;font:inherit" onchange="saveCrawlUrl()">
|
||
<button onclick="saveCrawlUrl()">enregistrer</button>
|
||
</div>
|
||
<div id="internet-status" class="muted" style="font-size:11px;margin-top:4px"></div>
|
||
</div>
|
||
<div id="param-block" class="gated-block">
|
||
<div class="subhead">Paramètres</div>
|
||
<label class="switchrow"><span class="switch"><input type="checkbox" id="toollimit-toggle" onchange="toggleToolLimit()"><span class="slider"></span></span> limiter les appels d'outils par tour<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">activé par défaut : coupe l'IA après ~8 appels d'outils (message <code>[stop: trop d'appels d'outils]</code>). Désactive-le si tu veux la laisser enchaîner sans plafond (l'anti-boucle reste actif).</span></span></label>
|
||
<label class="switchrow" style="margin-top:8px"><span class="switch"><input type="checkbox" id="compact-toggle" onchange="toggleCompact()"><span class="slider"></span></span> compactage automatique du contexte<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">activé par défaut : quand la conversation approche de la limite de contexte, les vieux tours sont résumés automatiquement (façon Hermes) au lieu de t'imposer un « vider ». Discussions quasi illimitées sans perdre le fil.</span></span></label>
|
||
</div>
|
||
</details>
|
||
<details><summary>Apparence</summary>
|
||
<label class="switchrow" style="justify-content:space-between;gap:12px"><span>thème</span>
|
||
<select id="theme-select" onchange="applyTheme(this.value);savePrefs()" style="flex:1;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px"></select>
|
||
</label>
|
||
<label class="switchrow" style="justify-content:space-between;gap:12px;margin-top:8px"><span>affichage<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip"><b>Complet</b> : tout est visible (raisonnement, appels d'outils, vitesse, config active). <b>Simple</b> : masque le raisonnement, les appels d'outils, les détails de vitesse sur les bulles et la config active à gauche.</span></span></span>
|
||
<select id="display-select" onchange="applyDisplay(this.value);savePrefs()" style="flex:1;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px">
|
||
<option value="full">complet</option>
|
||
<option value="simple">simple</option>
|
||
</select>
|
||
</label>
|
||
</details>
|
||
<details><summary>System prompt</summary>
|
||
<textarea id="sysprompt" placeholder="(optionnel) ex: tu es un assistant concis en français" oninput="saveSys()" style="width:100%;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit;min-height:70px;resize:vertical"></textarea>
|
||
</details>
|
||
<details><summary>Accès OpenAI</summary>
|
||
<div class="subhead">Endpoint compatible OpenAI<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">Branche n'importe quel client compatible OpenAI (OpenCode, Continue, Cursor…) sur cette URL. Modèle : <code>jean</code>. Si une clé est définie, le client doit envoyer <code>Authorization: Bearer <clé></code>.</span></span></div>
|
||
<label class="switchrow" style="margin-top:6px"><span class="switch"><input type="checkbox" id="oai-public-toggle" onchange="toggleOAIPublic()"><span class="slider"></span></span> exposer en public (ajean.link)<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">Rend ton IA joignable depuis <b>n'importe où</b> via <code>https://<machine>.oai.ajean.link/v1</code> (pour brancher un SaaS). Le trafic est chiffré <b>de bout en bout</b> jusqu'à ce serveur — le relais ajean.link ne voit rien. Nécessite un abonnement ajean.link actif.</span></span></label>
|
||
<div id="oai-public-wrap" style="display:none;margin-top:4px">
|
||
<div class="muted" style="font-size:11px;margin-bottom:2px">🌍 public (ajean.link) — accessible partout, TLS de bout en bout jusqu'à ce serveur</div>
|
||
<div class="row">
|
||
<input id="oai-public-url" readonly style="flex:1;min-width:0;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px;font:inherit;font-size:12px">
|
||
<button onclick="copyText(document.getElementById('oai-public-url').value,'URL publique copiée')" title="copier">⧉</button>
|
||
</div>
|
||
</div>
|
||
<div id="oai-local-wrap" style="margin-top:4px">
|
||
<div class="muted" style="font-size:11px;margin-bottom:2px">🏠 local (réseau)</div>
|
||
<div class="row">
|
||
<input id="oai-url" readonly style="flex:1;min-width:0;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px;font:inherit;font-size:12px">
|
||
<button onclick="copyText(document.getElementById('oai-url').value,'URL copiée')" title="copier">⧉</button>
|
||
</div>
|
||
</div>
|
||
<div class="muted" style="font-size:11px;margin-top:3px">modèle : <code>jean</code></div>
|
||
<div class="subhead" style="margin-top:12px">Clé API<span class="help" tabindex="0" onclick="event.preventDefault();event.stopPropagation();this.classList.toggle('open')">?<span class="tip">Protège l'endpoint des complétions (llama-server). Indispensable avant d'exposer le serveur sur internet. Modifier la clé <b>redémarre</b> le service.</span></span></div>
|
||
<div class="row" style="margin-top:4px">
|
||
<input id="oai-key" readonly style="flex:1;min-width:0;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px;font:inherit;font-size:12px">
|
||
<button id="oai-key-eye" onclick="toggleKeyReveal()" title="afficher / masquer">👁</button>
|
||
<button onclick="copyApiKey()" title="copier la clé">⧉</button>
|
||
</div>
|
||
<div class="row" style="margin-top:6px">
|
||
<button onclick="apiKeyAction('generate')">générer</button>
|
||
<button onclick="apiKeySet()">définir…</button>
|
||
<button onclick="apiKeyAction('clear')">retirer</button>
|
||
</div>
|
||
</details>
|
||
<details id="lc-details"><summary>Backend llama.cpp</summary>
|
||
<div id="lc-status" class="lc-head muted">…</div>
|
||
<div class="lc-modes">
|
||
<div class="lc-mode" id="lc-mode-fast" onclick="lcPick('fast')">
|
||
<div class="lc-mode-t">⚡ Version rapide <span class="lc-reco">conseillé</span></div>
|
||
<div class="lc-mode-d">prête à l'emploi, installée en ~2 min</div>
|
||
<div class="lc-mode-state" id="lc-fast-state"></div>
|
||
</div>
|
||
<div class="lc-mode" id="lc-mode-opt" onclick="lcPick('opt')">
|
||
<div class="lc-mode-t">🔧 Version optimisée</div>
|
||
<div class="lc-mode-d">compilée pour ta machine, plus longue</div>
|
||
<div class="lc-mode-state" id="lc-opt-state"></div>
|
||
</div>
|
||
</div>
|
||
<div id="lc-job" style="display:none;margin-top:10px">
|
||
<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> détails</div>
|
||
<pre id="lc-log" hidden></pre>
|
||
</div>
|
||
</details>
|
||
<details><summary>Service</summary>
|
||
<div class="row">
|
||
<button onclick="act('start')">start</button>
|
||
<button onclick="act('restart')">restart</button>
|
||
<button onclick="act('stop')">stop</button>
|
||
</div>
|
||
</details>
|
||
<details id="upd-details"><summary>Actions</summary>
|
||
<div class="row"><button id="upd-check" onclick="checkUpdate()">↥ Vérifier les mises à jour</button></div>
|
||
<div id="upd-msg" class="muted" style="font-size:12px;margin-top:6px;line-height:1.5"></div>
|
||
<div class="row" style="margin-top:6px">
|
||
<button onclick="loadAll()">↻ refresh</button>
|
||
<button onclick="resetChat()">⌫ clear chat</button>
|
||
<button id="btn-bench" onclick="runBenchUI()">⚡ bench</button>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
<div class="main" style="position:relative">
|
||
<div id="chat"></div>
|
||
<button id="scrollbtn" onclick="jumpBottom()" title="aller en bas">↓</button>
|
||
<div id="composer">
|
||
<div id="ctxtrack"><div id="ctx-fill"></div></div>
|
||
<div id="ctxmeta">
|
||
<span id="status-preset" class="muted" style="font-size:10px;letter-spacing:.03em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis"></span>
|
||
<span style="display:flex;align-items:center;gap:10px;margin-left:auto">
|
||
<span id="ctx-text" class="muted">contexte 0 / 0</span>
|
||
<button id="ctx-compact" onclick="compactContext()">compacter</button>
|
||
</span>
|
||
</div>
|
||
<div id="inputbar">
|
||
<textarea id="input" placeholder="message…" onkeydown="onKey(event)"></textarea>
|
||
<button id="send" onclick="send()">send</button>
|
||
<button id="stop" onclick="stopGen()" style="display:none;background:var(--danger-bg);border-color:var(--err);color:var(--err)">stop</button>
|
||
</div>
|
||
<div id="sendhint" class="muted" style="padding:0 12px 6px;font-size:10px;text-align:center;opacity:.7">Entrée pour envoyer · Maj+Entrée = nouvelle ligne</div>
|
||
</div>
|
||
</div>
|
||
<div id="toast"></div>
|
||
<div id="bench-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:30;align-items:center;justify-content:center;padding:20px" onclick="if(event.target===this)closeBenchModal()">
|
||
<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;width:100%;max-width:480px;display:flex;flex-direction:column">
|
||
<div style="padding:14px 16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
|
||
<strong>⚡ Benchmark</strong>
|
||
<button onclick="closeBenchModal()" style="margin:0">×</button>
|
||
</div>
|
||
<div id="bench-body" style="padding:18px 20px;display:flex;flex-direction:column;gap:12px"></div>
|
||
<div style="padding:12px 16px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:6px">
|
||
<button onclick="closeBenchModal()">fermer</button>
|
||
<button id="bench-rerun" onclick="runBenchUI()" style="border-color:var(--accent);color:var(--accent)">relancer</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="ask-modal" class="ask-overlay" style="display:none" onclick="if(event.target===this)askResolve(false)">
|
||
<div class="ask-box">
|
||
<div id="ask-title" class="ask-title"></div>
|
||
<div id="ask-msg" class="ask-msg"></div>
|
||
<input id="ask-input" class="ask-input" style="display:none">
|
||
<div class="ask-actions">
|
||
<button id="ask-cancel" onclick="askResolve(false)">Annuler</button>
|
||
<button id="ask-ok" class="ask-ok" onclick="askResolve(true)">Confirmer</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:30;align-items:center;justify-content:center;padding:20px">
|
||
<div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;width:100%;max-width:700px;max-height:90vh;display:flex;flex-direction:column">
|
||
<div style="padding:14px 16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center">
|
||
<strong id="modal-title">Preset</strong>
|
||
<button onclick="closeModal()" style="margin:0">×</button>
|
||
</div>
|
||
<div style="padding:14px 16px;display:flex;flex-direction:column;gap:10px;overflow:auto;flex:1">
|
||
<label class="muted">Nom <span style="opacity:.6">(espaces et accents OK, sauf / et \)</span></label>
|
||
<input id="m-name" style="background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit">
|
||
<div id="m-model-row" style="display:none">
|
||
<label class="muted">Moteur (backend) <span style="opacity:.6">— quel llama.cpp fait tourner ce modèle</span></label>
|
||
<div class="be-opts">
|
||
<label class="be-opt"><input type="radio" name="m-be" value="fast" onchange="onBackendMode('fast')"><span>⚡ Rapide</span><span class="be-note" id="be-fast-note"></span></label>
|
||
<label class="be-opt"><input type="radio" name="m-be" value="opt" onchange="onBackendMode('opt')"><span>🔧 Optimisé</span><span class="be-note" id="be-opt-note"></span></label>
|
||
<label class="be-opt"><input type="radio" name="m-be" value="custom" onchange="onBackendMode('custom')"><span>📁 Personnalisé</span></label>
|
||
</div>
|
||
<div id="m-backend-custom" style="display:none;margin:0 0 10px">
|
||
<input id="m-backend-path" oninput="onCustomPath()" placeholder="chemin vers llama-server(.exe)" style="width:100%;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit">
|
||
<select id="m-backend-detected" onchange="onPickDetected()" style="width:100%;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit;margin-top:6px"></select>
|
||
<div class="muted" id="be-drop-hint" style="font-size:11px;margin-top:4px"></div>
|
||
</div>
|
||
<label class="muted">Modèle <span style="opacity:.6">(remplace la ligne MODEL=)</span></label>
|
||
<select id="m-model" onchange="onPickModel()" style="width:100%;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit;margin-top:6px"></select>
|
||
<label class="muted" style="margin-top:10px;display:block">Télécharger depuis Hugging Face <span style="opacity:.6">(lien vers un .gguf)</span></label>
|
||
<div style="display:flex;gap:6px;margin-top:6px">
|
||
<input id="m-hf-url" placeholder="https://huggingface.co/…/resolve/main/model.gguf" style="flex:1;min-width:0;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit">
|
||
<button id="m-hf-btn" onclick="startDownload()" style="flex-shrink:0">⬇ télécharger</button>
|
||
</div>
|
||
<div id="m-hf-progress" class="muted" style="display:none;font-size:11px;margin-top:6px"></div>
|
||
<label class="muted" style="margin-top:10px;display:block">Quantization (tag) <span style="opacity:.6">(vide = détection auto depuis le nom du modèle)</span></label>
|
||
<input id="m-quant" oninput="applyQuant()" placeholder="ex: Q4_K_M, IQ3_XXS, BF16…" style="width:100%;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit;margin-top:6px">
|
||
</div>
|
||
<label class="muted">Contenu</label>
|
||
<textarea id="m-content" spellcheck="false" style="background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font:inherit;min-height:280px;resize:vertical"></textarea>
|
||
</div>
|
||
<div style="padding:14px 16px;border-top:1px solid var(--border);display:flex;justify-content:space-between;gap:6px;flex-wrap:wrap">
|
||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
||
<button id="m-del" onclick="delItem()" style="background:var(--danger-bg);border-color:var(--err);color:var(--err);margin:0">supprimer</button>
|
||
<label id="m-del-model-wrap" style="display:none;align-items:center;gap:5px;font-size:11px;color:var(--dim)"><input type="checkbox" id="m-del-model"> + le modèle .gguf</label>
|
||
</div>
|
||
<div style="display:flex;gap:6px">
|
||
<button onclick="closeModal()">annuler</button>
|
||
<button onclick="saveItem()" style="border-color:var(--accent);color:var(--accent)">enregistrer</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script src="marked.min.js"></script>
|
||
<script>
|
||
@@JS@@
|
||
</script></body></html>
|