From b7b25062723650ebc744851a51dd8b0fc2ab475a Mon Sep 17 00:00:00 2001
From: Mikei386 <44135113+Mikei386@users.noreply.github.com>
Date: Mon, 28 Sep 2026 14:27:55 +0200
Subject: [PATCH] Add isolated Athena Deck prototype with demo control and live
hardware telemetry
---
.gitignore | 2 +
README.md | 89 ++++++++++++++++++++++++++
app.js | 17 +++++
collect_hardware.py | 66 ++++++++++++++++++++
demo.py | 22 +++++++
index.html | 1 +
server.py | 148 ++++++++++++++++++++++++++++++++++++++++++++
style.css | 1 +
test_server.py | 45 ++++++++++++++
9 files changed, 391 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 app.js
create mode 100644 collect_hardware.py
create mode 100644 demo.py
create mode 100644 index.html
create mode 100644 server.py
create mode 100644 style.css
create mode 100644 test_server.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7a60b85
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+__pycache__/
+*.pyc
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1079234
--- /dev/null
+++ b/README.md
@@ -0,0 +1,89 @@
+# Athena Deck · Prototyp 0.1
+
+Eigenständige neue Oberfläche, Python-Standardbibliothek und HTML/CSS/JavaScript.
+Keine Installation von Python-Paketen oder Frontend-Builds nötig. Python >= 3.10.
+
+## Start und Stopp auf dem Mac
+
+```sh
+cd /Users/mike_i386/Documents/ChatGPT/Athena/AI-Profile-Router/experiments/athena-control-ui
+python3 server.py --port 8108
+```
+
+GUI: http://127.0.0.1:8108 · Beenden mit Ctrl+C im Startterminal.
+SIGTERM beendet ebenfalls den Server und seinen Demo-Kindprozess sauber.
+Ein belegter UI-Port führt zum Abbruch, nicht zur Übernahme eines Dienstes.
+Der Demo-Port wird vom Betriebssystem vergeben und als bereits gebundener
+Socket an den Kindprozess weitergereicht (keine Port-Prüfungs-Race).
+Kein SSH-Tunnel erforderlich. Die Anwendung bindet ausschließlich Loopback.
+Im separaten Git-Repository liegen diese Dateien im Wurzelverzeichnis;
+dort entsprechend `cd` in den Checkout und denselben Startbefehl verwenden.
+
+Hardware-Abfragen verwenden den vorhandenen SSH-Zugang:
+`ssh -i ~/.ssh/athena_key -o BatchMode=yes root@192.168.1.212`.
+Der bekannte Hostschlüssel muss bereits hinterlegt sein. Schlüssel werden
+weder kopiert noch ausgegeben. Athena erhält nur den Collector über stdin;
+auf dem Host werden keine Dateien angelegt und keine Dienste gesteuert.
+
+## Interne API v1
+
+Alle Antworten JSON, keine persistenten Zustandsdaten. GUI verwendet nur diese API.
+
+| Methode | Pfad | Ergebnis |
+|---|---|---|
+| GET | `/api/v1/status` | Name, Version, Laufzeit, Modus, Demo-Zustand |
+| GET | `/api/v1/hardware` | Verfügbarkeit, Messzeit, CPU, RAM, GPU-Liste, Fehler |
+| GET | `/api/v1/demo` | state, reachable, pid, port, location |
+| POST | `/api/v1/demo/start` | Idempotent starten und Health prüfen |
+| POST | `/api/v1/demo/stop` | Idempotent eigenen Kindprozess stoppen |
+
+POST benötigt `X-Athena-Deck: 1`; Browser-Origin muss zum Host passen.
+Host-Allowlist: localhost oder 127.0.0.1 mit tatsächlichem UI-Port.
+Keine CORS-Freigabe. 403 bei ungültigem Zugriff, 404 bei unbekannten Pfaden,
+503 bei fehlgeschlagener Demo-Bereitschaft. Keine frei übergebbaren Befehle,
+Prozess-IDs, Service-Namen oder Remote-Ziele.
+
+```sh
+curl http://127.0.0.1:8108/api/v1/status
+curl -X POST -H 'X-Athena-Deck: 1' http://127.0.0.1:8108/api/v1/demo/start
+curl -X POST -H 'X-Athena-Deck: 1' http://127.0.0.1:8108/api/v1/demo/stop
+```
+
+Hardware: `available` bezeichnet Erfolg der SSH-Collector-Abfrage, einzelne
+Messwerte können trotzdem fehlen (`null`). SSH-Ausfall liefert available=false,
+leere Daten und eine Fehlermeldung, keine alten Werte als vermeintliches Livebild.
+CPU-Auslastung: 250-ms-Differenz aus `/proc/stat` ohne doppelte Guest-Zählung.
+RAM: MemTotal minus MemAvailable aus `/proc/meminfo`, Einheit Bytes.
+CPU-Temperatur: k10temp/coretemp temp1_input, Grad Celsius.
+GPU: nvidia-smi CSV mit Index, UUID, Name, VRAM in MiB, GPU-Auslastung in Prozent,
+Temperatur in Grad Celsius. Keine Zuordnung nach vermuteter GPU-Reihenfolge.
+Die Anzeige rechnet Speicher in GiB um. Fehlende Werte heißen „Nicht verfügbar“.
+Abfrage bedarfsgesteuert mit fünf Sekunden Cache, GUI-Polling alle fünf Sekunden.
+Keine Historie und kein Hintergrund-Collector bei geschlossener Hardware-Seite.
+
+## Struktur und Grenzen
+
+- `server.py`: API, separater HardwareProvider, eigenständiger DemoService.
+- `demo.py`: Health-only HTTP-Kindprozess auf dem Mac, ohne Modellabhängigkeiten.
+- `collect_hardware.py`: fest begrenzte lesende Linux-Hardware-Abfragen.
+- `index.html`, `app.js`, `style.css`: neue responsive Oberfläche.
+- `test_server.py`: Prozess-Lebenszyklus, Kontrollgrenzen, Hardware-Ausfall.
+
+Sprachmodelle/Chat, Bildgenerierung, Audio und Weitere Dienste sind ausdrücklich
+Platzhalter. Keine Downloads, Installation, Presets, Chats oder Modellwechsel.
+Spätere Modellprofile und native llama.cpp-Worker sollten eigene Service-Adapter
+mit derselben Status-/Start-/Stopp-Trennung erhalten. Noch kein Worker-Registry,
+Scheduler, Authentifizierung für Netzwerkbetrieb oder produktionsreifer Supervisor.
+SIGKILL/Absturz-Cleanup ist nicht implementiert; regulär Ctrl+C/SIGTERM verwenden.
+SSH verwendet den vorgegebenen Root-Zugang; ein eingeschränktes Telemetrie-Konto
+wäre ein späterer eigener Auftrag. Keinerlei Host-Konfiguration wurde geändert.
+
+## Verifikation am 28.09.2026
+
+`python3 -m unittest discover -s . -v`: drei Tests erfolgreich.
+Zusätzlich GUI-Start → Läuft/Erreichbar → Stopp → Gestoppt/Nicht erreichbar geprüft.
+Hardware im Browser mit Ryzen 5 5600, 46,9 GiB RAM, RTX 3060 und RTX 5080 geprüft;
+CPU-/GPU-Temperaturen, VRAM und Auslastung vorhanden. Hardware-Ausfall im Test
+simuliert, ohne Athena oder SSH zu unterbrechen.
+Produktive Router-/Modell-/Bild-/Audio-/Netzwerkdienste nicht verändert.
+Vorhandene ungesicherte Änderungen im übergeordneten Repository unangetastet.
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..b8fa9a1
--- /dev/null
+++ b/app.js
@@ -0,0 +1,17 @@
+const view=document.querySelector('#view'), error=document.querySelector('#error');
+let busy=false, refreshing=false;
+const esc=v=>String(v??'Nicht verfügbar').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
+const fmt=(v,unit='')=>v==null?'Nicht verfügbar':`${Number(v).toLocaleString('de-DE',{maximumFractionDigits:1})}${unit}`;
+const heading=(tag,title,desc)=>`
`;
+const bar=v=>v==null?'':``;
+const placeholders={chat:['Sprachmodelle / Chat','Modellprofile, Laufzeit und Chat','Hier werden später Modellprofile und native llama.cpp-Prozesse verwaltet.'],image:['Bildgenerierung','Worker und Aufträge','Hier entsteht später die Übersicht für Bild-Worker und deren Zustand.'],audio:['Audio','Spracheingabe und Sprachausgabe','Hier werden später getrennte Worker für Erkennung und Ausgabe eingebunden.'],services:['Weitere Dienste','Erweiterbare Dienste','Hier finden später zusätzliche Worker und ihre Schnittstellen Platz.']};
+async function refresh(){if(refreshing)return;refreshing=true;const page=location.hash.slice(1)||'home';document.querySelectorAll('nav a').forEach(a=>a.classList.toggle('active',a.hash==='#'+page));try{error.textContent='';let html;
+if(page==='home'){const s=await api('status'),d=s.demo;html=heading('DEIN KONTROLLZENTRUM','Alles beginnt mit einer klaren Basis.','Eine kleine Oberfläche für Status, Hardware und den ersten steuerbaren Dienst.')+`
Anwendung
Bereit
Athena Deck läuft lokal auf deinem Mac.
Laufzeit ${fmt(s.uptime_seconds,' s')} · API v1
Betriebsmodus
Isoliert
Ein eigenständiger Prototyp mit lesendem Hardware-Zugriff auf Athena.
Keine Modell- oder Router-Steuerung angebunden
Demo-Dienst
LOKAL / CPU
Ein minimaler HTTP-Prozess zum Testen von Start, Stopp und Erreichbarkeit.
Lädt keine Modelle · endet beim Beenden von Athena Deck
`;
+}else if(page==='hardware'){const h=await api('hardware');html=heading('TELEMETRIE / ATHENA','Hardware im Blick.','Live-Messwerte vom Host 192.168.1.212. Aktualisierung alle fünf Sekunden.');if(!h.available)html+=`Hardware nicht verfügbar