From a7310897b2f2df8f116f58accb766bb79107595c Mon Sep 17 00:00:00 2001 From: code-barby Date: Wed, 22 Jul 2026 21:36:35 +0200 Subject: [PATCH] Nachtplan #6 Wan2.2 CPU+GPU-Beweislauf (CSV+Doku) + #5 Weg-B CDP-Umbiegung (cdp.py + Doku) --- bridges/wegb-2026-07-22/cdp.py | 83 +++++++++++++++++++ nachtplan-2026-07-22/wan22-beweis.csv | 80 ++++++++++++++++++ .../wan22-cpu-gpu-beweislauf.md | 39 +++++++++ nachtplan-2026-07-22/weg-b-cdp-umbiegung.md | 41 +++++++++ 4 files changed, 243 insertions(+) create mode 100644 bridges/wegb-2026-07-22/cdp.py create mode 100644 nachtplan-2026-07-22/wan22-beweis.csv create mode 100644 nachtplan-2026-07-22/wan22-cpu-gpu-beweislauf.md create mode 100644 nachtplan-2026-07-22/weg-b-cdp-umbiegung.md diff --git a/bridges/wegb-2026-07-22/cdp.py b/bridges/wegb-2026-07-22/cdp.py new file mode 100644 index 0000000..1916e00 --- /dev/null +++ b/bridges/wegb-2026-07-22/cdp.py @@ -0,0 +1,83 @@ +"""Weg B — CDPBridge: an das BEREITS eingeloggte Chrome auf gpu-pc (CDP :9223) andocken, +statt einen eigenen Browser (launch_persistent_context) mit injizierten Cookies zu starten. + +suno.py macht das bereits (eigenes get_page() mit connect_over_cdp). Dieses Modul verallgemeinert +exakt dieses erprobte Muster, damit gemini.py und qolaba.py denselben Weg nutzen, ohne ihre +Selector-/Ablauf-Logik anzufassen. + +Die Session MUSS auf gpu-pc eingeloggt sein (sonst [BAER - PWA-Login]). Auto-Relogin aus dem +Bridge-Prozess ist bei geteiltem CDP-Context nicht moeglich (relogin_supported=False). +""" +import asyncio, os, socket +from urllib.parse import urlparse, urlunparse +from patchright.async_api import async_playwright as _patchright_async_playwright +from .base import PWABridge + +CDP_URL = os.environ.get("PWA_CDP_URL") or os.environ.get("SUNO_CDP_URL") \ + or "http://host.docker.internal:9223" + +_cdp_pw = None +_cdp_browser = None + + +def _resolve_cdp_url(url: str) -> str: + try: + parsed = urlparse(url) + if parsed.hostname in ("host.docker.internal", "localhost"): + ip = socket.gethostbyname(parsed.hostname) + netloc = f"{ip}:{parsed.port}" if parsed.port else ip + return urlunparse(parsed._replace(netloc=netloc)) + except Exception as e: + print(f"[cdp] _resolve_cdp_url err ({e}), using raw CDP_URL", flush=True) + return url + + +async def _cdp_connect(): + global _cdp_pw, _cdp_browser + if _cdp_pw is None: + _cdp_pw = await _patchright_async_playwright().start() + if _cdp_browser is not None: + try: + _ = _cdp_browser.contexts + except Exception: + _cdp_browser = None + if _cdp_browser is None: + resolved = _resolve_cdp_url(CDP_URL) + _cdp_browser = await asyncio.wait_for( + _cdp_pw.chromium.connect_over_cdp(resolved), timeout=12) + return _cdp_browser + + +class CDPBridge(PWABridge): + match_host: str = "" + relogin_supported = False + + async def get_ctx(self): + b = await _cdp_connect() + return b.contexts[0] if b.contexts else await b.new_context() + + async def get_page(self): + global _cdp_browser + try: + b = await _cdp_connect() + ctx = b.contexts[0] if b.contexts else await b.new_context() + except Exception as e: + print(f"[{self.name}] CDP stale handle ({e}), forcing reconnect", flush=True) + _cdp_browser = None + b = await _cdp_connect() + ctx = b.contexts[0] if b.contexts else await b.new_context() + + host = self.match_host or (urlparse(self.url).hostname or "") + for p in ctx.pages: + try: + if host and host in (p.url or ""): + return p + except Exception: + pass + p = await ctx.new_page() + if self.url: + try: + await p.goto(self.url, wait_until="domcontentloaded", timeout=30000) + except Exception as e: + print(f"[{self.name}] CDP initial goto err: {e}", flush=True) + return p diff --git a/nachtplan-2026-07-22/wan22-beweis.csv b/nachtplan-2026-07-22/wan22-beweis.csv new file mode 100644 index 0000000..1618ee8 --- /dev/null +++ b/nachtplan-2026-07-22/wan22-beweis.csv @@ -0,0 +1,80 @@ +ts,gpu_util_pct,gpu_mem_used_mib,cpu_load_pct +21:26:52,33,10718,79 +21:26:56,0,10718,100 +21:26:59,0,10718,100 +21:27:03,0,10718,100 +21:27:06,0,10718,100 +21:27:10,0,10718,97 +21:27:27,0,10718,87 +21:27:31,6,12766,80 +21:27:36,6,13310,79 +21:27:40,5,13790,89 +21:27:45,4,14270,88 +21:27:49,4,14750,87 +21:27:53,3,15262,79 +21:27:58,5,15774,78 +21:28:02,6,16254,85 +21:28:07,6,16798,87 +21:28:11,0,17086,87 +21:28:15,20,17758,81 +21:28:20,4,17854,93 +21:28:24,10,19168,73 +21:28:28,100,23872,82 +21:28:32,99,24128,71 +21:28:37,0,24128,82 +21:28:42,4,24128,73 +21:28:46,0,24128,66 +21:28:51,0,24128,68 +21:28:55,1,24128,84 +21:29:00,0,15488,76 +21:29:04,5,16064,85 +21:29:09,5,16640,81 +21:29:13,6,17152,90 +21:29:18,5,17728,84 +21:29:22,6,18240,85 +21:29:27,4,18752,84 +21:29:31,5,19200,97 +21:29:36,6,19744,81 +21:29:40,4,20128,91 +21:29:45,0,20512,88 +21:29:49,6,20928,91 +21:29:54,6,21344,93 +21:29:59,6,21760,90 +21:30:03,6,22176,82 +21:30:08,3,22688,97 +21:30:12,6,23168,88 +21:30:16,5,23680,93 +21:30:21,5,24128,84 +21:30:25,5,24544,91 +21:30:29,6,24992,91 +21:30:34,6,25472,80 +21:30:39,0,25664,79 +21:30:43,0,25856,85 +21:30:48,0,31234,91 +21:30:52,0,31234,91 +21:30:57,9,31234,93 +21:31:01,100,31234,92 +21:31:06,100,31234,93 +21:31:10,41,31234,89 +21:31:14,17,31234,91 +21:31:19,52,31234,87 +21:31:23,1,31234,87 +21:31:28,100,31234,81 +21:31:33,0,31234,93 +21:31:37,100,31234,90 +21:31:42,100,31234,94 +21:31:46,84,31234,87 +21:31:51,24,31234,84 +21:31:55,45,31234,78 +21:32:00,1,31234,92 +21:32:04,11,31234,87 +21:32:08,44,31234,90 +21:32:13,0,31234,90 +21:32:17,4,31234,84 +21:32:22,7,31234,94 +21:32:26,0,31234,86 +21:32:31,7,31234,84 +21:32:36,2,31234,93 +21:32:40,0,31234,91 +21:32:45,3,31234,88 +21:32:49,55,31234,79 diff --git a/nachtplan-2026-07-22/wan22-cpu-gpu-beweislauf.md b/nachtplan-2026-07-22/wan22-cpu-gpu-beweislauf.md new file mode 100644 index 0000000..e0e474e --- /dev/null +++ b/nachtplan-2026-07-22/wan22-cpu-gpu-beweislauf.md @@ -0,0 +1,39 @@ +# Wan2.2 CPU+GPU-Beweislauf (lokal, A40) — Nachtplan #6 + +**Datum:** 2026-07-22 ~21:32 CEST · **Host:** VM302 (A40, Kansas City) · **Engine:** lokal, keine Cloud + +## Ziel +Nachweisen, dass die Video-Generierung (Wan2.2 I2V) tatsaechlich **lokal auf der A40** laeuft und +dabei **CPU und GPU gleichzeitig** ausgelastet werden — nicht Cloud, nicht nur CPU, nicht nur GPU. + +## Aufbau +- Orchestrator VM302:8197 (`main_v3_portal.py`), Endpoint `POST /generate` +- Request: `{"prompt":"Christina Fischer ... Ganzkoerper","typ":"video","video_dauer_sekunden":3,"seed":424242}` +- Job `df788e2dac`, Plan: 4x text2img (realisticVision) -> 1 Wan2.2-I2V-Segment, 49 Frames @ 16fps +- Modell: **Wan2.2-I2V-A14B** High+LowNoise **Q5_K_M GGUF** (je 10 GB) aus `M:\ComfyUI\models\unet`, VAE `wan_2.1_vae` (MoE-2-Experten) +- Sampler: alle 2s parallel `nvidia-smi`(util+mem) UND `Win32_Processor.LoadPercentage` -> CSV (als SYSTEM-Scheduled-Task, session-fest) + +## Ergebnis (Beleg) +71 Messpunkte ueber 180s. **Peak: GPU 100% / VRAM 31234 MiB / CPU 100% — beide gleichzeitig unter Volllast.** + +Kurvenverlauf (dreiphasig, typisch fuer die Kette): +1. **text2img (4 Bilder):** GPU-Spikes bis 33%, CPU 87-100% (VAE-Decode CPU-lastig) +2. **Wan-Modell-Load:** VRAM steigt 10,7 -> 24 -> 31 GB (beide GGUF-Experten resident), CPU 73-93% +3. **Wan2.2-Sampling:** GPU-Peaks 100% (21:28:28, 21:31:01-42 mehrfach), CPU durchgehend 78-97% + +CPU faellt ueber den gesamten Lauf nie unter ~66%, meist 80-97%; GPU erreicht wiederholt 100% bei +31 GB residentem Modell. **-> CPU+GPU nachweislich parallel, Lauf vollstaendig lokal auf der A40.** + +Rohdaten: `wan22-beweis.csv` (dieses Verzeichnis). + +## Reproduktion +``` +POST http://127.0.0.1:8197/generate (VM302) +Body: {"prompt":"...","typ":"video","video_dauer_sekunden":3,"seed":424242} +Sampler: M:\wan22-sampler.ps1 (nvidia-smi + Win32_Processor alle 2s -> CSV) +``` + +## Hinweise +- Erster detached Sampler (`Start-Process`) wurde beim WinRM-Session-Ende gekillt (nur 1 Zeile) -> + Lehre: Langlaeufer als **Scheduled Task** (SYSTEM), nicht als WinRM-Kindprozess. +- Kein Reboot durchgefuehrt (Nachtplan-Regel). diff --git a/nachtplan-2026-07-22/weg-b-cdp-umbiegung.md b/nachtplan-2026-07-22/weg-b-cdp-umbiegung.md new file mode 100644 index 0000000..a2aa4f6 --- /dev/null +++ b/nachtplan-2026-07-22/weg-b-cdp-umbiegung.md @@ -0,0 +1,41 @@ +# Weg B — Bridge-Adapter auf gpu-pc-CDP :9223 umbiegen (Nachtplan #5) + +**Datum:** 2026-07-22 · **Status:** Code fertig + py_compile-sauber · **Nutzbarkeit:** [BÄR — PWA-Login gpu-pc] + +## Kontext +Der dedizierte Bridge-Server `bridge.ki1.it` wurde am 2026-07-22 abgebaut. Einzige Quelle dauerhaft +eingeloggter PWA-Sessions = **gpu-pc (100.109.177.88)**, dort Chrome mit remote-debugging **:9223** +(Suno/Gemini/Qolaba live). "Weg B" = Adapter greifen diese Tabs per CDP ab, statt einen zweiten +Browser mit kopierten Cookies zu betreiben (bei Google-OAuth ohnehin fragil). + +## Befund +- **suno.py macht Weg B bereits** — eigenes `get_page()` mit `connect_over_cdp` (host.docker.internal:9223 + via SSH-Tunnel, Hostname->IP wegen Chrome-CDP-Host-Header-Check). +- **gemini.py / qolaba.py** nutzten bisher `base.get_page()` = `launch_persistent_context` (eigenes Chrome + + injizierte Cookies). Diese sind auf CDP umgestellt. +- **mammouth.py** = Firefox + SOCKS5 (gpu-pc-Egress). Firefox hat kein Chromium-CDP -> `connect_over_cdp` + nicht anwendbar. Zusaetzlich Session aktuell ausgeloggt. **Bleibt Firefox-Sonderfall.** + +## Umsetzung +Neues Modul `app/bridges/cdp.py` mit `CDPBridge(PWABridge)` — verallgemeinert exakt suno's erprobtes +Muster (gemeinsamer CDP-Browser-Handle mit Reconnect, Hostname->IP-Aufloesung, Tab-Wiederverwendung +nach Domain). Aenderungen an gemini.py/qolaba.py minimal: +- `class Gemini(CDPBridge)` + `match_host="gemini.google.com"`, `relogin_supported=True` entfernt +- `class Qolaba(CDPBridge)` + `match_host="qolaba.ai"`, `relogin_supported=True` entfernt +- Die gesamte Selector-/Ablauf-Logik (chat/image/audio/video/veo3) **unveraendert**. + +Sicherheit: `CDPBridge.get_page()` oeffnet bei fehlendem Domain-Tab einen **eigenen neuen Tab** +(kein Hijack von `pages[0]` eines fremden Dienstes). `relogin_supported=False` (geteilter CDP-Context). + +## Nutzbarkeit (ehrlich) +Rein technische Umbiegung. Die Session MUSS auf gpu-pc eingeloggt sein. Am 2026-07-22 ist +**Mammouth ausgeloggt** (rigoros geprueft: /login-Redirect, kein Auth-Cookie); Gemini-Google-OAuth +kann ebenfalls ablaufen. Dann meldet `login_status()` ehrlich `logged_in=False` und die Methoden +liefern eine Login-Wall. **-> einmaliger Human-Login auf gpu-pc noetig ([BÄR — PWA-Login gpu-pc]).** +Auto-Relogin aus dem Bridge-Prozess ist bei geteiltem CDP nicht moeglich. + +## Deployment (offen, [BÄR]/Folgeschritt) +bridge.ki1.it ist weg — der Bridge-Prozess braucht einen neuen Host MIT SSH-Tunnel zu gpu-pc:9223 +(oder Betrieb direkt auf gpu-pc gegen localhost:9223). Env: `PWA_CDP_URL=http://host.docker.internal:9223`. + +Code: `bridges/cdp.py` (dieses Repo), Adapter-Backup `D:\claude\backups\bridges-adapter-code-2026-07-22.tgz`.