- TypeScript 98.7%
- CSS 0.9%
- Dockerfile 0.3%
|
|
||
|---|---|---|
| .impeccable | ||
| server | ||
| shared | ||
| tests | ||
| web | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| DESIGN.md | ||
| docker-compose.standalone.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| PRODUCT.md | ||
| README.md | ||
| tsconfig.base.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
Appli-Benchmark — banc d'essai de modèles d'IA
Webapp auto-hébergée pour tester de façon complète, garder l'historique et comparer des modèles d'IA, avec pour chaque chiffre une explication en français simple.
- Se connecte à n'importe quelle API que vous saisissez : vLLM, Ollama, LM Studio, llama.cpp, OpenRouter, OpenAI, Anthropic, Google Gemini… Le type d'API et la liste des modèles sont détectés automatiquement.
- Mesure la vitesse (délai avant le premier mot, vitesse d'écriture, lecture de longs textes, tenue en charge avec 1 à 32 utilisateurs simultanés, régularité, démarrage à froid).
- Mesure la qualité sur 115 tests intégrés (français majoritaire et un lot anglais), plus des tests de mémoire longue générés selon la taille de contexte du modèle : raisonnement, maths, code exécuté dans un bac à sable, connaissances, français, rédaction et traduction notées par un modèle juge, honnêteté (hallucinations), refus justes, respect de consignes, appel d'outils, JSON, mémoire longue (« aiguille dans une botte de foin »), conversation et résistance à l'injection de prompt, cohérence.
- Tests personnalisés : vos propres questions, avec réponse attendue ou critères pour le juge (import/export JSON).
- Rapports détaillés, note globale selon un profil d'usage (assistant général, développement, documents/RAG, agents), classement, comparaison de 2 à 6 modèles avec un verdict rédigé, estimation de coût (tarifs cloud ou électricité en local), export PDF / CSV / JSON.
Sommaire
- Installation sur le homelab (Docker + Traefik)
- Variante sans Traefik (réseau local uniquement)
- Premier lancement
- Utilisation
- SSO Keycloak (facultatif)
- Mise à jour, sauvegarde, dépannage
- Sécurité
- Développement
1. Installation sur le homelab (Docker + Traefik)
Sur l'hôte Docker 10.0.0.19. Toutes les commandes se tapent sur une seule ligne.
a) Copier le dossier I.A/Appli-Benchmark vers /opt/docker-compose/appli-benchmark/, par exemple depuis le dépôt :
sudo cp -r ~/Mes_Scripts/I.A/Appli-Benchmark /opt/docker-compose/appli-benchmark
b) Créer le fichier de configuration à partir du modèle :
cd /opt/docker-compose/appli-benchmark && cp .env.example .env
c) Générer la clé de chiffrement et la coller dans .env à la ligne MASTER_KEY= :
openssl rand -hex 32
⚠️ Conservez cette clé (gestionnaire de mots de passe). Si elle change ou se perd, les clés API enregistrées dans l'application deviennent illisibles : il faudra les ressaisir.
d) Préparer le dossier de données (le conteneur tourne avec l'utilisateur non privilégié node, uid 1000) :
sudo mkdir -p data/appli-benchmark && sudo chown 1000:1000 data/appli-benchmark
e) Vérifier l'unicité des noms Traefik. Les routeurs appli-benchmark / appli-benchmark-secure et le middleware appli-benchmark-redirect ne doivent exister dans aucun autre stack (un doublon casse le routage sans message d'erreur). Le sous-domaine bench.darkbobby.fr doit pointer vers Traefik.
f) Construire et démarrer :
docker compose up -d --build
L'application est alors disponible sur https://bench.darkbobby.fr.
💡 Pour réserver l'accès au réseau local, activez la ligne commentée
lan-only@file,crowdsec@filedansdocker-compose.yml, puisdocker compose up -d --force-recreate.
2. Variante sans Traefik (réseau local uniquement)
Si vous voulez simplement y accéder par http://10.0.0.19:8080 :
- Dans
.env: laissezPUBLIC_URL=vide et ajoutezCOOKIE_SECURE=false. - Lancez :
docker compose -f docker-compose.standalone.yml up -d --build
3. Premier lancement
- Affichez le code d'installation dans les journaux du conteneur :
docker logs appli-benchmark
- Ouvrez l'application dans votre navigateur, saisissez ce code, puis choisissez un identifiant et un mot de passe (12 caractères minimum). Ce compte est administrateur.
Le code n'est valable qu'une fois et change à chaque redémarrage tant qu'aucun compte n'existe. Personne ne peut donc « prendre » votre application avant vous, même si elle est exposée.
4. Utilisation
Étape 1 — Ajouter une connexion (menu Connexions API)
Saisissez l'adresse de l'API, par exemple :
| Serveur | Adresse | Clé API |
|---|---|---|
| vLLM sur le GX10 | http://10.0.0.222:8000/v1 |
celle de VLLM_API_KEY si définie |
| Stack MoE (port 8010) | http://10.0.0.222:8010/v1 |
idem |
| Ollama | http://10.0.0.222:11434 |
aucune |
| OpenAI | https://api.openai.com/v1 |
obligatoire |
| Anthropic | https://api.anthropic.com |
obligatoire |
| Google Gemini | https://generativelanguage.googleapis.com |
obligatoire |
| OpenRouter | https://openrouter.ai/api/v1 |
obligatoire |
Cliquez sur Détecter : l'application identifie le serveur (vLLM, Ollama…), liste les modèles et récupère leur taille de contexte. Le bouton Test rapide vérifie qu'un modèle répond.
Pour les services payants, indiquez le tarif en € par million de tokens (entrée / sortie) dans le tableau des modèles : les coûts seront estimés.
Étape 2 — Lancer un benchmark (menu Nouveau benchmark)
- Choisissez le modèle, le niveau (Rapide ≈ quelques minutes, Standard, Complet) et les domaines.
- Choisissez un modèle juge, de préférence plus puissant que celui testé et différent de lui. Sans juge, Rédaction et Traduction sont ignorées.
- Suivez l'avancement en direct. Vous pouvez fermer la page : le test continue sur le serveur. Un benchmark interrompu (redémarrage, erreur) peut être repris là où il s'est arrêté.
Étape 3 — Lire le rapport
- Synthèse : note globale sur 100, points forts et faibles, et ce que cela signifie concrètement.
- Vitesse : chaque mesure avec son appréciation (Excellent / Bon / Moyen / Faible) et une phrase d'explication ; graphiques de lecture de textes longs et de montée en charge.
- Qualité par domaine et Détail des tests : chaque question est consultable, avec la réponse complète du modèle, ce qui était attendu, et l'explication de la note (et l'avis du juge). Vous pouvez corriger une note à la main.
- Le bouton ? à côté de chaque chiffre explique ce qu'il signifie ; le menu Comprendre les chiffres regroupe tout le vocabulaire.
Étape 4 — Comparer et classer
- Classement : tous les modèles testés, triables par domaine, avec un radar des trois premiers.
- Comparer : 2 à 6 benchmarks côte à côte, meilleur résultat mis en évidence, graphiques et verdict rédigé.
- Réglages : ajustez le poids de chaque domaine dans la note globale selon votre usage, et indiquez la puissance électrique de votre serveur pour estimer le coût d'un modèle local.
5. SSO Keycloak (facultatif)
L'application parle OpenID Connect nativement (flux Authorization Code + PKCE) : pas besoin d'oauth2-proxy. La connexion par mot de passe local peut rester active en parallèle, pratique en secours si Keycloak est indisponible.
Côté Keycloak (realm homelab, Keycloak 26 : vérifiez l'emplacement exact des réglages dans la console) :
- Créer un client OpenID Connect, Client ID
appli-benchmark. - Client authentication : On (client confidentiel), Standard flow : On, les autres flux désactivés.
- Valid redirect URIs :
https://bench.darkbobby.fr/api/auth/oidc/callback(URI exacte, pas de joker). - Web origins :
https://bench.darkbobby.fr. - Onglet Credentials : copier le secret du client.
- Groupes (seulement si vous utilisez
OIDC_ALLOWED_GROUPS/OIDC_ADMIN_GROUPS) : ajouter un Group Membership mapper, nom de claimgroups, Add to ID token On, Full group path Off, dans le client scope dédié du client.- ⚠️ L'application demande seulement
openid profile email: ne créez pas de client scope nommégroups. C'est ce qui provoque les erreursinvalid_scope. - Les groupes AD remontent via le group-ldap-mapper du provider LDAPS (Preserve Group Inheritance : Off).
- ⚠️ L'application demande seulement
Côté application (.env) :
PUBLIC_URL=https://bench.darkbobby.fr
OIDC_ISSUER=https://auth.darkbobby.fr/realms/homelab
OIDC_CLIENT_ID=appli-benchmark
OIDC_CLIENT_SECRET=<secret copié à l'étape 5>
OIDC_ALLOWED_GROUPS=<groupe AD autorisé, ex. utilisateurs-ia>
OIDC_ADMIN_GROUPS=<groupe AD administrateur>
Appliquer la configuration :
docker compose up -d --force-recreate
Un bouton « Se connecter avec le SSO » apparaît sur la page de connexion. Pour n'autoriser que le SSO, ajoutez LOCAL_AUTH=false.
Dépannage SSO
- redirect_uri mismatch : l'URI du client Keycloak doit être exactement
https://bench.darkbobby.fr/api/auth/oidc/callback, etPUBLIC_URLdoit être enhttps://. - Votre compte n'appartient à aucun groupe autorisé : le claim
groupsest absent ou vide. Vérifiez le mapper avec l'outil d'évaluation de jeton du client dans Keycloak.
6. Mise à jour, sauvegarde, dépannage
Mettre à jour après avoir récupéré une nouvelle version du dossier (git pull du dépôt puis copie) :
docker compose up -d --build
Vos résultats, connexions et réglages sont dans data/appli-benchmark/ et sont conservés.
Sauvegarder : copiez le dossier data/appli-benchmark/ (base SQLite benchmark.sqlite et fichiers -wal/-shm) et votre MASTER_KEY. L'idéal est d'arrêter le conteneur avant la copie :
docker compose stop && sudo tar czf appli-benchmark-$(date +%F).tgz data/appli-benchmark .env && docker compose start
Dépannage
| Symptôme | Cause probable |
|---|---|
| 404 ou page Traefik par défaut | noms de routeurs en doublon avec un autre stack, ou DNS de bench.darkbobby.fr |
| « Connexion refusée » à la détection | serveur de modèles arrêté, mauvais port, ou pare-feu entre 10.0.0.19 et le GX10 |
| « Ce serveur demande une clé API » | renseigner la clé (VLLM_API_KEY pour vLLM) |
| Le modèle « épuise son budget de tokens en réfléchissant » | modèle à raisonnement : augmentez Tokens max par réponse dans les réglages avancés |
| Mémoire longue ignorée | la taille de contexte du modèle est trop petite, ou non annoncée par le serveur |
| Impossible de se connecter en mode standalone | PUBLIC_URL doit être vide et COOKIE_SECURE=false quand il n'y a pas de HTTPS |
| Erreur d'écriture au démarrage | droits du dossier : sudo chown 1000:1000 data/appli-benchmark |
7. Sécurité
| Mesure | Détail |
|---|---|
| Authentification | compte local (mot de passe haché en Argon2id, paramètres OWASP) et/ou SSO OIDC avec PKCE ; installation protégée par un code à usage unique |
| Sessions | jeton aléatoire de 256 bits stocké haché côté serveur, cookie HttpOnly + SameSite=Lax (+ Secure et préfixe __Host- en HTTPS), expiration après inactivité, révocation des autres sessions au changement de mot de passe |
| Force brute | blocage progressif après 5 échecs (par IP et par identifiant) ; temps de réponse identique que le compte existe ou non |
| Clés API | chiffrées au repos en AES-256-GCM ; jamais renvoyées au navigateur (seul un indice sk-…1234 est affiché) |
| CSRF | vérification de l'origine (Origin, Sec-Fetch-Site), API uniquement en JSON |
| En-têtes | CSP stricte (aucun script externe ni inline), HSTS, X-Frame-Options: DENY, Referrer-Policy: no-referrer, Permissions-Policy |
| Entrées | chaque requête est validée par un schéma strict (Zod), taille des requêtes limitée, requêtes SQL paramétrées |
| Requêtes sortantes | adresses de métadonnées cloud et link-local bloquées après résolution DNS (anti-SSRF et DNS rebinding), redirections refusées, délais maximaux |
| Code produit par les modèles | exécuté uniquement dans un bac à sable QuickJS/WebAssembly, sans accès disque, réseau ni processus, avec limites de mémoire et de temps ; les expressions régulières personnalisées aussi (anti-ReDoS) |
| Exports | CSV protégé contre l'injection de formules tableur |
| Conteneur | utilisateur non root, système de fichiers en lecture seule, cap_drop: ALL, no-new-privileges, limites mémoire/processus, npm retiré de l'image, aucun script d'installation tiers exécuté |
| Traçabilité | journal d'audit (connexions, échecs, ajouts/suppressions de connexions et de benchmarks) |
Recommandations :
- Contrôler les dépendances régulièrement :
npm auditpuisdocker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image appli-benchmark:localpour scanner l'image. - L'application est conçue pour contacter les adresses que vous saisissez, y compris sur le réseau local : réservez-en l'accès aux personnes de confiance (SSO avec groupe autorisé ou
lan-only).
8. Développement
Prérequis : Node.js 24 LTS.
npm install --ignore-scripts
npm run build: compile l'interface (web/dist).npm start: démarre le serveur sur le port 8080 (TypeScript exécuté directement par Node 24).npm run devetnpm run dev:web: serveur avec rechargement + interface Vite sur le port 5173.npm test: 37 tests automatiques (vérificateurs, sécurité, benchmark complet sur un faux serveur).npm run typecheck: vérification des types.node tests/mock-openai.ts 8001: faux serveur « compatible OpenAI » pour essayer l'application sans modèle réel (connexionhttp://127.0.0.1:8001/v1).
Stack : Node.js 24 (SQLite et Argon2 intégrés), Hono, Zod, openid-client, QuickJS-WASM, undici ; React 19, Vite, Tailwind CSS 4, TanStack Query, React Router, Apache ECharts.
Organisation :
shared/ types, catégories, explications des chiffres, calcul des notes et verdicts
server/src/
app.ts routes de l'API et sécurité HTTP
auth.ts comptes, sessions, SSO
providers/ connecteurs OpenAI-compatible, Ollama, Anthropic, Gemini + détection automatique
bench/ mesures de vitesse, vérificateurs, bac à sable, juge
suites/ banque de tests intégrés (version dans suites/index.ts)
runs.ts file d'attente et exécution des benchmarks
web/src/ interface (pages et composants)
tests/ tests automatiques et faux serveur
Pour ajouter des tests intégrés : éditez server/src/suites/*.ts puis incrémentez SUITE_VERSION, pour que les comparaisons signalent les runs faits sur des banques de tests différentes.