refactor: "Gamebox" ueberall durch "AI-Box(en)" ersetzen

Rein terminologisch: die feste "Gamebox" ist konzeptuell zu beliebig vielen
AI-Boxen geworden (Multi-Node-Compute-Fleet). Wort-Sweep ueber Code-Kommentare,
Strings, README, docs, .env.example, CHANGELOG — keine Identifier/Keys betroffen
(Gamebox kam nirgends in Variablennamen vor). Casing erhalten: Gamebox→AI-Box,
gamebox→ai-box. NODE_NAME-Default gamebox→ai-box, Instanz-IDs f5tts@ai-box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-19 00:34:21 +02:00
co-authored by Claude Opus 4.8
parent 17a60e5d3e
commit a773832bca
19 changed files with 76 additions and 76 deletions
+1 -1
View File
@@ -235,7 +235,7 @@ Nur **App neu bauen** (kein Backend). APK 0.2.2.0.
## [0.2.0.4 0.2.0.5] — 2026-07-11 — Plan B: Lokales LLM („Gemini-Feeling")
Ein kleines, schnelles Modell (**Qwen3 8B** via llama.cpp/llama-swap auf der Gamebox-GPU) übernimmt einfache Turns in **<1 s**; alles Schwere/Technische/Werkzeug-artige reicht ein Router automatisch an **Claude** weiter. Ziel: schnelle Antworten ohne die Claude-Max-Subscription aufzugeben.
Ein kleines, schnelles Modell (**Qwen3 8B** via llama.cpp/llama-swap auf der AI-Box-GPU) übernimmt einfache Turns in **<1 s**; alles Schwere/Technische/Werkzeug-artige reicht ein Router automatisch an **Claude** weiter. Ziel: schnelle Antworten ohne die Claude-Max-Subscription aufzugeben.
### Hinzugefügt
+4 -4
View File
@@ -805,7 +805,7 @@ cp ARIA-v0.0.3.0.apk ~/ARIA-AGENT/rvs/updates/
Die GPU-Dienste laufen auf einem oder mehreren separaten Rechnern mit NVIDIA GPU.
Jeder **Compute-Node** verbindet sich ueber RVS mit der ARIA-Infrastruktur — kein
VPN noetig, funktioniert ueber verschiedene Netze hinweg. Frueher war das *eine*
feste „Gamebox"; jetzt sind es beliebig viele Nodes, jeder per `.env` konfiguriert.
feste „AI-Box"; jetzt sind es beliebig viele Nodes, jeder per `.env` konfiguriert.
### Dienste & Profile
@@ -828,7 +828,7 @@ LLM-Box COMPOSE_PROFILES=llm LLM_GPU=0
-- kleine Karte: Whisper (klein) statt Voxtral, neben F5-TTS --
Klein-Box COMPOSE_PROFILES=whisper,f5tts WHISPER_GPU=0 F5TTS_GPU=0
── oder All-in-One ──
Gamebox COMPOSE_PROFILES=voxtral,f5tts,llm VOXTRAL_GPU=1 F5TTS_GPU=0 LLM_GPU=0
AI-Box COMPOSE_PROFILES=voxtral,f5tts,llm VOXTRAL_GPU=1 F5TTS_GPU=0 LLM_GPU=0
↕ RVS (Rechenzentrum, WebSocket Relay)
@@ -1052,7 +1052,7 @@ docker exec aria-brain curl localhost:8080/memory/stats
- [x] Pre-Roll-Buffer einstellbar in App-Settings
- [x] Decimal-zu-Worte fuer TTS + generisches Acronym-Buchstabieren
- [x] voice_preload/voice_ready: visueller Status-Indikator beim Stimmen-Wechsel
- [x] Whisper STT auf die Gamebox ausgelagert (CUDA float16, fast Echtzeit)
- [x] Whisper STT auf die AI-Box ausgelagert (CUDA float16, fast Echtzeit)
- [x] **F5-TTS ersetzt XTTS** — bessere Voice-Cloning-Qualitaet, Whisper-auto-transkribierter Referenz-Text
- [x] Audio-Pause statt Ducking (TRANSIENT statt MAY_DUCK) + release-Timing fix
- [x] VAD-Stille-Toleranz einstellbar (1-8s) + adaptive Mikro-Baseline + Max-Aufnahme einstellbar (1-30 min)
@@ -1107,7 +1107,7 @@ docker exec aria-brain curl localhost:8080/memory/stats
- [x] App: Chat-Suche mit Next/Prev Navigation statt Filter
- [x] Token/Call-Metrics + Subscription-Quota-Tracking (Pro / Max 5x / Max 20x / Custom)
- [x] Datei-Manager Multi-Select: Bulk-Download als ZIP + Bulk-Delete (Diagnostic + App)
- [x] **FLUX.1 Bildgenerierung**: eigener `flux-bridge`-Container auf der Gamebox (analog xtts/whisper) mit Hot-Swap zwischen FLUX.1-dev (Quali) und FLUX.1-schnell (Tempo). Default-Modell + Raw-/Switch-Keywords + HuggingFace-Token in Diagnostic-UI verwaltet, automatischer Pipeline-Reload bei Modell-Wechsel. ARIA bekommt `flux_generate`-Tool, Output landet als `/shared/uploads/aria_generated_<ts>.png` und wird via `[FILE: ...]`-Marker als Anhang-Bubble in App + Diagnostic gerendert. Download-Status (mehrere GB) sichtbar als 🎉-Toast wenn fertig
- [x] **FLUX.1 Bildgenerierung**: eigener `flux-bridge`-Container auf der AI-Box (analog xtts/whisper) mit Hot-Swap zwischen FLUX.1-dev (Quali) und FLUX.1-schnell (Tempo). Default-Modell + Raw-/Switch-Keywords + HuggingFace-Token in Diagnostic-UI verwaltet, automatischer Pipeline-Reload bei Modell-Wechsel. ARIA bekommt `flux_generate`-Tool, Output landet als `/shared/uploads/aria_generated_<ts>.png` und wird via `[FILE: ...]`-Marker als Anhang-Bubble in App + Diagnostic gerendert. Download-Status (mehrere GB) sichtbar als 🎉-Toast wenn fertig
- [x] **ARIA Live (Diagnostic) + Not-Aus**: read-only Mirror der Claude-Code-Session ersetzt den SSH-Tab. Tool-Calls + Inputs + Outputs (truncated 4 KB) live, farbcodiert. Roter ⛔ Not-Aus-Button schickt `cancel_request` mit `hard:true` → Bridge ruft den proxy-internen `/cancel-all` Side-Channel (Port 3457) → alle Claude-Subprocesses sofort tot. Plus: Idle-Watchdog im Proxy (20 min Inaktivitaet → Subprocess-Kill) + httpx-Timeout-Split im Brain (connect 10s / read 24h) damit lange Pentests durchlaufen
- [x] **OAuth2-Pipeline ueber RVS-Callback**: Caddy mit Let's Encrypt vor dem RVS, HTTP-Route `/oauth/callback/{service}` broadcastet als `oauth_callback`-WS-Message, aria-bridge forwarded an Brain, Token landet in `/shared/config/oauth_tokens.json` (mode 0600). ARIAs `oauth_register_provider`-Tool legt neue Provider on-demand an (URLs/scopes, nicht Credentials). Diagnostic + App haben beide Provider-Verwaltung inklusive Custom-Provider-Anlage
- [x] **Skill-Mgmt-Tools fuer ARIA**: `skill_update` (Code/README/pip_packages mit venv-Rebuild) + `skill_delete` — verhindert Skill-Friedhof mit `-v2`/`-fixed`-Suffixen. Plus App-seitiger SkillBrowser (Run + Live-Output + Logs der letzten 20 Runs) in Settings → 🛠️ Skills
+4 -4
View File
@@ -357,7 +357,7 @@ const ChatScreen: React.FC = () => {
// folgende identische Events (z.B. zwei 'thinking' hintereinander) den
// Stream zumuellen. Eigentlich seltener Fall, aber billig zu pruefen.
const lastThoughtKeyRef = useRef<string>('');
// Service-Status (Gamebox: F5-TTS / Whisper Lade-Status) + Banner-Sichtbarkeit
// Service-Status (AI-Box: F5-TTS / Whisper Lade-Status) + Banner-Sichtbarkeit
const [serviceStatus, setServiceStatus] = useState<Record<string, {state: string, model?: string, loadSeconds?: number, error?: string, downloading?: boolean, freshlyDownloaded?: boolean}>>({});
const [serviceBannerDismissed, setServiceBannerDismissed] = useState(false);
// Gerätelokale TTS-Config: globaler Toggle (aus Settings) + temporäres Muten (Mund-Button)
@@ -1591,7 +1591,7 @@ const ChatScreen: React.FC = () => {
}
}
// Gamebox-Bridges (f5tts/whisper/flux) melden Lade-Status — Banner oben.
// AI-Box-Bridges (f5tts/whisper/flux) melden Lade-Status — Banner oben.
// Toast bei Download-Ende: erstmaliger HF-Download (mehrere GB) → User
// soll wissen dass er Bilder/Stimmen jetzt nutzen kann ohne in den
// Banner gucken zu muessen.
@@ -2289,7 +2289,7 @@ const ChatScreen: React.FC = () => {
// Aufraeumen von "verarbeitet"-Placeholder die nie ein STT-Result bekommen
// haben (leere Aufnahme, Wake-Word-Echo, STT-Fehler etc). Timeout skaliert
// mit der Aufnahmedauer — Whisper braucht auf der Gamebox grob real-time/5,
// mit der Aufnahmedauer — Whisper braucht auf der AI-Box grob real-time/5,
// plus Bridge-Roundtrip + Network. Formel: 60s Buffer + 1x Aufnahmedauer.
// Bei 5min Aufnahme = 6 min Wait, bei 5s Aufnahme = 65s. Sicher genug damit
// langsame STTs nicht versehentlich aufgeraeumt werden.
@@ -3060,7 +3060,7 @@ const ChatScreen: React.FC = () => {
</TouchableOpacity>
</View>
{/* Service-Status Banner (Gamebox: F5-TTS / Whisper Lade-Status) */}
{/* Service-Status Banner (AI-Box: F5-TTS / Whisper Lade-Status) */}
{(() => {
const entries = Object.entries(serviceStatus);
if (entries.length === 0 || serviceBannerDismissed) return null;
+1 -1
View File
@@ -859,7 +859,7 @@ META_TOOLS = [
"function": {
"name": "flux_generate",
"description": (
"Generiere ein Bild aus einem Text-Prompt via FLUX auf der Gamebox-GPU. "
"Generiere ein Bild aus einem Text-Prompt via FLUX auf der AI-Box-GPU. "
"Brauchbar fuer 'mal mir ein X', 'wie sieht ein Y aus?', Mockups, "
"Konzept-Skizzen, Memes. Render dauert 20-90s — kuendige es Stefan "
"kurz an, dann ist er nicht ueberrascht.\n\n"
+1 -1
View File
@@ -1,7 +1,7 @@
"""
Local-LLM-Client (Plan B) — Brain-Seite.
Ruft das schnelle lokale LLM (Qwen3 auf der Gamebox) ueber die Bridge:
Ruft das schnelle lokale LLM (Qwen3 auf der AI-Box) ueber die Bridge:
Brain → HTTP /internal/local-llm → Bridge → RVS → llm-adapter → llama.cpp
Analog zum Claude-`proxy_client`, nur ueber die Bridge (die ist der RVS-Client;
+22 -22
View File
@@ -2,7 +2,7 @@
ARIA Voice Bridge — Hauptmodul.
Verbindet die Android App (via RVS) mit ARIA-Core. Spracheingabe laeuft
ueber die whisper-bridge (Gamebox, faster-whisper auf CUDA), Sprachausgabe
ueber die whisper-bridge (AI-Box, faster-whisper auf CUDA), Sprachausgabe
ueber die f5tts-bridge (Voice Cloning, satzweises PCM-Streaming).
Nachrichtenfluss:
@@ -479,7 +479,7 @@ class STTEngine:
Erkannter Text oder leerer String.
"""
if self.model is None:
# Lazy-Load: normalerweise laeuft STT remote auf der Gamebox.
# Lazy-Load: normalerweise laeuft STT remote auf der AI-Box.
# Erst wenn das Fallback hier zuschlaegt, laden wir lokal.
logger.info("Lokales Whisper-Fallback — Modell wird nachgeladen...")
try:
@@ -654,7 +654,7 @@ class ARIABridge:
self._seen_client_msg_ids: "OrderedDict[str, float]" = OrderedDict()
self._SEEN_CLIENT_MSG_LIMIT = 200
# Komponenten (TTS: F5-TTS remote auf der Gamebox, lokales TTS wurde entfernt)
# Komponenten (TTS: F5-TTS remote auf der AI-Box, lokales TTS wurde entfernt)
self.tts_enabled = True
self.xtts_voice = ""
self._f5tts_config: dict = {}
@@ -686,7 +686,7 @@ class ARIABridge:
except (TypeError, ValueError):
self._persistent_xtts_speed = None
# F5-TTS-Felder aufsammeln (werden spaeter via RVS rebroadcastet,
# damit die f5tts-bridge auf der Gamebox die Settings auch nach
# damit die f5tts-bridge auf der AI-Box die Settings auch nach
# Restart wiederbekommt — sonst stuende sie auf Hard-Defaults)
for k in ("f5ttsModel", "f5ttsCkptFile", "f5ttsVocabFile",
"f5ttsCfgStrength", "f5ttsNfeStep"):
@@ -746,7 +746,7 @@ class ARIABridge:
# Gleiche Logik fuer die Wiedergabegeschwindigkeit (F5-TTS speed-Param,
# App-Setting aria_tts_speed, 1.0 = normal).
self._next_speed_override: Optional[float] = None
# STT-Requests die aktuell auf Antwort von der whisper-bridge (Gamebox) warten.
# STT-Requests die aktuell auf Antwort von der whisper-bridge (AI-Box) warten.
# requestId → Future mit dem Text (oder None bei Fehler).
self._pending_stt: dict[str, asyncio.Future] = {}
# whisper-bridge service_status: True wenn ready, False/None wenn loading/unbekannt.
@@ -771,7 +771,7 @@ class ARIABridge:
# {service, node, gpus, model, busy, last_seen}. Genutzt fuer die
# Diagnostic-Flotten-Anzeige und (Stage 3) targetInstance-Routing.
self._workers: dict[str, dict] = {}
# FLUX-Render-Requests die aktuell auf Antwort der flux-bridge (Gamebox) warten.
# FLUX-Render-Requests die aktuell auf Antwort der flux-bridge (AI-Box) warten.
# requestId → Future mit dem flux_response-Payload (oder None bei Fehler).
self._pending_flux: dict[str, asyncio.Future] = {}
# flux-bridge service_status: True wenn ready. Render-Timeouts werden
@@ -779,7 +779,7 @@ class ARIABridge:
self._remote_flux_ready: bool = False
# Lokales LLM (Plan B): requestId → Future mit dem llm_response-Payload.
# Analog zu _pending_flux — Brain ruft /internal/local-llm, wir relayen
# llm_request via RVS an den llm-adapter (Gamebox) und warten auf
# llm_request via RVS an den llm-adapter (AI-Box) und warten auf
# llm_response.
self._pending_llm: dict[str, asyncio.Future] = {}
# User-Message-Counter fuer Auto-Compact. Bei zu langer Konversation
@@ -815,7 +815,7 @@ class ARIABridge:
logger.info("ARIA Voice Bridge startet...")
logger.info("=" * 50)
# STT wird standardmaessig von der whisper-bridge (Gamebox) erledigt.
# STT wird standardmaessig von der whisper-bridge (AI-Box) erledigt.
# Lokales Whisper ist nur Fallback und wird lazy geladen wenn remote nicht
# antwortet. Das spart RAM auf der VM und Startup-Zeit.
@@ -1759,7 +1759,7 @@ class ARIABridge:
"""Broadcastet die aktuelle voice_config.json einmalig nach RVS-Connect.
Damit bekommen frisch verbundene Bridges (insbesondere die f5tts-bridge
auf der Gamebox nach Container-Restart) die zuletzt in Diagnostic
auf der AI-Box nach Container-Restart) die zuletzt in Diagnostic
gewaehlten Settings — ohne dass der User in Diagnostic was klicken muss.
"""
try:
@@ -2202,7 +2202,7 @@ class ARIABridge:
await self._broadcast_current_mode()
# Persistierte Voice-Config broadcasten — die f5tts-bridge auf
# der Gamebox bekommt damit nach Restart die zuletzt in
# der AI-Box bekommt damit nach Restart die zuletzt in
# Diagnostic gewaehlten Settings wieder (sonst stuende sie auf
# ihren Hard-Defaults).
asyncio.create_task(self._broadcast_persisted_config())
@@ -2563,7 +2563,7 @@ class ARIABridge:
elif msg_type == "config":
# Konfiguration von App/Diagnostic empfangen + persistent speichern.
# Felder die nicht direkt zur aria-bridge gehoeren (f5tts*) werden
# nur persistiert; die f5tts-bridge auf der Gamebox empfaengt den
# nur persistiert; die f5tts-bridge auf der AI-Box empfaengt den
# gleichen RVS-Broadcast und reagiert selber.
changed = False
if "ttsEnabled" in payload:
@@ -2587,7 +2587,7 @@ class ARIABridge:
new_model = payload["whisperModel"]
allowed = {"tiny", "base", "small", "medium", "large-v3"}
if new_model in allowed and new_model != self.stt_engine.model_size:
logger.info("[rvs] Whisper-Modell → %s (nur Config; Modell laedt Gamebox)",
logger.info("[rvs] Whisper-Modell → %s (nur Config; Modell laedt AI-Box)",
new_model)
self.stt_engine.model_size = new_model
self.stt_engine.model = None
@@ -3448,7 +3448,7 @@ class ARIABridge:
return
elif msg_type == "llm_response":
# Antwort des llm-adapter (Gamebox) auf unseren llm_request.
# Antwort des llm-adapter (AI-Box) auf unseren llm_request.
request_id = payload.get("requestId", "")
future = self._pending_llm.get(request_id)
if future is None or future.done():
@@ -3457,7 +3457,7 @@ class ARIABridge:
return
elif msg_type == "service_status":
# Gamebox-Bridges (whisper / f5tts / flux) melden ihren Lade-Status.
# AI-Box-Bridges (whisper / f5tts / flux) melden ihren Lade-Status.
# Wir nutzen das fuer den dynamischen STT-Timeout: solange whisper
# im 'loading' steckt, geben wir der Bridge mehr Zeit (Modell-Download
# kann 1-2 Min dauern), statt nach 45s lokal zu fallbacken.
@@ -3616,11 +3616,11 @@ class ARIABridge:
else:
logger.debug("[rvs] Unbekannter Typ: %s", msg_type)
# STT-Orchestrierung: zuerst Remote (Gamebox), Fallback lokal.
# STT-Orchestrierung: zuerst Remote (AI-Box), Fallback lokal.
# Zwei Timeouts:
# ready=True → 45s reicht selbst fuer lange Audios
# ready=False → 300s, weil das Modell evtl. noch heruntergeladen wird
# (large-v3 ~3GB, kann auf der Gamebox 1-2 Min dauern).
# (large-v3 ~3GB, kann auf der AI-Box 1-2 Min dauern).
_STT_REMOTE_TIMEOUT_READY_S = 45.0
_STT_REMOTE_TIMEOUT_LOADING_S = 300.0
@@ -3973,15 +3973,15 @@ class ARIABridge:
_FLUX_TIMEOUT_LOADING_S = 900.0 # 15 min beim allerersten Mal (Modell-Download)
# ── Local-LLM-Roundtrip: Brain → Bridge → RVS → llm-adapter → zurueck ──
# Qwen3 auf der Gamebox antwortet auf kurze Turns in <1 s. Grosszuegiger
# Timeout deckt Kaltstart / laengere Antworten / Netz-Jitter (Gamebox@home)
# Qwen3 auf der AI-Box antwortet auf kurze Turns in <1 s. Grosszuegiger
# Timeout deckt Kaltstart / laengere Antworten / Netz-Jitter (AI-Box@home)
# ab. Bei Timeout faellt der Router im Brain per Escalation auf Claude.
_LLM_TIMEOUT_S = 30.0
async def _local_llm(self, messages: list, max_tokens: int = 512,
temperature: float = 0.7, stop=None, tools=None,
model=None) -> dict:
"""Schickt einen llm_request an den llm-adapter (Gamebox), wartet auf
"""Schickt einen llm_request an den llm-adapter (AI-Box), wartet auf
llm_response. tools (B1b) werden durchgereicht; tool_calls kommen zurueck.
Rueckgabe: {ok, content, tool_calls, model, elapsedMs} oder {ok:False, error}."""
if self.ws_rvs is None:
@@ -4024,7 +4024,7 @@ class ARIABridge:
try:
result = await asyncio.wait_for(future, timeout=self._LLM_TIMEOUT_S)
except asyncio.TimeoutError:
return {"ok": False, "error": f"Timeout ({self._LLM_TIMEOUT_S:.0f}s) — Gamebox nicht erreichbar?"}
return {"ok": False, "error": f"Timeout ({self._LLM_TIMEOUT_S:.0f}s) — AI-Box nicht erreichbar?"}
if not isinstance(result, dict) or not result.get("ok"):
err = (result or {}).get("error") if isinstance(result, dict) else "leeres Resultat"
return {"ok": False, "error": err or "llm-adapter Fehler"}
@@ -4527,7 +4527,7 @@ class ARIABridge:
await _send_response(writer, 200, result)
elif method == "POST" and path == "/internal/flux-generate":
# Vom Brain (flux_generate-Tool) gefeuert. Wir routen den
# Render-Request via RVS an die flux-bridge (Gamebox),
# Render-Request via RVS an die flux-bridge (AI-Box),
# warten synchron auf die PNG-Antwort, speichern sie nach
# /shared/uploads/ und melden Pfad + Render-Stats zurueck.
# Brain referenziert das Bild dann mit [FILE:]-Marker in
@@ -4564,7 +4564,7 @@ class ARIABridge:
await _send_response(writer, status, result)
elif method == "POST" and path == "/internal/local-llm":
# Vom Brain (Router / Testchat) gefeuert. Wir relayen den
# Chat-Request via RVS an den llm-adapter (Gamebox Qwen3),
# Chat-Request via RVS an den llm-adapter (AI-Box Qwen3),
# warten synchron auf llm_response und geben content zurueck.
try:
data = json.loads(body.decode("utf-8", "ignore"))
+9 -9
View File
@@ -162,7 +162,7 @@
</style>
</head>
<body>
<!-- Service-Status Banner unten rechts (Gamebox: F5-TTS / Whisper Lade-Status) -->
<!-- Service-Status Banner unten rechts (AI-Box: F5-TTS / Whisper Lade-Status) -->
<div id="service-status-banner" style="display:none;position:fixed;bottom:16px;right:16px;z-index:999;background:#1E1E2E;border:1px solid #2A2A3E;border-radius:8px;padding:10px 14px;font-size:12px;color:#fff;min-width:240px;max-width:360px;box-shadow:0 4px 14px rgba(0,0,0,0.5);">
<div style="display:flex;align-items:flex-start;gap:8px;">
<span id="service-status-icon" style="font-size:18px;line-height:1;">&#x23F3;</span>
@@ -548,7 +548,7 @@
<h2>Lokales LLM (schnelle Antworten) <button class="info-btn" onclick="showInfo('local-llm')" title="Wie funktioniert das?"></button></h2>
<div class="card" style="max-width:540px;">
<div style="font-size:11px;color:#8888AA;margin-bottom:12px;line-height:1.55;">
Ein schnelles lokales Modell (<strong>Qwen3</strong> auf der Gamebox) beantwortet
Ein schnelles lokales Modell (<strong>Qwen3</strong> auf der AI-Box) beantwortet
<strong>leichte Fragen in unter 1&nbsp;Sekunde</strong>. Was schwerer wird, gibt es
automatisch an <strong>Claude</strong> ab. Aenderungen greifen sofort
(kein Neustart) — geschrieben nach <code>/shared/config/local_llm.json</code>.
@@ -600,7 +600,7 @@
</div>
<div id="local-llm-model-desc" style="font-size:10px;color:#8888AA;margin:0 0 2px 0;line-height:1.5;"></div>
<div style="font-size:10px;color:#FFD60A;margin:0 0 4px 0;line-height:1.5;">
Beim ersten Wechsel zu einem Modell lädt die Gamebox das GGUF (mehrere GB) —
Beim ersten Wechsel zu einem Modell lädt die AI-Box das GGUF (mehrere GB) —
die <strong>erste Antwort dauert dann länger</strong>, danach ist es gecacht.
Liste kommt aus <code>/shared/config/local_models.json</code> (Keys = xtts/llama-swap/config.yaml).
</div>
@@ -647,7 +647,7 @@
<summary style="color:#8888AA;font-size:12px;cursor:pointer;">F5-TTS Modell-Tuning (advanced)</summary>
<div style="margin-top:10px;display:flex;flex-direction:column;gap:8px;">
<div style="color:#8888AA;font-size:11px;">
Werden via RVS an die f5tts-bridge auf der Gamebox geschickt.
Werden via RVS an die f5tts-bridge auf der AI-Box geschickt.
Modell-/Checkpoint-Wechsel triggert einen Reload (~30s).
Hardcoded Defaults: F5TTS_v1_Base, cfg_strength=2.5, nfe_step=32.
</div>
@@ -838,7 +838,7 @@
<div class="settings-section">
<h2>FLUX Bildgenerierung</h2>
<div style="font-size:11px;color:#8888AA;margin-bottom:8px;">
Steuerung der Image-Generation (flux-bridge auf der Gamebox).
Steuerung der Image-Generation (flux-bridge auf der AI-Box).
Default-Modell wird via RVS gepusht — Wechsel triggert Pipeline-Reload (15-30s
aus HF-Cache, mehrere Minuten beim Erst-Download). Keywords nutzt ARIAs Brain
im System-Prompt.
@@ -2939,7 +2939,7 @@
'Glob': '\uD83D\uDCC1 Dateien suchen',
'Agent': '\uD83E\uDD16 Sub-Agent',
};
// ── Service-Status Banner (Gamebox: F5-TTS / Whisper Lade-Status) ──
// ── Service-Status Banner (AI-Box: F5-TTS / Whisper Lade-Status) ──
// Aggregiert die Status-Infos der Bridges. Wenn irgendwas am Laden
// ist, zeigt das Banner unten rechts. Sobald alles auf 'ready' ist,
// bleibt's einen Moment und wird dann vom User weggeklickt (oder
@@ -6475,17 +6475,17 @@
html: `
<p>Jeder Turn, den das <strong>lokale LLM</strong> oder ein <strong>Fast-Path</strong> (reiner Skill, ganz ohne LLM) beantwortet, ist ein Claude-Call, der <strong>nicht</strong> gegen dein Subscription-Quota laeuft.</p>
<p><strong>„Claude-Calls gespart"</strong> = Anzahl der local- + fast-path-Antworten im Zeitfenster. Konservativ gezaehlt: 1 Antwort = mindestens 1 gesparter Claude-Call (bei Tool-Use waeren es real oft mehr).</p>
<p><strong>„lokale Tokens"</strong> = Prompt+Antwort-Tokens, die auf deiner eigenen Gamebox-GPU verarbeitet wurden (echte <code>usage</code>-Zahlen vom Modell, sonst chars/4-Schaetzung). Die kosten dich nichts ausser Strom.</p>
<p><strong>„lokale Tokens"</strong> = Prompt+Antwort-Tokens, die auf deiner eigenen AI-Box-GPU verarbeitet wurden (echte <code>usage</code>-Zahlen vom Modell, sonst chars/4-Schaetzung). Die kosten dich nichts ausser Strom.</p>
<p>Fast-Path-Antworten (z.B. „nächstes Lied") haben ~0 Tokens — reiner Skill-Aufruf, kein Modell.</p>
`,
},
'local-llm': {
title: 'Lokales LLM — schnelle Antworten',
html: `
<p>Ein kleines, schnelles Modell (<strong>Qwen3 8B</strong>) laeuft auf deiner Gamebox-GPU und beantwortet <strong>einfache Plauder-Turns in &lt;1&nbsp;s</strong>. Alles Schwere, Technische oder Werkzeug-artige (Wetter, Timer, Musik, Bilder, Gedaechtnis, Code) reicht ein Router automatisch an <strong>Claude</strong> weiter.</p>
<p>Ein kleines, schnelles Modell (<strong>Qwen3 8B</strong>) laeuft auf deiner AI-Box-GPU und beantwortet <strong>einfache Plauder-Turns in &lt;1&nbsp;s</strong>. Alles Schwere, Technische oder Werkzeug-artige (Wetter, Timer, Musik, Bilder, Gedaechtnis, Code) reicht ein Router automatisch an <strong>Claude</strong> weiter.</p>
<p><strong>Lokales LLM nutzen</strong> — Master-Schalter. Aus = alle Anfragen laufen wie bisher ueber Claude.</p>
<p><strong>Nur lokales LLM</strong> — erzwingt lokal, KEIN Claude-Fallback. Zum Ausprobieren, wie stark das lokale Modell allein ist. Achtung: Werkzeug-Turns (Wetter/Timer/…) funktionieren dann nicht — das lokale Tier hat keine Tools.</p>
<p>Die Antwortzeit haengt an deinem Heim-Internet (Gamebox @home, ARIA @RZ). Ist die Gamebox aus/nicht erreichbar, faellt ARIA automatisch auf Claude zurueck.</p>
<p>Die Antwortzeit haengt an deinem Heim-Internet (AI-Box @home, ARIA @RZ). Ist die AI-Box aus/nicht erreichbar, faellt ARIA automatisch auf Claude zurueck.</p>
`,
},
'local-llm-tools': {
+1 -1
View File
@@ -1025,7 +1025,7 @@ function connectRVS(forcePlain) {
}
broadcast({ type: "voice_ready", payload: msg.payload });
} else if (msg.type === "service_status") {
// Gamebox-Bridges (f5tts/whisper) melden ihren Lade-Status —
// AI-Box-Bridges (f5tts/whisper) melden ihren Lade-Status —
// an Browser durchreichen fuer das Banner unten rechts
const svc = msg.payload?.service || "?";
const state = msg.payload?.state || "?";
+2 -2
View File
@@ -1,7 +1,7 @@
# FLUX.1-dev Bildgenerierung — Architektur & Stand
Ergaenzung des ARIA-Agent-Stacks um native Text-to-Image-Generierung via
FLUX.1-dev auf der Gamebox. Folgt dem **gleichen Pattern wie f5tts / whisper**:
FLUX.1-dev auf der AI-Box. Folgt dem **gleichen Pattern wie f5tts / whisper**:
ein eigener Container auf dem Gaming-PC, der sich selbst per WebSocket zum
RVS verbindet und auf seinen Request-Typ lauscht.
@@ -23,7 +23,7 @@ aria-bridge ── send_to_core ──▶ aria-brain
RVS
│ fanout
flux-bridge (Gamebox)
flux-bridge (AI-Box)
│ FluxPipeline.from_pretrained(...)
│ pipeline(prompt, width, height, steps, guidance).images[0]
│ PIL → PNG → base64
+9 -9
View File
@@ -1,4 +1,4 @@
# Plan B — Lokaler LLM-Router (Gamebox) neben Claude
# Plan B — Lokaler LLM-Router (AI-Box) neben Claude
**Ziel:** „Gemini-Feeling" für den Alltag, ohne die Claude-Max-Subscription
aufzugeben. Ein schnelles lokales LLM beantwortet die einfachen ~80 % der Turns
@@ -11,7 +11,7 @@ Gemessen (10.07.2026): CLI-Round-trip über den Claude-Max-Proxy hat einen
**harten Boden von ~3,5 s** (Subprozess-Start pro Turn). Streaming-API würde das
brechen, kostet aber API-Geld → verliert die Max-Subscription. Ein lokales
LLM für die einfachen Turns umgeht den 3,5-s-Boden komplett und ist **gratis**
(läuft auf vorhandener Gamebox-GPU). Echtes Speech-to-Speech-Duplex (Gemini
(läuft auf vorhandener AI-Box-GPU). Echtes Speech-to-Speech-Duplex (Gemini
Live nativ) ist mit einem Text-Modell als Hirn prinzipiell nicht drin.
## Modell & Serving (entschieden)
@@ -19,17 +19,17 @@ Live nativ) ist mit einem Text-Modell als Hirn prinzipiell nicht drin.
- **Modell:** Qwen3 8B, GGUF **Q4_K_M** (~6 GB). Bestes Tool-Calling der 7/8B-
Klasse, solides Deutsch, Apache-2.0. Alt.: Mistral Small 3 7B (schneller,
weniger Tool-Calling).
- **Serving:** **llama.cpp `llama-server`** im Docker-Container auf der Gamebox
- **Serving:** **llama.cpp `llama-server`** im Docker-Container auf der AI-Box
(kein Ollama nötig — nativer OpenAI-kompatibler `/v1/chat/completions`).
- **VRAM-Budget:** 12-GB-Karte, Whisper-small (~12 GB) + F5-TTS (~12 GB) →
~89 GB frei → passt. (FLUX ist auf 12 GB eh raus.)
## Anbindung: über den RVS, wie TTS/STT (kein IP-Pflegen)
Die Gamebox ist ein anderer Host als das Brain. Statt direktem HTTP (IP/Port/
Die AI-Box ist ein anderer Host als das Brain. Statt direktem HTTP (IP/Port/
Firewall) läuft das LLM **über den RVS-Token-Room**, exakt wie Whisper/F5-TTS:
- llama.cpp hört nur auf localhost der Gamebox.
- llama.cpp hört nur auf localhost der AI-Box.
- Ein **dünner RVS-Adapter** daneben (Vorbild: whisper-/xtts-Bridge) verbindet
sich mit dem RVS-Token, lauscht auf `llm_request`, ruft lokal llama-server,
schickt `llm_response` (korreliert per requestId) zurück.
@@ -115,7 +115,7 @@ mit Ziel lokal.
## Phasen
- **B0 — Infra:** llama.cpp-Container + RVS-Adapter auf der Gamebox,
- **B0 — Infra:** llama.cpp-Container + RVS-Adapter auf der AI-Box,
`ALLOWED_TYPES`, `local_llm_chat()` im Brain. Isoliert testen („sag hallo").
- **B1 — Router + lokale Tools:** Heuristik Tier-1/2 + Escalation, schlanke
Persona lokal, **kuratierte Tool-Auswahl lokal** (Adapter/Bridge/Brain-Tool-
@@ -207,8 +207,8 @@ Zerfaellt in zwei Teile:
(Docker-Socket) + Controller mit Placement-Policy + Reconciliation +
Broadcast-Kollisions-Vermeidung (nicht 2× dieselbe Faehigkeit). = Mini-Nomad.
**Empfehlung:** Fuer 2 Gameboxen NICHT bauen — statische Platzierung reicht
(Gamebox1=LLM, Gamebox2=Voice). Dynamisches Laden/Entladen zum VRAM-Freimachen
**Empfehlung:** Fuer 2 AI-Boxen NICHT bauen — statische Platzierung reicht
(AI-Box1=LLM, AI-Box2=Voice). Dynamisches Laden/Entladen zum VRAM-Freimachen
deckt `llama-swap` innerhalb eines Hosts (B0.5). Waechst die Flotte: erst den
billigen Heartbeat-Teil; fuer echte Orchestrierung Docker Swarm / Nomad nehmen
statt selbst einen Scheduler zu bauen.
@@ -227,7 +227,7 @@ lohnt nicht):
einen Heartbeat via RVS (Host, GPU-Util, VRAM frei/belegt, laufende
GPU-Container). Diagnostic zeigt pro Host VRAM-Balken + Dienste + „Host X hat
N GB frei". Kein Start/Stop, nur Sicht + Hinweis wohin verschiebbar.
- **Zukunft (Gamebox3, 4×3060 = 48 GB):** neuer Host, eigenes Profil, `up`
- **Zukunft (AI-Box3, 4×3060 = 48 GB):** neuer Host, eigenes Profil, `up`
erscheint im Dashboard; grosses lokales LLM oder FLUX-Vollausbau dorthin.
Ohne Orchestrator.
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
ARIA FLUX-Bridge laeuft auf der Gamebox (RTX 3060).
ARIA FLUX-Bridge laeuft auf der AI-Box (RTX 3060).
Empfaengt flux_request via RVS FLUX.1-dev/-schnell auf GPU sendet
flux_response mit base64-PNG zurueck an die aria-bridge. Diese speichert
+5 -5
View File
@@ -183,9 +183,9 @@ Wichtige Mechanismen:
- [x] Decimal-zu-Worte fuer TTS (0.1 → null komma eins, mit IP-Schutz-Lookahead)
- [x] Generic Acronym-Buchstabieren (XTTS → X T T S, USB → U S B, ueber expliziter Liste)
- [x] voice_preload/voice_ready: Stille Mini-Render bei Voice-Wechsel + Toast/Status "bereit"
- [x] Whisper STT auf die Gamebox ausgelagert (faster-whisper CUDA, float16) — neuer aria-whisper-bridge Container
- [x] aria-bridge: STT primaer remote (Gamebox), Fallback lokal nach 45s Timeout
- [x] Whisper-Modell hot-swap auf Gamebox via config-Broadcast aus Diagnostic
- [x] Whisper STT auf die AI-Box ausgelagert (faster-whisper CUDA, float16) — neuer aria-whisper-bridge Container
- [x] aria-bridge: STT primaer remote (AI-Box), Fallback lokal nach 45s Timeout
- [x] Whisper-Modell hot-swap auf AI-Box via config-Broadcast aus Diagnostic
- [x] **F5-TTS ersetzt XTTS komplett** — neuer aria-f5tts-bridge Container, Voice Cloning, satzweises Streaming
- [x] Voice-Upload mit Whisper-Auto-Transkription — User muss keinen Referenz-Text eintippen
- [x] Audio-Pause statt Ducking: Spotify/YouTube pausieren komplett waehrend TTS (TRANSIENT statt MAY_DUCK)
@@ -334,7 +334,7 @@ Skills mit Tool-Use.
- [x] Datei-Manager (Diagnostic + App-Modal): /shared/uploads/ verwalten, Multi-Select + Select-All + Bulk-Download als ZIP + Bulk-Delete
- [x] Wipe-All-Button (Memory + Stimmen + Settings)
- [x] Voice Export/Import pro Stimme (Diagnostic + XTTS-Bridge auf Gamebox)
- [x] Voice Export/Import pro Stimme (Diagnostic + XTTS-Bridge auf AI-Box)
- [x] F5/Whisper-Settings als JSON-Bundle Export/Import
- [x] App Chat-Suche umgebaut: Highlight + Next/Prev statt Filter
- [x] App Pinch-Zoom in Bildern rewriten (Multi-Touch-Race-Bugs)
@@ -399,7 +399,7 @@ Skills mit Tool-Use.
### Architektur
- [ ] Diagnostic: System-Info Tab (Container-Status, Disk, RAM, CPU)
- [ ] RVS Zombie-Connections endgueltig loesen
- [ ] Gamebox: kleine Web-Oberflaeche fuer Credentials/Server-Config oder zentral aus Diagnostic per RVS push
- [ ] AI-Box: kleine Web-Oberflaeche fuer Credentials/Server-Config oder zentral aus Diagnostic per RVS push
- [ ] Erste Skills bauen lassen (yt-dlp, pdf-extract, image-resize, etc.) — durch normale Anfragen, ARIA legt sie selbst an
- [ ] Heartbeat (periodische Selbst-Checks)
- [ ] Lokales LLM als Waechter (Triage vor Claude-Call)
+1 -1
View File
@@ -63,7 +63,7 @@ const ALLOWED_TYPES = new Set([
"agent_stream",
"oauth_callback",
// Lokales LLM (Plan B) — Router im Brain schickt einfache Turns an das
// Qwen3 auf der Gamebox (via Bridge → RVS → llm-adapter → llama.cpp).
// Qwen3 auf der AI-Box (via Bridge → RVS → llm-adapter → llama.cpp).
// llm_partial ist fuer B2 (Token-Streaming) reserviert, noch ungenutzt.
"llm_request", "llm_response", "llm_partial",
// Workspace-Desktop (Code-Projekte): Live-Code-Editor (CodeMirror in der App)
+2 -2
View File
@@ -20,8 +20,8 @@ COMPOSE_PROFILES=whisper,f5tts
# ─── Node-Name ────────────────────────────────────
# Freier Name dieses Rechners. Erscheint in Diagnostic (Flotten-Anzeige) und
# in den Logs, und bildet die Instanz-ID der Dienste (z.B. f5tts@gamebox).
NODE_NAME=gamebox
# in den Logs, und bildet die Instanz-ID der Dienste (z.B. f5tts@ai-box).
NODE_NAME=ai-box
# ─── GPU-Zuordnung pro Dienst ─────────────────────
# Setzt NVIDIA_VISIBLE_DEVICES fuer den jeweiligen Container.
+2 -2
View File
@@ -1,7 +1,7 @@
# ════════════════════════════════════════════════
# ARIA Compute-Node — GPU-Dienste (STT / TTS / LLM)
#
# KEINE feste "Gamebox" mehr: dieser Stack laeuft auf beliebig vielen
# KEINE feste "AI-Box" mehr: dieser Stack laeuft auf beliebig vielen
# Worker-Nodes. Jeder Node startet ueber COMPOSE_PROFILES nur die Dienste,
# die er anbieten soll, und pinnt sie per *_GPU auf bestimmte Grafikkarten.
# Alles verbindet sich ueber RVS mit der ARIA-Infrastruktur — kein VPN.
@@ -10,7 +10,7 @@
# STT-Box → COMPOSE_PROFILES=voxtral
# TTS-Box → COMPOSE_PROFILES=f5tts
# LLM-Box → COMPOSE_PROFILES=llm
# All-in-One → COMPOSE_PROFILES=voxtral,f5tts,llm (die alte Gamebox)
# All-in-One → COMPOSE_PROFILES=voxtral,f5tts,llm (die alte AI-Box)
#
# FLUX-Bildgenerierung liegt im /flux Verzeichnis — eigener Stack.
# ════════════════════════════════════════════════
+2 -2
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
ARIA F5-TTS Bridge laeuft auf der Gamebox (RTX 3060).
ARIA F5-TTS Bridge laeuft auf der AI-Box (RTX 3060).
Empfaengt xtts_request via RVS F5-TTS Voice Cloning auf GPU streamt
16-bit PCM Chunks als audio_pcm Nachrichten zurueck an die App.
@@ -387,7 +387,7 @@ async def _send(ws, mtype: str, payload: dict) -> None:
# ──────────────────────────────────────────────────────────────
# DEBUG-LOG ueber RVS → /shared/logs/app.log
#
# Gleiches Pattern wie in whisper-bridge: Stefan's Gamebox ist
# Gleiches Pattern wie in whisper-bridge: Stefan's AI-Box ist
# Windows (kein SSH), in Zukunft koennten whisper + f5tts auf
# unterschiedlichen Hosts laufen. Logs ueber RVS heisst: ein Pfad.
#
+4 -4
View File
@@ -1,6 +1,6 @@
# Local-LLM-Adapter (Gamebox) — Plan B, Phase B0
# Local-LLM-Adapter (AI-Box) — Plan B, Phase B0
Bringt ein lokales, schnelles LLM (Qwen3 8B) auf die Gamebox und haengt es
Bringt ein lokales, schnelles LLM (Qwen3 8B) auf die AI-Box und haengt es
per RVS an ARIA — fuer die einfachen ~80 % der Turns (<1 s), waehrend Claude
das Tiefen-Hirn bleibt. Siehe `docs/plan-local-llm-router.md` im Repo-Root.
@@ -17,7 +17,7 @@ das Tiefen-Hirn bleibt. Siehe `docs/plan-local-llm-router.md` im Repo-Root.
cached es unter `xtts/models/` (Bind-Mount → kein Re-Download bei Restart).
Default: **Qwen3 8B, Q4_K_M** aus dem offiziellen Repo `Qwen/Qwen3-8B-GGUF`.
Modell/Quant wechseln = in der `.env` der Gamebox setzen (kein Code):
Modell/Quant wechseln = in der `.env` der AI-Box setzen (kein Code):
```
LLM_HF_REPO=Qwen/Qwen3-8B-GGUF # HF-Repo
@@ -35,7 +35,7 @@ umstellen + Container neu — Ein-Zeilen-Wechsel, kein Code.
Modelle) ist ein geplanter Folge-Baustein via `llama-swap` — siehe
`docs/plan-local-llm-router.md`.
## Start (auf der Gamebox)
## Start (auf der AI-Box)
```bash
cd xtts
+2 -2
View File
@@ -1,5 +1,5 @@
"""
ARIA Local-LLM-Adapter (Gamebox) Plan B, Phase B0.
ARIA Local-LLM-Adapter (AI-Box) Plan B, Phase B0.
Bruecke zwischen RVS und dem lokalen llama.cpp-Server. Spiegelt das Muster der
whisper-bridge: verbindet sich per WebSocket mit dem RVS (Token-Room, TLS mit
@@ -7,7 +7,7 @@ ws-Fallback, Reconnect-Backoff), lauscht auf `llm_request` und ruft den lokalen
llama.cpp-`/v1/chat/completions`-Endpoint (OpenAI-kompatibel), antwortet mit
`llm_response` (korreliert per requestId).
Topologie: Gamebox steht zuhause, ARIA im RZ die Kommunikation laeuft ueber
Topologie: AI-Box steht zuhause, ARIA im RZ die Kommunikation laeuft ueber
den RVS (wie TTS/STT), keine IPs zu pflegen. Nur URL + Token.
Env:
+3 -3
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
ARIA Whisper Bridge laeuft auf der Gamebox (RTX 3060).
ARIA Whisper Bridge laeuft auf der AI-Box (RTX 3060).
Zwei Modi:
@@ -292,7 +292,7 @@ async def _send(ws, mtype: str, payload: dict) -> None:
# ──────────────────────────────────────────────────────────────
# DEBUG-LOG ueber RVS → /shared/logs/app.log
#
# Stefan's Gamebox ist Windows, kein SSH → wir brauchen Whisper-Bridge-
# Stefan's AI-Box ist Windows, kein SSH → wir brauchen Whisper-Bridge-
# Logs ueber den gleichen Pfad wie die App: app_log-Messages via RVS,
# aria-bridge schreibt sie in /shared/logs/app.log. Diagnostic / App-
# Logs-Tab zeigen sie dann mit platform="whisper".
@@ -881,7 +881,7 @@ async def run_loop(runner: WhisperRunner, sessions: SessionManager) -> None:
logger.info("Initial: sende config_request an aria-bridge")
await _send(ws, "config_request", {"service": "whisper"})
# Startup-Marker — App-Logs zeigen damit ob Streaming-Code
# ueberhaupt aktiv ist (Stefan baut auf Gamebox via PS,
# ueberhaupt aktiv ist (Stefan baut auf AI-Box via PS,
# Build/Restart kann unbeabsichtigt alte Version weiterfahren).
await _debug_log(ws, "boot",
"whisper-bridge online — streaming-mode ENABLED, debug-log ON")