refactor(diagnostic): Einstellungen in 3 Sub-Tabs gliedern

Der Settings-Tab war auf 13 Sektionen untereinander gewachsen (unuebersichtlich).
Jetzt drei Sub-Tabs im #tab-settings:
- Modelle & KI: Sprachmodell (Brain), Lokales LLM, Externe Anbieter (OpenRouter
  & Co — Platzhalter), Sprachausgabe/F5-TTS, Spracherkennung (STT: Voxtral/
  Whisper), Voice-ID
- Integrationen: OAuth-Apps, FLUX Bildgenerierung
- System & Wartung: Reparatur/Restart, Komplett-Reset, Betriebsmodus,
  Runtime-Konfiguration, App-Onboarding-QR

Nur Re-Parenting: jede Sektion wird byte-identisch in ihr Panel verschoben,
alle Panels bleiben immer im DOM (nur CSS zeigt/versteckt), Parent bleibt
#tab-settings → alle Loader (get_voice_config, loadRuntimeConfig, …) und
Save/Load-Handler laufen unveraendert. Verifiziert: 46 Element-ids vorher =
46 nachher, keine verloren/doppelt; JS-Block node --check sauber.

Neu: settings-subnav + switchSettingsTab() (merkt den zuletzt gewaehlten
Sub-Tab in localStorage), STT-Section-Hinweis dass die Engine pro Compute-Node
via COMPOSE_PROFILES gewaehlt wird, Platzhalter-Section fuer externe Anbieter
(kein Backend, nur reservierter Platz). App unveraendert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 23:49:25 +02:00
co-authored by Claude Opus 4.8
parent 182351e022
commit 17a60e5d3e
+285 -246
View File
@@ -126,6 +126,12 @@
/* Settings */
.settings-section { margin-bottom:20px; }
.settings-section h2 { margin-bottom:12px; }
.settings-subnav { display:flex; gap:4px; flex-wrap:wrap; margin:2px 0 18px; border-bottom:1px solid #1E1E2E; }
.settings-subnav-btn { background:none; border:none; color:#8888AA; font-family:inherit; font-size:13px; padding:8px 14px; cursor:pointer; border-bottom:2px solid transparent; }
.settings-subnav-btn:hover { color:#E0E0F0; }
.settings-subnav-btn.active { color:#0096FF; border-bottom-color:#0096FF; }
.settings-subtab { display:none; }
.settings-subtab.visible { display:block; }
/* Metric-Zellen im Token/Calls-Card */
.metric-cell { background:#0D0D1A; border:1px solid #1E1E2E; border-radius:6px; padding:8px 10px; }
.metric-cell .metric-label { color:#8888AA; font-size:10px; }
@@ -488,65 +494,126 @@
</div>
</div>
<!-- Reparatur & Restart -->
<div class="settings-section">
<h2>Reparatur & Restart</h2>
<div class="card" style="line-height:1.6;">
<p style="color:#8888AA;font-size:12px;margin:0 0 10px;">
Wenn ein Container haengt oder ARIA nicht mehr antwortet — hier kann man gezielt eingreifen.
</p>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
<button class="btn secondary" onclick="restartContainer('aria-bridge')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-bridge neu</button>
<button class="btn secondary" onclick="restartContainer('aria-brain')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-brain neu</button>
<button class="btn secondary" onclick="restartContainer('aria-qdrant')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-qdrant neu</button>
</div>
<div id="restart-status" style="margin-top:10px;font-size:11px;color:#8888AA;"></div>
</div>
<!-- Sub-Tab-Navigation (Einstellungen) -->
<div class="settings-subnav">
<button class="settings-subnav-btn active" data-sub="models" onclick="switchSettingsTab('models')">Modelle &amp; KI</button>
<button class="settings-subnav-btn" data-sub="integrations" onclick="switchSettingsTab('integrations')">Integrationen</button>
<button class="settings-subnav-btn" data-sub="system" onclick="switchSettingsTab('system')">System &amp; Wartung</button>
</div>
<!-- Komplett-Reset -->
<div class="settings-section">
<h2>Komplett-Reset</h2>
<div class="card" style="line-height:1.6;border-left:3px solid #FF3B30;">
<p style="color:#FF6B6B;font-size:12px;margin:0 0 10px;">
<strong>⚠ WIPE ALL</strong> — alle Einstellungen, Stimmen und das komplette
Gedächtnis (Vector-DB) werden gelöscht. ARIA wird leer wie nach
Erstinstallation. Bleiben tun nur:
</p>
<ul style="color:#8888AA;font-size:12px;margin:0 0 12px 16px;padding:0;">
<li><code>.env</code> (Tokens + RVS-Config)</li>
<li><code>aria-data/ssh/</code> (SSH-Keys für aria-wohnung)</li>
</ul>
<p style="color:#8888AA;font-size:12px;margin:0 0 10px;">
Vorher exportieren wenn etwas erhalten bleiben soll (Gehirn-Tab + Voice-Liste).
</p>
<button class="btn" onclick="wipeAll()" style="background:#3A1010;border:1px solid #FF3B30;color:#FF6B6B;">🗑 ALLES löschen — neue ARIA</button>
<div id="wipe-status" style="margin-top:10px;font-size:11px;color:#8888AA;"></div>
</div>
</div>
<div class="settings-subtab visible" data-sub="models">
<!-- Betriebsmodus -->
<!-- Tool-Berechtigungen-Section entfernt — Brain steuert Tool-Use
selbst (Skills + skill_create Meta-Tool). Es gibt keine granulare
Permission-Maske, Brain weiss zur Laufzeit welche Tools es hat. -->
<!-- Brain-Model-Einstellung -->
<div class="settings-section">
<h2>Betriebsmodus</h2>
<h2>Sprachmodell (Brain)</h2>
<div class="card" style="max-width:500px;">
<div id="mode-selector" style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
<button class="btn mode-btn" data-mode="normal" onclick="setMode('normal')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F7E2;</span> Normal<br><span style="font-size:10px;color:#8888AA;">Hoert zu, antwortet, spricht</span>
</button>
<button class="btn mode-btn" data-mode="nicht_stoeren" onclick="setMode('nicht_stoeren')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F534;</span> Nicht stoeren<br><span style="font-size:10px;color:#8888AA;">Nur Kritikalarme</span>
</button>
<button class="btn mode-btn" data-mode="fluester" onclick="setMode('fluester')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F7E1;</span> Fluestern<br><span style="font-size:10px;color:#8888AA;">Nur Text, keine Sprache</span>
</button>
<button class="btn mode-btn" data-mode="hangar" onclick="setMode('hangar')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x2708;&#xFE0F;</span> Hangar<br><span style="font-size:10px;color:#8888AA;">Nur wichtige Meldungen</span>
</button>
<button class="btn mode-btn" data-mode="gaming" onclick="setMode('gaming')" style="background:#1E1E2E;border:2px solid transparent;grid-column:1/-1;">
<span style="font-size:18px;">&#x1F3AE;</span> Gaming<br><span style="font-size:10px;color:#8888AA;">Nur direkte Fragen</span>
</button>
<div style="font-size:11px;color:#8888AA;margin-bottom:10px;line-height:1.5;">
Welches Claude-Model das Brain pro Anfrage nutzt. Wert wird in
<code>/shared/config/runtime.json</code> als <code>brainModel</code> persistiert.
Bei Aenderung: <strong>aria-brain restarten</strong> (Reparatur-Section oben), damit's greift.
<br><br>
ARIA laeuft ueber dein Claude-Max-Abo (CLI) — waehlbar ist der <strong>Tier</strong>
(Opus/Sonnet/Haiku), nicht eine feste Version. Die CLI nimmt automatisch das
jeweils aktuelle Modell des Tiers.
<br><br>
Die Auswahlliste kommt aus <code>/shared/config/models.json</code> — dort kannst du
Tiers/Beschreibungen anpassen (kein Neustart noetig, danach „↻ Aktualisieren").
</div>
<div style="margin-top:8px;font-size:11px;color:#555570;" id="mode-status">Aktueller Modus: Normal</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:12px;color:#8888AA;white-space:nowrap;">Aktives Model:</span>
<select id="setting-model-select" onchange="onModelSelectChange()" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="">(lade Liste…)</option>
</select>
<button class="btn secondary" onclick="loadModelList()" title="Liste vom Proxy neu holen" style="padding:4px 8px;font-size:10px;">↻ Aktualisieren</button>
<button class="btn" onclick="saveModel()" style="padding:4px 8px;font-size:10px;">Setzen</button>
</div>
<div id="model-desc" style="font-size:10px;color:#6a6a88;margin-bottom:6px;min-height:12px;"></div>
<div id="model-status" style="font-size:10px;color:#8888AA;margin-bottom:8px;"></div>
<details style="font-size:11px;color:#8888AA;">
<summary style="cursor:pointer;">Erweitert: freie Model-ID</summary>
<div style="display:flex;align-items:center;gap:8px;margin-top:6px;">
<input type="text" id="setting-model" placeholder="z.B. claude-opus-4" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<button class="btn secondary" onclick="loadModel()" style="padding:4px 8px;font-size:10px;">Laden</button>
<button class="btn" onclick="saveModelFreeText()" style="padding:4px 8px;font-size:10px;">Setzen</button>
</div>
</details>
</div>
</div>
<div class="settings-section">
<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
<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>.
</div>
<!-- Master -->
<label style="display:flex;align-items:flex-start;gap:8px;margin-bottom:4px;font-size:13px;color:#E0E0F0;cursor:pointer;">
<input type="checkbox" id="local-llm-enabled" onchange="saveLocalLlmConfig()" style="margin:2px 0 0 0;">
<span><strong>Lokales LLM einschalten</strong></span>
</label>
<div style="font-size:10px;color:#8888AA;margin:0 0 12px 24px;line-height:1.5;">
<strong style="color:#4ADE80;">AN:</strong> leichte Fragen → lokal (schnell), schwere → Claude.&nbsp;
<strong style="color:#8888AA;">AUS:</strong> alles laeuft ueber Claude (wie bisher). — <em>Das ist der Normal-Betrieb.</em>
</div>
<!-- Nur lokal -->
<label style="display:flex;align-items:flex-start;gap:8px;margin-bottom:4px;font-size:13px;color:#E0E0F0;cursor:pointer;">
<input type="checkbox" id="local-llm-onlylocal" onchange="saveLocalLlmConfig()" style="margin:2px 0 0 0;">
<span><strong>Nur lokales LLM</strong> — Claude komplett aussperren</span>
</label>
<div style="font-size:10px;color:#8888AA;margin:0 0 12px 24px;line-height:1.5;">
<strong style="color:#FFD60A;">Nur zum Testen.</strong> Erzwingt IMMER das lokale Modell — auch bei
schweren Fragen, ohne Claude-Rettung. So siehst du, was Qwen allein kann. Werkzeug-Fragen
(Wetter/Timer/…) funktionieren dann nicht. <strong>Fuer den Alltag: AUS lassen.</strong>
</div>
<!-- Tool-Umfang -->
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;">
<span style="font-size:13px;color:#E0E0F0;"><strong>Werkzeuge lokal:</strong></span>
<select id="local-llm-toolvariant" onchange="saveLocalLlmConfig()" style="background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="slim">Abgespeckt — kuratierte Tools</option>
<option value="full" disabled>Voll — ganzes Arsenal (braucht mehr VRAM)</option>
</select>
<button class="info-btn" onclick="showInfo('local-llm-tools')" title="Voll: wie viel VRAM?"></button>
</div>
<div style="font-size:10px;color:#8888AA;margin:0 0 6px 0;line-height:1.5;">
Welche Werkzeuge das lokale Modell <em>selbst</em> ausfuehren darf. „Voll" ist gesperrt,
bis eine 2.&nbsp;Grafikkarte da ist (siehe&nbsp;ⓘ).
<br><span style="color:#FFD60A;">Aktueller Stand (B1a): das lokale Modell <strong>plaudert nur</strong> — Werkzeuge macht noch Claude. Lokale Tools kommen mit B1b.</span>
</div>
<!-- Lokales Modell (llama-swap, B0.5) -->
<div style="display:flex;align-items:center;gap:8px;margin:12px 0 4px 0;padding-top:10px;border-top:1px solid #2a2a3a;">
<span style="font-size:13px;color:#E0E0F0;"><strong>Lokales Modell:</strong></span>
<select id="local-llm-model" onchange="saveLocalLlmConfig()" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="">(lade Liste…)</option>
</select>
<button class="btn secondary" onclick="loadLocalModelList()" title="Liste neu laden" style="padding:4px 8px;font-size:10px;"></button>
</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) —
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>
<div id="local-llm-status" style="font-size:11px;color:#6a6a88;margin-top:8px;padding-top:8px;border-top:1px solid #2a2a3a;min-height:14px;"></div>
</div>
</div>
<!-- Externe KI-Anbieter (Platzhalter) -->
<div class="settings-section">
<h2>Externe Anbieter (OpenRouter &amp; Co)</h2>
<div class="card" style="max-width:540px;border-left:3px solid #8888AA;">
<p style="color:#AAA;font-size:13px;margin:0 0 8px;">Geplant: neben den lokalen Diensten (F5-TTS, Whisper/Voxtral, lokales LLM) auch externe Anbieter wie <b>OpenRouter</b> &amp; Co anbinden.</p>
<p style="color:#8888AA;font-size:12px;margin:0;">Noch nicht angebunden — der Bereich ist hier als Platz reserviert. Die Verdrahtung (API-Key + Routing) kommt als eigener Schritt.</p>
</div>
</div>
@@ -663,97 +730,10 @@
</div>
</div>
<!-- FLUX Bildgenerierung -->
<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).
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.
</div>
<div class="card" style="max-width:500px;">
<div style="display:flex;flex-direction:column;gap:8px;">
<label style="color:#8888AA;font-size:12px;">Default-Modell:</label>
<select id="diag-flux-default-model" onchange="sendVoiceConfig()"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<option value="dev">FLUX.1-dev (hoechste Qualitaet, 20-90s)</option>
<option value="schnell">FLUX.1-schnell (4-step, 5-15s)</option>
</select>
<label style="color:#8888AA;font-size:12px;">
Raw-Keyword — Pipe-Modus, ARIA leitet den Prompt 1:1 durch (kein Rewriting):
</label>
<input type="text" id="diag-flux-keyword-raw"
placeholder="flux"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<label style="color:#8888AA;font-size:12px;">
Switch-Keyword — zwingt das ANDERE Modell als das Default fuer diesen Request:
</label>
<input type="text" id="diag-flux-keyword-switch"
placeholder="fix"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<label style="color:#8888AA;font-size:12px;margin-top:4px;">
HuggingFace-Token (nur fuer FLUX.1-dev — gated Modell, Lizenz-Bestaetigung).
Wird per RVS an die flux-bridge gepusht. Leer = kein Token (Schnell-Modell laeuft auch ohne).
</label>
<div style="display:flex;gap:4px;">
<input type="password" id="diag-flux-hf-token"
placeholder="hf_..."
style="flex:1;min-width:0;box-sizing:border-box;background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;font-family:monospace;">
<button type="button" class="btn secondary" onclick="toggleSecret('diag-flux-hf-token', this)" style="padding:4px 10px;flex-shrink:0;" title="Anzeigen/Verbergen">&#128065;</button>
</div>
<div style="color:#666680;font-size:10px;">
Erst auf <a href="https://huggingface.co/black-forest-labs/FLUX.1-dev" target="_blank" style="color:#0096FF;">huggingface.co/.../FLUX.1-dev</a> "Agree" klicken,
dann unter <a href="https://huggingface.co/settings/tokens" target="_blank" style="color:#0096FF;">Settings → Tokens</a> einen Read-Token erzeugen.
</div>
<div style="display:flex;gap:8px;align-items:center;margin-top:6px;">
<button class="btn primary" onclick="sendVoiceConfig()" style="padding:6px 14px;font-size:12px;">
Anwenden
</button>
<div style="color:#666680;font-size:10px;">
Beide Modelle = volle Qualitaet, schnell ist nur ein 4-Step-Distillat (Apache-2.0).
</div>
</div>
</div>
</div>
</div>
<!-- OAuth Apps -->
<div class="settings-section">
<h2>OAuth-Apps (Spotify, Google, GitHub, Strava, Microsoft, ...)</h2>
<div style="font-size:11px;color:#8888AA;margin-bottom:8px;">
Trag pro Service `client_id` + `client_secret` ein (aus dem Developer-Dashboard
des Providers). RVS stellt die Callback-URL bereit — die musst Du EINMAL pro
Service im Provider-Dashboard als gueltige Redirect-URI eintragen.
Danach kann ARIA per `oauth_authorize`-Tool eine Auth-URL bauen; Stefan klickt,
autorisiert, ARIA bekommt den Token automatisch.
</div>
<div style="font-size:11px;color:#666680;margin-bottom:8px;" id="oauth-callback-hint">
Lade Callback-URL...
</div>
<div class="card" style="max-width:780px;">
<div id="oauth-services-list" style="display:flex;flex-direction:column;gap:8px;">
<div style="color:#555570;font-style:italic;">Lade Services...</div>
</div>
<div style="margin-top:14px;display:flex;gap:8px;align-items:center;">
<button class="btn secondary" onclick="loadOAuthServices()" style="padding:6px 14px;font-size:12px;">
↻ Neu laden
</button>
<div style="color:#666680;font-size:10px;">
client_secret wird verschlüsselt persistiert (file-mode 0600). Nicht in git, nicht im Repo.
</div>
</div>
</div>
</div>
<!-- Whisper (STT) -->
<div class="settings-section">
<h2>Whisper (Spracherkennung)</h2>
<h2>Spracherkennung (STT: Voxtral / Whisper)</h2>
<p style="color:#8888AA;font-size:12px;max-width:500px;margin:-6px 0 10px;">Die aktive STT-Engine wird pro Compute-Node über <code>COMPOSE_PROFILES</code> gewählt (Voxtral <em>oder</em> Whisper, siehe Satelliten &rarr; Compute-Flotte). Die folgenden Einstellungen betreffen Whisper.</p>
<div style="font-size:11px;color:#8888AA;margin-bottom:8px;">
Aenderungen werden sofort an die Bridge gesendet und das Modell neu geladen
(kann bei medium/large 10-30s dauern — waehrend dieser Zeit ist STT kurz pausiert).
@@ -822,6 +802,162 @@
</div>
</div>
</div>
</div>
<div class="settings-subtab" data-sub="integrations">
<!-- OAuth Apps -->
<div class="settings-section">
<h2>OAuth-Apps (Spotify, Google, GitHub, Strava, Microsoft, ...)</h2>
<div style="font-size:11px;color:#8888AA;margin-bottom:8px;">
Trag pro Service `client_id` + `client_secret` ein (aus dem Developer-Dashboard
des Providers). RVS stellt die Callback-URL bereit — die musst Du EINMAL pro
Service im Provider-Dashboard als gueltige Redirect-URI eintragen.
Danach kann ARIA per `oauth_authorize`-Tool eine Auth-URL bauen; Stefan klickt,
autorisiert, ARIA bekommt den Token automatisch.
</div>
<div style="font-size:11px;color:#666680;margin-bottom:8px;" id="oauth-callback-hint">
Lade Callback-URL...
</div>
<div class="card" style="max-width:780px;">
<div id="oauth-services-list" style="display:flex;flex-direction:column;gap:8px;">
<div style="color:#555570;font-style:italic;">Lade Services...</div>
</div>
<div style="margin-top:14px;display:flex;gap:8px;align-items:center;">
<button class="btn secondary" onclick="loadOAuthServices()" style="padding:6px 14px;font-size:12px;">
↻ Neu laden
</button>
<div style="color:#666680;font-size:10px;">
client_secret wird verschlüsselt persistiert (file-mode 0600). Nicht in git, nicht im Repo.
</div>
</div>
</div>
</div>
<!-- FLUX Bildgenerierung -->
<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).
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.
</div>
<div class="card" style="max-width:500px;">
<div style="display:flex;flex-direction:column;gap:8px;">
<label style="color:#8888AA;font-size:12px;">Default-Modell:</label>
<select id="diag-flux-default-model" onchange="sendVoiceConfig()"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<option value="dev">FLUX.1-dev (hoechste Qualitaet, 20-90s)</option>
<option value="schnell">FLUX.1-schnell (4-step, 5-15s)</option>
</select>
<label style="color:#8888AA;font-size:12px;">
Raw-Keyword — Pipe-Modus, ARIA leitet den Prompt 1:1 durch (kein Rewriting):
</label>
<input type="text" id="diag-flux-keyword-raw"
placeholder="flux"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<label style="color:#8888AA;font-size:12px;">
Switch-Keyword — zwingt das ANDERE Modell als das Default fuer diesen Request:
</label>
<input type="text" id="diag-flux-keyword-switch"
placeholder="fix"
style="background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;">
<label style="color:#8888AA;font-size:12px;margin-top:4px;">
HuggingFace-Token (nur fuer FLUX.1-dev — gated Modell, Lizenz-Bestaetigung).
Wird per RVS an die flux-bridge gepusht. Leer = kein Token (Schnell-Modell laeuft auch ohne).
</label>
<div style="display:flex;gap:4px;">
<input type="password" id="diag-flux-hf-token"
placeholder="hf_..."
style="flex:1;min-width:0;box-sizing:border-box;background:#1E1E2E;color:#fff;border:1px solid #2A2A3E;border-radius:6px;padding:6px 10px;font-size:13px;font-family:monospace;">
<button type="button" class="btn secondary" onclick="toggleSecret('diag-flux-hf-token', this)" style="padding:4px 10px;flex-shrink:0;" title="Anzeigen/Verbergen">&#128065;</button>
</div>
<div style="color:#666680;font-size:10px;">
Erst auf <a href="https://huggingface.co/black-forest-labs/FLUX.1-dev" target="_blank" style="color:#0096FF;">huggingface.co/.../FLUX.1-dev</a> "Agree" klicken,
dann unter <a href="https://huggingface.co/settings/tokens" target="_blank" style="color:#0096FF;">Settings → Tokens</a> einen Read-Token erzeugen.
</div>
<div style="display:flex;gap:8px;align-items:center;margin-top:6px;">
<button class="btn primary" onclick="sendVoiceConfig()" style="padding:6px 14px;font-size:12px;">
Anwenden
</button>
<div style="color:#666680;font-size:10px;">
Beide Modelle = volle Qualitaet, schnell ist nur ein 4-Step-Distillat (Apache-2.0).
</div>
</div>
</div>
</div>
</div>
</div>
<div class="settings-subtab" data-sub="system">
<!-- Reparatur & Restart -->
<div class="settings-section">
<h2>Reparatur & Restart</h2>
<div class="card" style="line-height:1.6;">
<p style="color:#8888AA;font-size:12px;margin:0 0 10px;">
Wenn ein Container haengt oder ARIA nicht mehr antwortet — hier kann man gezielt eingreifen.
</p>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
<button class="btn secondary" onclick="restartContainer('aria-bridge')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-bridge neu</button>
<button class="btn secondary" onclick="restartContainer('aria-brain')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-brain neu</button>
<button class="btn secondary" onclick="restartContainer('aria-qdrant')" style="color:#FF3B30;border-color:#FF3B30;">🚨 aria-qdrant neu</button>
</div>
<div id="restart-status" style="margin-top:10px;font-size:11px;color:#8888AA;"></div>
</div>
</div>
<!-- Komplett-Reset -->
<div class="settings-section">
<h2>Komplett-Reset</h2>
<div class="card" style="line-height:1.6;border-left:3px solid #FF3B30;">
<p style="color:#FF6B6B;font-size:12px;margin:0 0 10px;">
<strong>⚠ WIPE ALL</strong> — alle Einstellungen, Stimmen und das komplette
Gedächtnis (Vector-DB) werden gelöscht. ARIA wird leer wie nach
Erstinstallation. Bleiben tun nur:
</p>
<ul style="color:#8888AA;font-size:12px;margin:0 0 12px 16px;padding:0;">
<li><code>.env</code> (Tokens + RVS-Config)</li>
<li><code>aria-data/ssh/</code> (SSH-Keys für aria-wohnung)</li>
</ul>
<p style="color:#8888AA;font-size:12px;margin:0 0 10px;">
Vorher exportieren wenn etwas erhalten bleiben soll (Gehirn-Tab + Voice-Liste).
</p>
<button class="btn" onclick="wipeAll()" style="background:#3A1010;border:1px solid #FF3B30;color:#FF6B6B;">🗑 ALLES löschen — neue ARIA</button>
<div id="wipe-status" style="margin-top:10px;font-size:11px;color:#8888AA;"></div>
</div>
</div>
<!-- Betriebsmodus -->
<div class="settings-section">
<h2>Betriebsmodus</h2>
<div class="card" style="max-width:500px;">
<div id="mode-selector" style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
<button class="btn mode-btn" data-mode="normal" onclick="setMode('normal')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F7E2;</span> Normal<br><span style="font-size:10px;color:#8888AA;">Hoert zu, antwortet, spricht</span>
</button>
<button class="btn mode-btn" data-mode="nicht_stoeren" onclick="setMode('nicht_stoeren')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F534;</span> Nicht stoeren<br><span style="font-size:10px;color:#8888AA;">Nur Kritikalarme</span>
</button>
<button class="btn mode-btn" data-mode="fluester" onclick="setMode('fluester')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x1F7E1;</span> Fluestern<br><span style="font-size:10px;color:#8888AA;">Nur Text, keine Sprache</span>
</button>
<button class="btn mode-btn" data-mode="hangar" onclick="setMode('hangar')" style="background:#1E1E2E;border:2px solid transparent;">
<span style="font-size:18px;">&#x2708;&#xFE0F;</span> Hangar<br><span style="font-size:10px;color:#8888AA;">Nur wichtige Meldungen</span>
</button>
<button class="btn mode-btn" data-mode="gaming" onclick="setMode('gaming')" style="background:#1E1E2E;border:2px solid transparent;grid-column:1/-1;">
<span style="font-size:18px;">&#x1F3AE;</span> Gaming<br><span style="font-size:10px;color:#8888AA;">Nur direkte Fragen</span>
</button>
</div>
<div style="margin-top:8px;font-size:11px;color:#555570;" id="mode-status">Aktueller Modus: Normal</div>
</div>
</div>
<!-- Runtime-Konfiguration -->
<div class="settings-section">
@@ -885,112 +1021,8 @@
</div>
</div>
</div>
<!-- Tool-Berechtigungen-Section entfernt — Brain steuert Tool-Use
selbst (Skills + skill_create Meta-Tool). Es gibt keine granulare
Permission-Maske, Brain weiss zur Laufzeit welche Tools es hat. -->
<!-- Brain-Model-Einstellung -->
<div class="settings-section">
<h2>Sprachmodell (Brain)</h2>
<div class="card" style="max-width:500px;">
<div style="font-size:11px;color:#8888AA;margin-bottom:10px;line-height:1.5;">
Welches Claude-Model das Brain pro Anfrage nutzt. Wert wird in
<code>/shared/config/runtime.json</code> als <code>brainModel</code> persistiert.
Bei Aenderung: <strong>aria-brain restarten</strong> (Reparatur-Section oben), damit's greift.
<br><br>
ARIA laeuft ueber dein Claude-Max-Abo (CLI) — waehlbar ist der <strong>Tier</strong>
(Opus/Sonnet/Haiku), nicht eine feste Version. Die CLI nimmt automatisch das
jeweils aktuelle Modell des Tiers.
<br><br>
Die Auswahlliste kommt aus <code>/shared/config/models.json</code> — dort kannst du
Tiers/Beschreibungen anpassen (kein Neustart noetig, danach „↻ Aktualisieren").
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:12px;color:#8888AA;white-space:nowrap;">Aktives Model:</span>
<select id="setting-model-select" onchange="onModelSelectChange()" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="">(lade Liste…)</option>
</select>
<button class="btn secondary" onclick="loadModelList()" title="Liste vom Proxy neu holen" style="padding:4px 8px;font-size:10px;">↻ Aktualisieren</button>
<button class="btn" onclick="saveModel()" style="padding:4px 8px;font-size:10px;">Setzen</button>
</div>
<div id="model-desc" style="font-size:10px;color:#6a6a88;margin-bottom:6px;min-height:12px;"></div>
<div id="model-status" style="font-size:10px;color:#8888AA;margin-bottom:8px;"></div>
<details style="font-size:11px;color:#8888AA;">
<summary style="cursor:pointer;">Erweitert: freie Model-ID</summary>
<div style="display:flex;align-items:center;gap:8px;margin-top:6px;">
<input type="text" id="setting-model" placeholder="z.B. claude-opus-4" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<button class="btn secondary" onclick="loadModel()" style="padding:4px 8px;font-size:10px;">Laden</button>
<button class="btn" onclick="saveModelFreeText()" style="padding:4px 8px;font-size:10px;">Setzen</button>
</div>
</details>
</div>
</div>
<div class="settings-section">
<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
<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>.
</div>
<!-- Master -->
<label style="display:flex;align-items:flex-start;gap:8px;margin-bottom:4px;font-size:13px;color:#E0E0F0;cursor:pointer;">
<input type="checkbox" id="local-llm-enabled" onchange="saveLocalLlmConfig()" style="margin:2px 0 0 0;">
<span><strong>Lokales LLM einschalten</strong></span>
</label>
<div style="font-size:10px;color:#8888AA;margin:0 0 12px 24px;line-height:1.5;">
<strong style="color:#4ADE80;">AN:</strong> leichte Fragen → lokal (schnell), schwere → Claude.&nbsp;
<strong style="color:#8888AA;">AUS:</strong> alles laeuft ueber Claude (wie bisher). — <em>Das ist der Normal-Betrieb.</em>
</div>
<!-- Nur lokal -->
<label style="display:flex;align-items:flex-start;gap:8px;margin-bottom:4px;font-size:13px;color:#E0E0F0;cursor:pointer;">
<input type="checkbox" id="local-llm-onlylocal" onchange="saveLocalLlmConfig()" style="margin:2px 0 0 0;">
<span><strong>Nur lokales LLM</strong> — Claude komplett aussperren</span>
</label>
<div style="font-size:10px;color:#8888AA;margin:0 0 12px 24px;line-height:1.5;">
<strong style="color:#FFD60A;">Nur zum Testen.</strong> Erzwingt IMMER das lokale Modell — auch bei
schweren Fragen, ohne Claude-Rettung. So siehst du, was Qwen allein kann. Werkzeug-Fragen
(Wetter/Timer/…) funktionieren dann nicht. <strong>Fuer den Alltag: AUS lassen.</strong>
</div>
<!-- Tool-Umfang -->
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;">
<span style="font-size:13px;color:#E0E0F0;"><strong>Werkzeuge lokal:</strong></span>
<select id="local-llm-toolvariant" onchange="saveLocalLlmConfig()" style="background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="slim">Abgespeckt — kuratierte Tools</option>
<option value="full" disabled>Voll — ganzes Arsenal (braucht mehr VRAM)</option>
</select>
<button class="info-btn" onclick="showInfo('local-llm-tools')" title="Voll: wie viel VRAM?"></button>
</div>
<div style="font-size:10px;color:#8888AA;margin:0 0 6px 0;line-height:1.5;">
Welche Werkzeuge das lokale Modell <em>selbst</em> ausfuehren darf. „Voll" ist gesperrt,
bis eine 2.&nbsp;Grafikkarte da ist (siehe&nbsp;ⓘ).
<br><span style="color:#FFD60A;">Aktueller Stand (B1a): das lokale Modell <strong>plaudert nur</strong> — Werkzeuge macht noch Claude. Lokale Tools kommen mit B1b.</span>
</div>
<!-- Lokales Modell (llama-swap, B0.5) -->
<div style="display:flex;align-items:center;gap:8px;margin:12px 0 4px 0;padding-top:10px;border-top:1px solid #2a2a3a;">
<span style="font-size:13px;color:#E0E0F0;"><strong>Lokales Modell:</strong></span>
<select id="local-llm-model" onchange="saveLocalLlmConfig()" style="flex:1;background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:6px 8px;color:#E0E0F0;font-family:inherit;font-size:12px;">
<option value="">(lade Liste…)</option>
</select>
<button class="btn secondary" onclick="loadLocalModelList()" title="Liste neu laden" style="padding:4px 8px;font-size:10px;"></button>
</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) —
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>
<div id="local-llm-status" style="font-size:11px;color:#6a6a88;margin-top:8px;padding-top:8px;border-top:1px solid #2a2a3a;min-height:14px;"></div>
</div>
</div>
<!-- OpenClaw-Config-Sektion entfernt — aria-core ist raus. -->
@@ -1990,6 +2022,7 @@
alert('Es war kein Fingerprint vorhanden.');
}
refreshVoiceIdStatus();
switchSettingsTab(localStorage.getItem('diag_settings_subtab') || 'models');
return;
}
@@ -4165,6 +4198,12 @@
// ── Haupt-Tab Navigation ──────────────────────────────────
function switchSettingsTab(sub) {
sub = sub || 'models';
document.querySelectorAll('.settings-subtab').forEach(el => el.classList.toggle('visible', el.dataset.sub === sub));
document.querySelectorAll('.settings-subnav-btn').forEach(b => b.classList.toggle('active', b.dataset.sub === sub));
try { localStorage.setItem('diag_settings_subtab', sub); } catch (e) {}
}
function switchMainTab(tab) {
document.querySelectorAll('.main-tab').forEach(el => el.classList.remove('visible'));
document.querySelectorAll('.main-nav-btn').forEach(b => b.classList.remove('active'));