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:
+48
-17
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user