Endpoint compatible OpenAI?Branche n'importe quel client compatible OpenAI (OpenCode, Continue, Cursor…) sur cette URL. Modèle : jean. Si une clé est définie, le client doit envoyer Authorization: Bearer <clé>.
+
+
+
🌍 public (ajean.link) — accessible partout, TLS de bout en bout jusqu'à ce serveur
+
+
+
+
+
+
+
🏠 local (réseau)
+
+
+
+
+
+
modèle : jean
+
Clé API?Protège l'endpoint des complétions (llama-server). Indispensable avant d'exposer le serveur sur internet. Modifier la clé redémarre le service.
+
+
+
+
+
+
+
+
+
+
+
+ Service
+
+
+
+
+
+
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ contexte 0 / 0
+
+
+
+
+
+
+
+
+
Entrée pour envoyer · Maj+Entrée = nouvelle ligne
+
+
+
+
+
+
+ ⚡ Benchmark
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Preset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/js/00-md.js b/ui/src/js/00-md.js
new file mode 100644
index 0000000..a9db1da
--- /dev/null
+++ b/ui/src/js/00-md.js
@@ -0,0 +1,21 @@
+// marked: GFM on, no auto-breaks (single newlines stay inline).
+marked.setOptions({ gfm: true, breaks: false });
+// Pre-process to fix common LLM markdown mistakes before handing to marked:
+// - code fences glued to preceding text on the same line ("foo ```ruby ...")
+// - fences without a closing newline
+// - 3+ consecutive blank lines collapsed to one (LLMs love padding)
+function fixMd(s){
+ if(!s) return '';
+ // Force a newline before a fence that's been glued to preceding text
+ // (common LLM mistake: "...crée le fichier et```ruby"). We do NOT split
+ // *after* the fence — the part after the fence is the language identifier.
+ s = s.replace(/([^\n])(\s*)(```+|~~~+)(?=\w*\s*\n)/g, '$1\n$3');
+ // Collapse runs of blank lines that LLMs love to emit.
+ s = s.replace(/\n{3,}/g, '\n\n');
+ return s;
+}
+function md(src){ return src ? marked.parse(fixMd(src)) : ''; }
+let msgs = [];
+let busy = false;
+function toggleSide(){ document.getElementById('side').classList.toggle('open'); document.getElementById('backdrop').classList.toggle('open'); document.body.classList.toggle('drawer-open'); }
+function saveSys(){ localStorage.setItem('jean.sys', document.getElementById('sysprompt').value); }
diff --git a/ui/src/js/01-theme.js b/ui/src/js/01-theme.js
new file mode 100644
index 0000000..883476d
--- /dev/null
+++ b/ui/src/js/01-theme.js
@@ -0,0 +1,43 @@
+// ===== Thèmes ================================================================
+// Registre des thèmes disponibles. Pour en AJOUTER un : ajouter un bloc
+// [data-theme="…"] dans le