diff --git a/CHANGELOG.md b/CHANGELOG.md index b1d8ded..40c002e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 0d95ae1..352c3e0 100644 --- a/README.md +++ b/README.md @@ -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_.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_.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 diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index 669682d..92cbe6e 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -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(''); - // 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>({}); 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 = () => { - {/* 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; diff --git a/aria-brain/agent.py b/aria-brain/agent.py index d443aa2..c8515da 100644 --- a/aria-brain/agent.py +++ b/aria-brain/agent.py @@ -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" diff --git a/aria-brain/local_llm.py b/aria-brain/local_llm.py index b5df701..728b9f6 100644 --- a/aria-brain/local_llm.py +++ b/aria-brain/local_llm.py @@ -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; diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index ed40a63..a2d816c 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -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")) diff --git a/diagnostic/index.html b/diagnostic/index.html index e3a1827..81c374e 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -162,7 +162,7 @@ - +