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
|
alive = True
|
||||||
break
|
break
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
alive = True # PC on, service down
|
alive = True
|
||||||
break
|
break
|
||||||
except (socket.timeout, OSError):
|
except (socket.timeout, OSError):
|
||||||
continue # PC off ou inaccessible
|
continue
|
||||||
|
|
||||||
jean_alive_cache["alive"] = alive
|
jean_alive_cache["alive"] = alive
|
||||||
jean_alive_cache["timestamp"] = now
|
jean_alive_cache["timestamp"] = now
|
||||||
return alive
|
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):
|
def wait_for_jean(trigger_wol=True):
|
||||||
"""Attend que Jean soit accessible. Si ENABLE_WOL et trigger_wol, envoie WoL d'abord."""
|
"""Attend que Jean soit accessible. Si ENABLE_WOL et trigger_wol, envoie WoL d'abord."""
|
||||||
alive = jean_alive()
|
alive = jean_alive()
|
||||||
@@ -888,6 +906,9 @@ def chat_completions():
|
|||||||
data, fwd_headers
|
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"):
|
if not ensure_vram_for_backend("jean"):
|
||||||
return jsonify({"error": "Failed to prepare VRAM for Jean"}), 503
|
return jsonify({"error": "Failed to prepare VRAM for Jean"}), 503
|
||||||
|
|
||||||
@@ -994,13 +1015,9 @@ def dashboard():
|
|||||||
@app.route("/api/dashboard/status")
|
@app.route("/api/dashboard/status")
|
||||||
def dashboard_status():
|
def dashboard_status():
|
||||||
"""Etat complet en JSON"""
|
"""Etat complet en JSON"""
|
||||||
jean_ok = jean_alive()
|
pc_alive = jean_alive()
|
||||||
olla_ok = False
|
jean_ok = jean_service_ok() if pc_alive else False
|
||||||
try:
|
olla_ok = ollama_service_ok() if pc_alive else False
|
||||||
r = requests.get(f"http://{OLLAMA_DIRECT_HOST}:{OLLAMA_DIRECT_PORT}/api/version", timeout=2)
|
|
||||||
olla_ok = r.ok
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(f"http://{JEAN_WEB_HOST}:{JEAN_WEB_PORT}/api/presets", timeout=1)
|
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)
|
stats = dict(request_stats)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
|
"pc": {
|
||||||
|
"alive": pc_alive,
|
||||||
|
"host": JEAN_WEB_HOST,
|
||||||
|
},
|
||||||
"jean": {
|
"jean": {
|
||||||
"alive": jean_ok,
|
"alive": jean_ok,
|
||||||
"host": f"{JEAN_WEB_HOST}:{JEAN_WEB_PORT}",
|
"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)}
|
.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{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 .error{color:var(--red)}
|
||||||
#logs .warn{color:var(--yellow)}
|
#logs .warn{color:#f0883e;font-weight:500}
|
||||||
#logs .info{color:var(--muted)}
|
#logs .info{color:var(--muted)}
|
||||||
#logs .debug{color:#484f58}
|
#logs .debug{color:#484f58}
|
||||||
#logs .highlight{color:var(--green);font-weight:700}
|
#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="grid">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>🔌 Statut</h2>
|
<h2>🔌 Statut</h2>
|
||||||
<div class="row"><span class="label">Jean</span><span id="jean-status">-</span></div>
|
<div class="row"><span class="label">PC Gaming</span><span id="pc-status">-</span></div>
|
||||||
<div class="row"><span class="label">Ollama</span><span id="ollama-status">-</span></div>
|
<div class="row"><span class="label">Jean (8090)</span><span id="jean-status">-</span></div>
|
||||||
<div class="row"><span class="label">VRAM Backend</span><span id="vram-status">-</span></div>
|
<div class="row"><span class="label">Ollama (11434)</span><span id="ollama-status">-</span></div>
|
||||||
<div class="row"><span class="label">Preset actif</span><span id="active-preset">-</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>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>🎰 Slot Jean</h2>
|
<h2>🎰 Slot Jean</h2>
|
||||||
@@ -1211,9 +1233,18 @@ async function fetchStatus() {
|
|||||||
const d = await r.json();
|
const d = await r.json();
|
||||||
|
|
||||||
// Status dots
|
// Status dots
|
||||||
$('#jean-status').innerHTML = (d.jean.alive ? '<span class="status-dot on"></span>' : '<span class="status-dot off"></span>') + 'Jean : ' + d.jean.host;
|
$('#pc-status').innerHTML = (d.pc.alive
|
||||||
$('#ollama-status').innerHTML = (d.ollama.alive ? '<span class="status-dot on"></span>' : '<span class="status-dot off"></span>') + 'Ollama : ' + d.ollama.host;
|
? '<span class="status-dot on"></span> ON'
|
||||||
$('#vram-status').innerHTML = (d.jean.vram_backend === 'jean' ? '<span class="badge badge-blue">JEAN</span>' : '<span class="badge badge-green">OLLAMA</span>');
|
: '<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>';
|
$('#active-preset').innerHTML = '<span class="badge badge-green">' + d.jean.active_preset + '</span>';
|
||||||
|
|
||||||
// Slot
|
// Slot
|
||||||
|
|||||||
Reference in New Issue
Block a user