fix(llm-tui): fix card layout overlap, handle HTTP 503 loading state, and auto-switch to status tab

This commit is contained in:
Noel Bautista 2026-10-21 13:05:56 -07:00
parent ca74d9f321
commit d3b0f9ba7a
No known key found for this signature in database

View file

@ -220,6 +220,15 @@ def check_port_status(port: int) -> tuple[bool, str]:
data = json.loads(response.read().decode())
status = data.get("status", "unknown")
return True, f"Online ({status})"
except urllib.error.HTTPError as e:
if e.code == 503:
try:
data = json.loads(e.read().decode())
msg = data.get("error", {}).get("message", "Loading model")
return True, f"Loading ({msg})"
except Exception:
return True, "Loading model..."
return False, f"HTTP Error {e.code}"
except Exception:
return False, "Offline"
@ -246,6 +255,7 @@ class LLMConfigApp(App):
border: solid #3b4252;
padding: 1 2;
margin-bottom: 1;
height: auto;
}
.title {
color: #88c0d0;
@ -302,18 +312,21 @@ class LLMConfigApp(App):
border-left: thick #88c0d0;
padding: 1 2;
margin-bottom: 1;
height: auto;
}
#vram-meter {
background: #232834;
border: solid #4c566a;
padding: 1;
margin-top: 1;
height: auto;
}
#status-card {
background: #1e222b;
border: solid #4c566a;
padding: 1;
margin-bottom: 1;
height: auto;
}
Log {
background: #0f1117;
@ -339,6 +352,8 @@ class LLMConfigApp(App):
_sync_lock: bool = False
_last_selected_model: str = ""
_last_selected_mmproj: str = ""
_last_log_size: int = -1
_last_log_name: str = ""
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
@ -672,7 +687,12 @@ class LLMConfigApp(App):
lines = []
for port, label in [(11434, "Planner / Solo"), (11435, "Worker 1"), (11436, "Worker 2")]:
online, msg = check_port_status(port)
badge = "[green]● ONLINE[/]" if online else "[yellow]○ OFFLINE[/]"
if not online:
badge = "[yellow]○ OFFLINE[/]"
elif "loading" in msg.lower():
badge = "[cyan]⏳ LOADING[/]"
else:
badge = "[green]● ONLINE[/]"
lines.append(f"Port {port} ({label}): {badge} - {msg}")
card = self.query_one("#status-card", Static)
@ -684,8 +704,13 @@ class LLMConfigApp(App):
if logs:
latest = logs[0]
try:
cur_size = latest.stat().st_size
if cur_size == self._last_log_size and latest.name == self._last_log_name:
return
self._last_log_size = cur_size
self._last_log_name = latest.name
with open(latest, "r", errors="ignore") as f:
f.seek(max(0, latest.stat().st_size - 8192))
f.seek(max(0, cur_size - 16384))
tail = f.read()
log_widget.clear()
log_widget.write(f"--- Streaming {latest.name} ---\n" + tail)
@ -732,7 +757,8 @@ class LLMConfigApp(App):
)
subprocess.Popen(cmd, env=env, cwd=str(SCRIPT_DIR), start_new_session=True)
self.notify(f"Launching {preset} server. Check Status & Live Logs tab.", severity="information")
self.notify(f"Launching {preset} server. Switching to Status & Logs...", severity="information")
self.query_one(TabbedContent).active = "tab-status"
self.action_refresh_status()
def action_stop(self) -> None: