feat(app+brain): App-Bugfixes + Skill-Mgmt-Tools + Voice-Speed persistent + Skill-Browser
App-Bugs:
- Trigger-Liste war leer: brainApi.listTriggers() cast'te {triggers: [...]}
direkt als Array, t.sort() warf — TriggerBrowser blieb leer. Fix: unwrap.
- GPS-Tracking startete erst bei SettingsScreen-Mount, nicht beim App-Boot.
Wenn Stefan direkt in den Chat ging, blieb GPS aus. Fix: restoreFromStorage()
in App.tsx useEffect.
- Text in Chat-Bubbles nicht markierbar / kein Copy-Mechanismus: Bubble jetzt
Pressable mit onLongPress + neues ⎘-Icon in Status-Row → openBubbleActions().
Alert-Menu mit "Ganzen Text teilen" + pro extrahierte URL/Mail/Tel eine
eigene Option. Share.share() — keine neuen Native-Deps noetig.
Brain — Skill-Mgmt:
- ARIA legte beim Skill-Umbau neue Versionen mit Suffix an (Skill-Friedhof),
weil sie kein Update/Delete-Tool kannte. Zwei neue META_TOOLS in agent.py:
skill_update (kann entry_code, readme, pip_packages, args, description,
active patchen — venv wird bei pip_packages-Aenderung rebuilt) + skill_delete.
- skills.py update_skill um entry_code/readme/pip_packages erweitert,
venv-Rebuild bei pip-Aenderung.
Bridge — Voice-Speed persistent:
- _next_speed_override war pro-Request-Override ohne Persistenz. Bei
Diagnostic-Chats / Trigger-Replies ohne vorherigen App-Chat fiel der Speed
auf 1.0 zurueck, ebenso nach Bridge-Restart. Jetzt: _persistent_xtts_speed
aus voice_config.json (xttsSpeed), wird nach jedem App-chat mit speed
autopersistiert. TTS-Generation faellt zurueck: per-Request > persistent > 1.0.
App — Feature 6:
- SkillBrowser.tsx: Liste aller Skills, Toggle aktiv/inaktiv, Detail-Modal
mit Args-Inputs, Ausfuehren mit Live-stdout/stderr, Logs der letzten 20
Runs, Loeschen. Settings-Sektion "Skills" (🛠️) zwischen Trigger und
Protokoll. brainApi.listSkills/getSkill/runSkill/updateSkill/deleteSkill/
getSkillLogs ergaenzt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+72
-3
@@ -519,6 +519,10 @@ class ARIABridge:
|
||||
self.xtts_voice = ""
|
||||
self._f5tts_config: dict = {}
|
||||
self._flux_config: dict = {}
|
||||
# Persistente TTS-Speed (App-Setting), wird aus voice_config.json
|
||||
# gelesen + bei config-Broadcasts (siehe handle config in chat)
|
||||
# geupdated. Fallback wenn der Per-Request-Override fehlt.
|
||||
self._persistent_xtts_speed: Optional[float] = None
|
||||
vc: dict = {}
|
||||
# Gespeicherte Voice-Config laden
|
||||
try:
|
||||
@@ -528,6 +532,19 @@ class ARIABridge:
|
||||
vc = json.load(f)
|
||||
self.tts_enabled = vc.get("ttsEnabled", True)
|
||||
self.xtts_voice = vc.get("xttsVoice", "")
|
||||
# Persistente TTS-Speed: vorher war's nur per-Chat-Override
|
||||
# (App schickte speed mit jeder Nachricht). Bei Diagnostic-Chat
|
||||
# OHNE App-Vor-Chat blieb _next_speed_override=None → 1.0.
|
||||
# Jetzt persistent — Bridge greift bei TTS immer auf den
|
||||
# zuletzt von der App gesetzten Wert zurueck.
|
||||
try:
|
||||
persisted_speed = float(vc.get("xttsSpeed", 1.0))
|
||||
if 0.1 <= persisted_speed <= 5.0:
|
||||
self._persistent_xtts_speed: Optional[float] = persisted_speed
|
||||
else:
|
||||
self._persistent_xtts_speed = None
|
||||
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
|
||||
# Restart wiederbekommt — sonst stuende sie auf Hard-Defaults)
|
||||
@@ -1185,7 +1202,16 @@ class ARIABridge:
|
||||
# TTS-Call wieder die alte Default-Stimme. Der Override bleibt gueltig bis
|
||||
# zum naechsten chat-Event, wo er entweder ueberschrieben oder geloescht wird.
|
||||
xtts_voice = self._next_voice_override or getattr(self, 'xtts_voice', '')
|
||||
xtts_speed = self._next_speed_override or 1.0
|
||||
# Speed-Reihenfolge: Per-Request-Override (App schickte gerade) >
|
||||
# persistierter App-Setting (voice_config.json xttsSpeed) > 1.0 default.
|
||||
# Damit greift die App-Speed auch bei Diagnostic-Chats / Trigger-
|
||||
# Replies / Bridge-Restart, ohne dass die App vorher noch mal getippt
|
||||
# haben muss.
|
||||
xtts_speed = (
|
||||
self._next_speed_override
|
||||
or getattr(self, "_persistent_xtts_speed", None)
|
||||
or 1.0
|
||||
)
|
||||
|
||||
tts_text = tts_text_preview or text
|
||||
if not tts_text:
|
||||
@@ -1274,6 +1300,8 @@ class ARIABridge:
|
||||
"xttsVoice": getattr(self, "xtts_voice", ""),
|
||||
"whisperModel": self.stt_engine.model_size,
|
||||
}
|
||||
if getattr(self, "_persistent_xtts_speed", None) is not None:
|
||||
payload["xttsSpeed"] = self._persistent_xtts_speed
|
||||
payload.update(getattr(self, "_f5tts_config", {}) or {})
|
||||
payload.update(getattr(self, "_flux_config", {}) or {})
|
||||
await self._send_to_rvs({
|
||||
@@ -1285,6 +1313,24 @@ class ARIABridge:
|
||||
except Exception as e:
|
||||
logger.debug("[rvs] Config-Broadcast fehlgeschlagen: %s", e)
|
||||
|
||||
async def _persist_speed_change(self, speed: float) -> None:
|
||||
"""Schreibt nur den xttsSpeed-Eintrag in voice_config.json — der
|
||||
Rest bleibt unangetastet. Wird gerufen wenn App per chat-Event
|
||||
einen neuen Speed mitschickt (kein config-Broadcast)."""
|
||||
try:
|
||||
path = "/shared/config/voice_config.json"
|
||||
data: dict = {}
|
||||
if os.path.exists(path):
|
||||
with open(path) as f:
|
||||
data = json.load(f) or {}
|
||||
data["xttsSpeed"] = speed
|
||||
os.makedirs("/shared/config", exist_ok=True)
|
||||
with open(path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
logger.info("[speed] Persistiert: %.2fx", speed)
|
||||
except Exception as exc:
|
||||
logger.warning("[speed] Persistierung fehlgeschlagen: %s", exc)
|
||||
|
||||
def _fetch_active_session(self) -> None:
|
||||
"""Holt die aktive Session vom Diagnostic-Endpoint."""
|
||||
try:
|
||||
@@ -1732,11 +1778,23 @@ class ARIABridge:
|
||||
self._next_voice_override = voice_override or None
|
||||
logger.info("[rvs] Voice fuer Antworten: %s",
|
||||
self._next_voice_override or "(Default)")
|
||||
# Speed-Override (TTS-Wiedergabegeschwindigkeit, pro Geraet)
|
||||
# Speed-Override (TTS-Wiedergabegeschwindigkeit, pro Geraet) —
|
||||
# plus persistente Spiegelung damit der Wert nach Bridge-Restart
|
||||
# erhalten bleibt und Diagnostic-Chats / Trigger-Replies den
|
||||
# zuletzt von der App gesetzten Speed bekommen.
|
||||
if "speed" in payload:
|
||||
try:
|
||||
speed = float(payload.get("speed", 0) or 0)
|
||||
self._next_speed_override = speed if 0.1 <= speed <= 5.0 else None
|
||||
if 0.1 <= speed <= 5.0:
|
||||
self._next_speed_override = speed
|
||||
# Persistieren wenn der Wert sich gegenueber dem
|
||||
# gespeicherten geaendert hat — vermeidet voice_config.json
|
||||
# auf jeder Nachricht zu schreiben.
|
||||
if speed != getattr(self, "_persistent_xtts_speed", None):
|
||||
self._persistent_xtts_speed = speed
|
||||
asyncio.create_task(self._persist_speed_change(speed))
|
||||
else:
|
||||
self._next_speed_override = None
|
||||
except (TypeError, ValueError):
|
||||
self._next_speed_override = None
|
||||
if text:
|
||||
@@ -1865,6 +1923,15 @@ class ARIABridge:
|
||||
self.xtts_voice = payload["xttsVoice"]
|
||||
logger.info("[rvs] XTTS-Stimme: %s", self.xtts_voice or "default")
|
||||
changed = True
|
||||
if "xttsSpeed" in payload:
|
||||
try:
|
||||
new_speed = float(payload["xttsSpeed"])
|
||||
if 0.1 <= new_speed <= 5.0:
|
||||
self._persistent_xtts_speed = new_speed
|
||||
logger.info("[rvs] XTTS-Speed (persistent): %.2fx", new_speed)
|
||||
changed = True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if "whisperModel" in payload:
|
||||
new_model = payload["whisperModel"]
|
||||
allowed = {"tiny", "base", "small", "medium", "large-v3"}
|
||||
@@ -1900,6 +1967,8 @@ class ARIABridge:
|
||||
"xttsVoice": getattr(self, "xtts_voice", ""),
|
||||
"whisperModel": self.stt_engine.model_size,
|
||||
}
|
||||
if getattr(self, "_persistent_xtts_speed", None) is not None:
|
||||
config_data["xttsSpeed"] = self._persistent_xtts_speed
|
||||
config_data.update(getattr(self, "_f5tts_config", {}))
|
||||
config_data.update(getattr(self, "_flux_config", {}))
|
||||
with open("/shared/config/voice_config.json", "w") as f:
|
||||
|
||||
Reference in New Issue
Block a user