From fa8f77691075f6ce22218a0808976ffde371fd30 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 3 Jul 2026 14:29:21 +0200 Subject: [PATCH] =?UTF-8?q?Freie=20Hand=20(A3):=20Medien-/Lautst=C3=A4rke-?= =?UTF-8?q?Steuerung=20f=C3=BCr=20den=20PC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - executor.py: /media (play_pause/next/prev/stop) + /volume (up/down/mute, steps 1-25) via pyautogui Media-Keys — wirkt wie Multimedia-Tastatur - mcp_pc.py: Tools pc_media + pc_volume für Hermes Co-Authored-By: Claude Fable 5 --- client/hermes-pc/executor.py | 36 ++++++++++++++++++++++++++++++++++++ mcp/mcp_pc.py | 24 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/client/hermes-pc/executor.py b/client/hermes-pc/executor.py index 948d1cd..956ea36 100644 --- a/client/hermes-pc/executor.py +++ b/client/hermes-pc/executor.py @@ -108,6 +108,42 @@ async def press_keys(req: dict): raise HTTPException(500, str(e)) +# ── Medien & Lautstärke (A3: Lucy steuert den PC per Sprache) ────────────── +# Media-Keys wirken auf den AKTIVEN Player (Spotify, YouTube, VLC …) — genau wie +# die Tasten auf einer Multimedia-Tastatur. Lautstärke = System-Master (2 % je Schritt). +MEDIA_KEYS = {"play_pause": "playpause", "next": "nexttrack", "prev": "prevtrack", "stop": "stop"} +VOLUME_KEYS = {"up": "volumeup", "down": "volumedown", "mute": "volumemute"} + + +@app.post("/media", dependencies=[Depends(require_auth)]) +async def media_control(req: dict): + action = (req.get("action") or "").strip().lower() + key = MEDIA_KEYS.get(action) + if not key: + raise HTTPException(400, f"Unbekannte Aktion '{action}'. Erlaubt: {', '.join(MEDIA_KEYS)}") + try: + import pyautogui + pyautogui.press(key) + return {"ok": True, "action": action} + except Exception as e: + raise HTTPException(500, str(e)) + + +@app.post("/volume", dependencies=[Depends(require_auth)]) +async def volume_control(req: dict): + action = (req.get("action") or "").strip().lower() + key = VOLUME_KEYS.get(action) + if not key: + raise HTTPException(400, f"Unbekannte Aktion '{action}'. Erlaubt: {', '.join(VOLUME_KEYS)}") + steps = 1 if action == "mute" else max(1, min(25, int(req.get("steps", 5)))) + try: + import pyautogui + pyautogui.press(key, presses=steps, interval=0.02) + return {"ok": True, "action": action, "steps": steps} + except Exception as e: + raise HTTPException(500, str(e)) + + # ── Apps / Browser ───────────────────────────────────────────────────────── @app.post("/open", dependencies=[Depends(require_auth)]) diff --git a/mcp/mcp_pc.py b/mcp/mcp_pc.py index ce2d986..62b4655 100644 --- a/mcp/mcp_pc.py +++ b/mcp/mcp_pc.py @@ -92,6 +92,30 @@ def pc_key(keys: str) -> str: return f"Tastenkombination '{keys}' gedrückt." if result.get("ok") else str(result) +@mcp.tool() +def pc_media(action: str) -> str: + """Steuert die Medien-Wiedergabe auf dem Windows-PC — wirkt auf den gerade aktiven Player + (Spotify, YouTube, VLC …), wie die Tasten einer Multimedia-Tastatur. + action: play_pause (Wiedergabe/Pause umschalten) | next (nächster Titel) | + prev (voriger Titel) | stop.""" + result = _pc("/media", {"action": action}) + if "error" in result: + return f"FEHLER: {result['error']}" + return f"Medien-Aktion '{action}' ausgeführt." if result.get("ok") else str(result) + + +@mcp.tool() +def pc_volume(action: str, steps: int = 5) -> str: + """Ändert die System-Lautstärke des Windows-PCs. + action: up (lauter) | down (leiser) | mute (Stumm umschalten). + steps = Stärke 1–25 (je Schritt ≈ 2 %); 5 ≈ 10 % — für „etwas lauter/leiser" passt der Default, + für „viel" nimm 10–15.""" + result = _pc("/volume", {"action": action, "steps": steps}) + if "error" in result: + return f"FEHLER: {result['error']}" + return f"Lautstärke: {action} (x{result.get('steps', steps)})." if result.get("ok") else str(result) + + @mcp.tool() def pc_open(target: str) -> str: """Öffnet eine URL im Browser oder eine Datei/Programm auf dem Windows-PC.