Compare commits

Author SHA1 Message Date
Folzo 9439307e6a jean-router: contexte reel depuis llama-server + overrides
- Interroge llama-server:8080 pour le n_ctx du modele actif
- JEAN_CTX_OVERRIDES prioritaire si defini
- Fallback: Ollama matching → heuristique
- Plus de devinette, le contexte est precis
2026-08-02 10:25:51 +02:00
Folzo fcaad763da dashboard: plus de spam [Presets] Erreur depuis le polling
- dashboard_status utilise le cache presets au lieu d'appeler Jean
- jean_service_ok/ollama_service_ok silencieux (pas de warning log)
- slot check uniquement si jean est UP
- [Presets] Erreur ne vient plus du dashboard mais d'OpenFox/OpenWebUI
2026-08-02 09:53:29 +02:00
Folzo e93ab95350 jean-router: detection a 3 niveaux - PC / Jean / Ollama
- PC: TCP connect (ON/OFF) → WoL uniquement si OFF
- Jean: HTTP /api/presets (UP/DOWN)
- Ollama: HTTP /api/version (UP/DOWN)
- Dashboard: 3 lignes de statut distinctes
- WoL ne se declenche que si PC OFF, pas si service DOWN
2026-08-02 01:19:35 +02:00
Folzo dc900172f2 jean-router: detection PC via TCP connect au lieu de HTTP
- TCP connect vers 8090 ou 11434 (pas de requete HTTP)
- ConnectionRefused = PC allume (service down)
- Timeout = PC eteint → WoL
- Plus de spam HTTP vers un serveur bloque
2026-08-02 01:15:46 +02:00
Folzo 697e4e36c9 jean-router: WoL ne se declenche plus si Ollama repond (PC allume)
- jean_alive verifie Jean(8090) OU Ollama(11434)
- WoL seulement si les DEUX sont inaccessibles
- Logs WoL espaces a 5s au lieu de 2s
2026-08-02 01:13:21 +02:00
Folzo bb15bd8d24 dashboard: supprimer le spam de logs DEBUG et reduire le polling
- urllib3/requests en WARNING (plus de 'Starting new HTTP connection')
- QueueHandler en INFO (plus de DEBUG)
- Polling status reduit de 3s a 10s
2026-08-02 01:11:49 +02:00
Folzo 62bb38ecff jean-router: dashboard HTML de diagnostic temps reel
- /dashboard : page HTML avec statut, slot, stats, actions
- /api/dashboard/status : JSON etat complet (Jean, Ollama, slot, VRAM)
- /api/dashboard/logs/stream : SSE logs en temps reel
- /api/dashboard/logs : derniers logs JSON
- /api/dashboard/actions/refresh : force rafraichissement cache
- /api/dashboard/actions/restart-jean : restart Jean via WoL
- Tracking des requetes (total, jean, ollama, erreurs)
- Log buffer en memoire avec QueueHandler
2026-08-02 01:08:55 +02:00
Folzo 06285b8d4f jean-router: streaming de messages d'attente pendant le WoL
- Quand le PC est eteint/en veille, stream immediat de messages
- 'PC de jeu se reveille...' → 'Magic packet envoye...' → 'Demarrage X%...'
- Une fois pret, forward la vraie reponse en stream
- Plus de blocage silencieux, l'utilisateur voit la progression
2026-08-01 19:27:54 +02:00
Folzo f2bcfb98e3 jean-router: WoL plus robuste + retry sur echec upstream
- Retry avec WoL quand la requete upstream echoue (connexion refusee)
- Logs plus verbeux dans wait_for_jean
- Cache jean_alive reduit a 2s
2026-08-01 08:51:30 +02:00
Folzo 4f8a5288ff jean-router: ajout Wake-on-LAN
- Detection si Jean/Ollama inaccessible
- Envoi magic packet WoL vers TARGET_MAC (fallback PC_GAMING_MAC)
- Attente WAKE_TIMEOUT secondes que la machine demarre
- Integration dans get_presets, get_ollama_models, chat_completions
- Verrous pour eviter les WoL simultanes
- Active via ENABLE_WOL=true
2026-08-01 08:20:35 +02:00
Folzo 68a76aa254 jean-router: utiliser le nom d'affichage (name) comme id modele
- /v1/models expose name au lieu de l'id technique des presets Jean
- Routing: resolution name -> id interne pour le switch
- Correspondance bidirectionnelle dans chat_completions
2026-07-26 21:30:32 +02:00
Folzo cbb43ad0f3 docs: ajout procedures mise a jour OpenFox et jean-router 2026-07-22 22:00:31 +02:00
Folzo 4f95757489 jean-router: resolution dynamique des context_length + max_tokens + capabilities
- Suppression du preset_ctx_map code en dur
- Resolution dynamique: Jean /v1/models → matching Ollama → heuristique
- Ajout max_tokens / max_input_tokens dans /v1/models
- Enrichissement Ollama via /api/show pour donnees manquantes
- Detection capabilities (vision, thinking) pour presets Jean
- Auto-doublement max_tokens pour presets reasoning=on
- Timeout switch augmente a 15s avec retry
- Tracking du dernier preset actif (bypass bug Jean active=false)
- Cache TTL configurable (15s par defaut), ?refresh=true
- Plan de test des capacites LLM
2026-07-22 21:59:07 +02:00
2 changed files with 1166 additions and 54 deletions
+907 -50
View File
File diff suppressed because it is too large Load Diff
+255
View File
@@ -0,0 +1,255 @@
# Plan de test — Capacités des LLM (vision, thinking)
## 1. Vérification de /v1/models
```bash
# Vérifier que les champs sont bien présents
curl -s http://localhost:3014/v1/models | python3 -c "
import json, sys
data = json.load(sys.stdin)['data']
for m in data:
ctx = m.get('context_length', '?')
max_tok = m.get('max_tokens', '?')
max_in = m.get('max_input_tokens', '?')
caps = m.get('capabilities', [])
print(f'{m[\"id\"]:45s} | ctx={str(ctx):>8s} | max_tok={str(max_tok):>8s} | caps={caps}')
"
# Forcer le refresh
curl -s "http://localhost:3014/v1/models?refresh=true" | python3 -c "..."
```
**Checklist :**
- [ ] Tous les modèles ont `context_length` (pas `?` ni `None`)
- [ ] Tous les modèles ont `max_tokens` et `max_input_tokens`
- [ ] Les modèles ont `capabilities` (pas vide, min `["completion"]`)
- [ ] Le preset "Ornith 1.0 35b Q4 MOE" a des champs valides
---
## 2. Test de vision (multimodal)
### 2.1 — Modèles censés supporter la vision (selon `/v1/models`)
| Modèle Ollama | Vision annoncée |
|---------------|----------------|
| qwen3.5:9b | vision |
| qwen3.5:0.8b | vision |
| qwen3.5:4b | vision |
| qwen3.5:2b | vision |
| qwen3.5 (latest) | vision |
| gemma4:12b | vision |
| ministral-3:14b | vision |
```bash
# Script de test (enregistre comme test_vision.sh)
for MODEL in qwen3.5:9b qwen3.5:4b qwen3.5:2b gemma4:12b ministral-3:14b; do
echo "=== Test vision: $MODEL ==="
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL\",
\"messages\": [{
\"role\": \"user\",
\"content\": \"Décris ce que tu vois dans l'image.\"
}],
\"max_tokens\": 100
}" | python3 -c "
import json, sys
d = json.load(sys.stdin)
if 'error' in d:
print(f' ERREUR: {d[\"error\"]}')
else:
content = d['choices'][0]['message']['content']
print(f' REPONSE: {content[:200]}')
"
echo ""
done
```
### 2.2 — Test avec image réelle
```bash
# Encoder une image en base64 (necessite une image de test)
IMAGE_B64=$(base64 -w0 /path/to/test-image.jpg)
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{
\"model\": \"qwen3.5:9b\",
\"messages\": [{
\"role\": \"user\",
\"content\": [
{\"type\": \"text\", \"text\": \"Décris cette image en une phrase.\"},
{\"type\": \"image_url\", \"image_url\": {\"url\": \"data:image/jpeg;base64,$IMAGE_B64\"}}
]
}],
\"max_tokens\": 200
}" | python3 -m json.tool
```
---
## 3. Test de thinking/reasoning
### 3.1 — Modèles censés supporter le thinking
| Modèle | Thinking annoncé |
|--------|-----------------|
| qwen3.5:9b | thinking |
| qwen3.5:0.8b | thinking |
| qwen3.5:4b | thinking |
| qwen3.5:2b | thinking |
| qwen3.5 (latest) | thinking |
| qwen3:8b | thinking |
| deepseek-r1:14b | thinking |
| deepseek-r1 | thinking |
| gemma4:12b | thinking |
| gemma4:26b | thinking |
| gemma4:e4b | thinking |
| magistral | thinking |
| gpt-oss | thinking |
| gemma4 (latest) | thinking |
```bash
# Test de raisonnement
for MODEL in deepseek-r1:14b qwen3.5:9b qwen3:8b gemma4:12b; do
echo "=== Test thinking: $MODEL ==="
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL\",
\"messages\": [{
\"role\": \"user\",
\"content\": \"Si un train part de Paris à 100 km/h et un autre de Lyon à 150 km/h, distance 400 km, combien de temps avant qu'ils se croisent ? Explique ton raisonnement étape par étape.\"
}],
\"max_tokens\": 500
}" | python3 -c "
import json, sys
d = json.load(sys.stdin)
if 'error' in d:
print(f' ERREUR: {d[\"error\"]}')
else:
content = d['choices'][0]['message']['content']
print(f' REPONSE: {content[:300]}')
# Vérifier si la réponse contient un raisonnement structuré
has_reasoning = any(kw in content.lower() for kw in ['étape', 'd\'abord', 'premièrement', 'step', 'first', 'raisonn'])
print(f' STRUCTURE_VISIBLE: {has_reasoning}')
"
echo ""
done
```
### 3.2 — Test thinking avec le paramètre OpenAI `reasoning_effort`
> Pour les modèles Jean avec `reasoning: "on"` (Ornith, qwen3.6-27b-mtp, etc.)
```bash
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "ornith-35b-q6",
"messages": [{"role": "user", "content": "Combien de 'r' y a-t-il dans le mot \"strawberry\" ?"}],
"max_tokens": 300
}' | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(json.dumps(d, indent=2)[:2000])
"
# Le modèle devrait répondre : 3 (s-t-r-a-w-b-e-r-r-y → 3 'r')
# Si thinking est actif, il devrait montrer son raisonnement
```
---
## 4. Test des modèles sans certaines capacités
```bash
# Tester un modèle sans vision — lui envoyer une image devrait échouer
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "mistral",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "Décris cette image."},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}}
]
}],
"max_tokens": 100
}' | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'Status attendu: ERREUR → Reçu: {\"error\" in d}')
"
```
---
## 5. Test de routing (Jean ↔ Ollama)
```bash
# Tester un modèle Jean (doit déclencher le switch VRAM)
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "ornith-35b-q6",
"messages": [{"role": "user", "content": "Bonjour, es-tu fonctionnel ?"}],
"max_tokens": 50
}' | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('choices',[{}])[0].get('message',{}).get('content','ERREUR:'+json.dumps(d))[:300])"
# Puis tester un modèle Ollama (doit déclencher le switch inverse)
curl -s http://localhost:3014/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "mistral",
"messages": [{"role": "user", "content": "Bonjour, es-tu fonctionnel ?"}],
"max_tokens": 50
}' | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('choices',[{}])[0].get('message',{}).get('content','ERREUR:'+json.dumps(d))[:300])"
```
---
## 6. Synthèse
| Check | Méthode |
|-------|---------|
| `/v1/models` a `max_tokens` + `max_input_tokens` | curl + jq |
| `/v1/models` a `capabilities` non-vide | curl + jq |
| Preset "Ornith 1.0 35b Q4 MOE" existe avec champs valides | curl + jq |
| Modèle `vision=true` accepte image sans erreur | curl + image base64 |
| Modèle `vision=false` rejette image | curl + image base64 |
| Modèle `thinking=true` montre raisonnement structuré | curl + analyse réponse |
| Switch Jean→Ollama fonctionne | 2 requêtes séquentielles |
| `?refresh=true` force la mise à jour du cache | 2 requêtes avec timestamp |
---
## 7. Mise à jour OpenFox
```bash
openfox update # télécharge la nouvelle version
kill $(lsof -t -i :10369) # tue l'ancien processus (sinon EADDRINUSE)
openfox # redémarre
```
---
## 8. Mise à jour jean-router sur effi-server
```bash
# Depuis la machine locale
scp jean-router/app.py effi-server:/home/effi/effi/jean-router/app.py
# Sur effi-server
ssh effi-server
cd /home/effi/effi
docker build -t effi-jean-router ./jean-router
docker stop jean-router && docker rm jean-router
docker run -d --name jean-router --network host \
--env-file /home/effi/effi/.env \
-e JEAN_WEB_HOST=192.168.1.11 \
-e OLLAMA_DIRECT_HOST=192.168.1.11 \
effi-jean-router
```