Claude f99e5b59b8 Refonte de l'interface : direction « Sober Tech »
Reprise du design d'après la maquette fournie, sans changer d'architecture :
l'UI reste du HTML/CSS/JS assemblé dans le binaire (voir plus bas).

Charte
- Palette ardoise + sauge en remplacement des bruns « Terre ». Deux variantes :
  claire par défaut (celle de la maquette) et « Deep Dark » (fond #0F172A,
  cartes #1E293B), à un clic depuis l'en-tête. Une variable --on-accent porte ce
  qui s'écrit sur les aplats de sauge, pour que le contraste tienne dans les
  deux variantes.
- Typographie Inter (interface) + JetBrains Mono (code, chiffres, chemins), en
  sous-ensemble latin, embarquées comme l'étaient Bricolage et IBM Plex Mono —
  toujours aucune requête vers un service de polices.
- Boutons sans contour, fond au survol, léger enfoncement au clic.
- Coque à plat : plus de cartes flottantes séparées par une gouttière, la barre
  latérale est collée au bord et le fil occupe tout le reste.

Coque
- Barre d'en-tête : titre de la discussion + sélecteur de modèle. Changer de
  preset demandait d'ouvrir la barre latérale et de descendre jusqu'aux
  presets ; c'est désormais une liste déroulante, toujours visible.
- Barre latérale en trois zones — marque, contenu défilant, moniteur machine —
  et escamotable d'un clic sur grand écran. Les discussions y passent au
  premier plan, avec une recherche textuelle (filtrage côté client : la liste
  est déjà chargée, sans les messages) ; les réglages descendent sous un repli
  unique, d'où openDetails(), qui déplie aussi les parents.
- Moniteur machine en pied de colonne : une jauge par ressource (charge GPU,
  puis VRAM et température en détail, mémoire vive), sauge jusqu'à 75 %, ambre
  puis rouille quand la machine sature. Il remplace la section « Machine », qui
  disait la même chose en plus verbeux et en plus loin.
- L'option « barre latérale escamotable » disparaît d'Apparence : elle faisait
  de la barre un tiroir posé SUR la conversation, là où le bouton d'en-tête
  l'escamote pour de bon. Deux mécanismes concurrents pour la même intention.

Fil et saisie
- La réponse de l'IA redevient une carte, la question un aplat de sauge : sur un
  fond de fil coloré, du texte nu flottait sans ancrage.
- Saisie en pilule, ses outils (joindre, fichiers, envoyer) dans la barre
  elle-même. L'envoi est une pastille ronde à flèche ; le mot « Envoyer » reste
  porté par aria-label et l'infobulle.

Corrections croisées
- L'heure d'une discussion prenait la moitié de la ligne (flex:1 hérité de
  `.preset>span`), le titre était tronqué au premier mot.
- Une liste déroulante posée directement dans une ligne de modale débordait
  sous son intitulé quand sa valeur était longue (chemin de destination).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd
2026-08-16 16:17:59 +00:00
2026-06-08 12:54:49 +02:00

Loki — assistant IA local en conteneur (fork d'AJEAN)

Loki est un fork de AJEAN de nathaninline, sous licence MIT — voir NOTICE.md et LICENSE. L'essentiel du code et des fonctionnalités vient d'AJEAN ; ce fork le rebaptise et le fait tourner dans un conteneur Docker GPU autonome, là où l'amont s'installe en binaire + systemd sur la machine hôte.

Loki fait tourner un modèle de langage 100 % en local : discussions multiples, mémoire persistante, accès internet, captures de pages web, outils MCP, agent (shell, fichiers) — serveur d'inférence llama.cpp compris, dans une seule image.

Architecture

┌────────────────── conteneur loki ──────────────────┐
│  loki web  (UI + API, port 8090, premier plan)     │
│     │ pilote (fichier PID — pas de systemd)        │
│  loki serve ──exec──► llama-server (CUDA, :8080)   │
│                        ▲ modèles .gguf             │
│  chromium (Playwright) — captures de pages web     │
│  /data (config, bbolt, presets, mémoire,           │
│         workspace par discussion, modèles)         │
│  /models (GGUF déposés à la main)                  │
└────────────────────────────────────────────────────┘
  • Un seul conteneur : l'UI joint le moteur sur localhost (contrainte héritée de l'amont), les deux partagent donc le même conteneur.
  • Sans systemd : l'amont pilote le moteur via systemctl ; en conteneur, Loki bascule automatiquement sur une supervision par fichier PID (internal/loki/sys_service_container.go). Changer de modèle depuis l'UI redémarre le moteur normalement.
  • Le moteur (port 8080, non authentifié par défaut) n'est pas exposé ; seule l'UI (8090) l'est.

Démarrage rapide (Docker, GPU NVIDIA)

Pré-requis : pilote NVIDIA + NVIDIA Container Toolkit.

cp .env.example .env
docker compose up --build   # quelques minutes : llama-server vient précompilé
                            # de l'image officielle llama.cpp (server-cuda)

Interface : http://localhost:8090 — installe un modèle depuis la recherche Hugging Face intégrée (voir ci-dessous), il démarre tout seul.

Installer un modèle

Dans l'éditeur de preset, Chercher un modèle interroge Hugging Face et ne remonte que les dépôts GGUF. Choisir un dépôt déplie ses quantifications avec leur taille et un verdict mémoire (ok / juste / trop) calculé sur la VRAM réellement détectée — ou sur la RAM système s'il n'y a pas de GPU. C'est une estimation : le coût exact du cache KV dépend de l'architecture du modèle, que la seule liste des fichiers ne révèle pas.

Si le dépôt publie un projecteur vision (mmproj-*.gguf), Loki propose de l'installer avec le modèle et remplit le champ Vision du preset. C'est le seul moyen fiable d'avoir la vision : un projecteur encode dans l'espace latent de son modèle, donc un mmproj pris dans un autre dépôt donne un moteur qui démarre et ne voit rien. Quand le dépôt n'en publie pas, Loki le dit plutôt que d'aller en chercher un ailleurs.

Deux repères pour choisir un dépôt :

  • unsloth/* publie des quantifications Dynamic (UD-Q4_K_XL, UD-IQ3_XXS…) qui gardent en plus haute précision les tenseurs sensibles : à taille égale, elles se tiennent mieux qu'un Q4_K_M classique.
  • ggml-org/* est le dépôt de référence de l'équipe llama.cpp — c'est en général là que le projecteur vision est publié en premier.

Le champ Télécharger un modèle reste disponible pour coller un lien direct (dépôt privé, fichier hors des conventions). Un dépôt à accès restreint demande la variable d'environnement HF_TOKEN.

Installation sur Unraid

L'image est construite et publiée par GitHub Actions sur GHCR (ghcr.io/r0m1k3/loki:latest) à chaque push sur main — aucun build sur Unraid. Compose prêt à l'emploi : docker-compose.unraid.yml.

  1. Installe le plugin Nvidia Driver (Apps) et vérifie nvidia-smi.
  2. Crée les dossiers :
    mkdir -p /mnt/user/appdata/loki/data /mnt/user/appdata/loki/models
    
  3. Plugin Compose Manager → nouvelle stack → colle docker-compose.unraid.yml → Compose Up.
  4. Interface : http://<ip-unraid>:8090.

Configuration

Tout se règle dans l'UI (modèle, contexte, presets…) et survit aux redémarrages (volume /data). Variables d'environnement du conteneur :

Variable Rôle Défaut
LOKI_WEB_PORT port de l'UI 8090
LOKI_MODEL modèle initial (semé au 1er boot seulement) —
LOKI_CTX taille de contexte initiale 32768
LOKI_NGL couches GPU initiales 999 (tout)
LOKI_HOME données (volume) /data
LOKI_MODEL_DIRS dossiers .gguf additionnels /models
HF_TOKEN jeton Hugging Face, pour les dépôts à accès restreint —

En CLI dans le conteneur : docker exec -it loki loki status (aussi : logs, restart, config, bench, test…).

Données et persistance

Tout l'état vit sous /data (= LOKI_HOME). Si ce chemin n'est pas un volume monté sur l'hôte, il disparaît au premier docker compose down — presets et modèles compris.

Chemin Contenu
/data/loki.db base bbolt : préférences, discussions, mémoire des réglages
/data/presets/ un .env par preset (modèle, contexte, NGL, vision…)
/data/models/ modèles téléchargés depuis l'interface
/data/memory/ pages de mémoire persistante (.md)
/data/workspace/ racine du dossier de travail de l'agent
/data/workspace/discussions/<id>/ fichiers d'UNE discussion : dépôts, captures, ce que l'agent y écrit
/data/loki-engine.log journal de llama-server (aussi via loki logs)
/models GGUF déposés à la main depuis l'hôte (volume séparé, LOKI_MODEL_DIRS)

Vérifier que le volume est bien là :

docker inspect loki --format '{{range .Mounts}}{{.Source}} → {{.Destination}}{{println}}{{end}}'

Sur Unraid, garde le même chemin hôte d'un lancement à l'autre : /mnt/user/… (partage, via FUSE) et /mnt/cache/… (disque de cache) désignent des emplacements différents dès que le partage n'est pas en cache-only ou que le mover est passé. Le compose fourni utilise /mnt/user/appdata/loki/….

Autre piège au redémarrage du serveur : Docker relance les conteneurs restart: unless-stopped avant que le plugin Nvidia Driver ait chargé ses modules. Le journal montre alors des ERROR: init … result=11 et le moteur démarre sans GPU. Un docker restart loki une fois le pilote prêt suffit.

Fonctionnalités

Héritées d'AJEAN :

  • Tchat avec streaming, raisonnement visible, pièces jointes, export de conversations. La vision demande un modèle multimodal et son projecteur mmproj — voir Installer un modèle.
  • Mémoire persistante (memory off|ondemand|always).
  • Accès internet : recherche + lecture de pages, moteur Go intégré ou Crawl4AI pour les pages JS.
  • Agent : shell, fichiers, workspace (agent on).
  • Serveurs MCP : Node.js est inclus dans l'image pour les serveurs npx.
  • Presets de configuration par modèle, bench, auto-détection GPU.
  • API OpenAI-compatible exposable (network on, protégée par clé).

Ajoutées par ce fork :

  • Discussions multiples : historique complet dans la barre latérale, titre repris du premier message (renommable), suppression. Chaque discussion a son dossier de fichiers (workspace/discussions/<id>/) : les pièces jointes déposées, les captures et ce que l'agent écrit y atterrissent, le shell et les chemins relatifs du modèle y sont résolus. Changer de discussion change donc les fichiers ; supprimer (ou vider) une discussion emporte les siens, pour que le disque ne se remplisse pas en silence.
  • Recherche Hugging Face intégrée avec verdict mémoire et installation liée du projecteur vision (voir Installer un modèle).
  • Captures de pages web : l'agent dispose de l'outil web_screenshot (Chromium via Playwright, inclus dans l'image). Les captures partent en JPEG et sont plafonnées à 20 fichiers / 40 Mo par discussion. La description de l'outil suit la capacité réelle du moteur, sondée sur /props : sans vision effective, elle dit au modèle « tu ne vois pas l'image » plutôt que de lui promettre des yeux qu'il n'a pas — il peut toujours prendre la capture et la montrer, sans prétendre la décrire. L'image relayée au moteur reste éphémère : la persister gonflait le contexte jusqu'à le faire déborder.
  • Panneau Fichiers (bouton dossier de la barre de saisie) : les fichiers de la discussion ouverte — dépôts, captures, ce que l'agent y a écrit — avec navigation dans les sous-dossiers, téléchargement et suppression. Un dossier affiche la taille de tout son contenu, c'est ce qu'on libère en le supprimant, et le pied donne l'occupation disque de la discussion. Les chemins sont bornés à son dossier, liens symboliques résolus des deux côtés : ni le reste du disque ni les autres discussions ne sont atteignables. Les fichiers d'avant ce rangement que la migration n'a pas su rattacher restent joignables par le bouton hors discussion, qui disparaît une fois le ménage fait.
  • Interface « Sober Tech » : ardoise et sauge, typographie Inter (interface) et JetBrains Mono (code, chiffres, chemins) — embarquées dans le binaire, donc aucune requête vers un service de polices. Deux variantes : claire par défaut, Deep Dark (fond #0F172A, cartes #1E293B) d'un clic depuis l'en-tête. L'en-tête porte le titre de la discussion et le sélecteur de modèle (le changement de preset ne demande plus d'ouvrir les réglages) ; la barre latérale s'escamote pour rendre toute la largeur au fil ; les discussions s'y cherchent au clavier et les jauges GPU / VRAM / mémoire vive restent visibles en pied de colonne.
  • Identité : ton prénom et un avatar emoji pour toi et pour Loki, affichés dans le fil.
  • Paramètres : les réglages d'application (identité, apparence, accès OpenAI, actions) sont regroupés à part des réglages d'IA.

Retirées par ce fork :

  • Accès distant via ajean.link : la section de l'interface et son module JS sont supprimés — un conteneur derrière son propre réseau n'en a pas l'usage. Le code serveur du relais reste en place mais inerte (aucun jeton, aucune section pour en fournir un) : le retirer créerait un conflit à chaque reprise de l'amont.
  • Postes distants (faire agir l'agent sur un autre PC appairé) : bouton du composeur, modales d'appairage et module JS supprimés. Même traitement que ci-dessus — les routes /api/node/* subsistent mais plus rien ne peut générer de code d'appairage, donc aucun poste ne peut se connecter.
  • Catalogue de modèles distant : il interrogeait ajean.link/models.json, sa route n'avait aucun consommateur et son repli embarqué datait de 2024. La recherche Hugging Face le remplace.

Différences avec l'amont

AJEAN (amont) Loki (ce fork)
Installation binaire + sudo ajean install (systemd) docker compose up
Moteur llama.cpp compilé sur la machine (ajean llamacpp install) image officielle llama.cpp (server-cuda), précompilée
Panneau « Moteur » propose d'installer/compiler annonce le moteur fourni par l'image, sans proposer d'install
Supervision moteur systemd / launchd / PID (Windows) fichier PID (LOKI_CONTAINER=1)
Configuration initiale ajean edit ($EDITOR) entrypoint + loki config set
Choix du modèle lien Hugging Face collé à la main recherche intégrée + verdict VRAM + projecteur lié
Historique de tchat conversation unique discussions multiples, titrées et persistées
Accès distant relais chiffré ajean.link retiré de l'interface
Mise à jour ajean update (binaire GitHub) docker compose pull

Le reste — mémoire, outils, protocole, moteur d'inférence — est celui d'AJEAN. Pour récupérer les évolutions de l'amont :

git fetch upstream && git merge upstream/main   # conflits de renommage à arbitrer

Build sans GPU / autres accélérateurs / version épinglée

L'image Loki se construit au-dessus de l'image serveur officielle de llama.cpp, choisie par le build-arg LLAMACPP_IMAGE :

# CPU seul (test sans GPU)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server .
# Vulkan (GPU AMD/Intel/NVIDIA sans CUDA)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-vulkan .
# Version de llama.cpp épinglée (reproductible)
docker build --build-arg LLAMACPP_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda-b10423 .

Aucune compilation de llama.cpp n'a lieu : le moteur est maintenu et précompilé par l'équipe amont (toutes architectures GPU courantes).

Licence

MIT — © les contributeurs d'AJEAN (« Jean contributors ») pour le code amont, voir LICENSE et NOTICE.md.

S
Description
No description provided
Readme MIT
21 MiB
0 Stars 1 Watchers 0 Forks
Languages
Go 68.2%
HTML 18.6%
JavaScript 9.5%
CSS 3.4%
Dockerfile 0.2%