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
This commit is contained in:
Folzo
2026-08-02 01:19:35 +02:00
parent dc900172f2
commit e93ab95350
+48 -17
View File
@@ -146,16 +146,34 @@ def jean_alive() -> bool:
alive = True
break
except ConnectionRefusedError:
alive = True # PC on, service down
alive = True
break
except (socket.timeout, OSError):
continue # PC off ou inaccessible
continue
jean_alive_cache["alive"] = alive
jean_alive_cache["timestamp"] = now
return alive
def jean_service_ok() -> bool:
"""Verifie que le service Jean repond (HTTP)"""
try:
r = requests.get(f"http://{JEAN_WEB_HOST}:{JEAN_WEB_PORT}/api/presets", timeout=3)
return r.ok
except Exception:
return False
def ollama_service_ok() -> bool:
"""Verifie que le service Ollama repond (HTTP)"""
try:
r = requests.get(f"http://{OLLAMA_DIRECT_HOST}:{OLLAMA_DIRECT_PORT}/api/version", timeout=2)
return r.ok
except Exception:
return False
def wait_for_jean(trigger_wol=True):
"""Attend que Jean soit accessible. Si ENABLE_WOL et trigger_wol, envoie WoL d'abord."""
alive = jean_alive()
@@ -888,6 +906,9 @@ def chat_completions():
data, fwd_headers
)
if not jean_service_ok():
log.warning(f"[Router] PC ON mais Jean DOWN, requete vers {model_id} risque d'echouer")
if not ensure_vram_for_backend("jean"):
return jsonify({"error": "Failed to prepare VRAM for Jean"}), 503
@@ -994,13 +1015,9 @@ def dashboard():
@app.route("/api/dashboard/status")
def dashboard_status():
"""Etat complet en JSON"""
jean_ok = jean_alive()
olla_ok = False
try:
r = requests.get(f"http://{OLLAMA_DIRECT_HOST}:{OLLAMA_DIRECT_PORT}/api/version", timeout=2)
olla_ok = r.ok
except Exception:
pass
pc_alive = jean_alive()
jean_ok = jean_service_ok() if pc_alive else False
olla_ok = ollama_service_ok() if pc_alive else False
try:
r = requests.get(f"http://{JEAN_WEB_HOST}:{JEAN_WEB_PORT}/api/presets", timeout=1)
@@ -1029,6 +1046,10 @@ def dashboard_status():
stats = dict(request_stats)
return jsonify({
"pc": {
"alive": pc_alive,
"host": JEAN_WEB_HOST,
},
"jean": {
"alive": jean_ok,
"host": f"{JEAN_WEB_HOST}:{JEAN_WEB_PORT}",
@@ -1134,7 +1155,7 @@ h1{font-size:18px;color:var(--purple);margin-bottom:12px}
.badge-blue{background:#1a2a3a;color:var(--blue);border:1px solid var(--blue)}
#logs{grid-column:1/-1;height:400px;overflow-y:auto;font-size:12px;line-height:1.6;border:1px solid var(--border);border-radius:6px;padding:10px;background:#0a0e13}
#logs .error{color:var(--red)}
#logs .warn{color:var(--yellow)}
#logs .warn{color:#f0883e;font-weight:500}
#logs .info{color:var(--muted)}
#logs .debug{color:#484f58}
#logs .highlight{color:var(--green);font-weight:700}
@@ -1157,10 +1178,11 @@ h1{font-size:18px;color:var(--purple);margin-bottom:12px}
<div class="grid">
<div class="card">
<h2>🔌 Statut</h2>
<div class="row"><span class="label">Jean</span><span id="jean-status">-</span></div>
<div class="row"><span class="label">Ollama</span><span id="ollama-status">-</span></div>
<div class="row"><span class="label">VRAM Backend</span><span id="vram-status">-</span></div>
<div class="row"><span class="label">Preset actif</span><span id="active-preset">-</span></div>
<div class="row"><span class="label">PC Gaming</span><span id="pc-status">-</span></div>
<div class="row"><span class="label">Jean (8090)</span><span id="jean-status">-</span></div>
<div class="row"><span class="label">Ollama (11434)</span><span id="ollama-status">-</span></div>
<div class="row"><span class="label">VRAM</span><span id="vram-status">-</span></div>
<div class="row"><span class="label">Preset</span><span id="active-preset">-</span></div>
</div>
<div class="card">
<h2>🎰 Slot Jean</h2>
@@ -1211,9 +1233,18 @@ async function fetchStatus() {
const d = await r.json();
// Status dots
$('#jean-status').innerHTML = (d.jean.alive ? '<span class="status-dot on"></span>' : '<span class="status-dot off"></span>') + 'Jean : ' + d.jean.host;
$('#ollama-status').innerHTML = (d.ollama.alive ? '<span class="status-dot on"></span>' : '<span class="status-dot off"></span>') + 'Ollama : ' + d.ollama.host;
$('#vram-status').innerHTML = (d.jean.vram_backend === 'jean' ? '<span class="badge badge-blue">JEAN</span>' : '<span class="badge badge-green">OLLAMA</span>');
$('#pc-status').innerHTML = (d.pc.alive
? '<span class="status-dot on"></span> ON'
: '<span class="status-dot off"></span> OFF — WoL requis');
$('#jean-status').innerHTML = (d.jean.alive
? '<span class="status-dot on"></span> UP'
: (d.pc.alive ? '<span class="status-dot warn"></span> DOWN (PC ON)' : '<span class="status-dot off"></span> DOWN'));
$('#ollama-status').innerHTML = (d.ollama.alive
? '<span class="status-dot on"></span> UP'
: (d.pc.alive ? '<span class="status-dot warn"></span> DOWN (PC ON)' : '<span class="status-dot off"></span> DOWN'));
$('#vram-status').innerHTML = (d.jean.vram_backend === 'jean'
? '<span class="badge badge-blue">JEAN</span>'
: '<span class="badge badge-green">OLLAMA</span>');
$('#active-preset').innerHTML = '<span class="badge badge-green">' + d.jean.active_preset + '</span>';
// Slot