hermes-hub/scripts/capture_live_a21_screenshots.py

111 lines
4 KiB
Python

"""
Hermes Hub — Task A21 Screenshot Capture Script
Captures high-resolution (1440x920) screenshots for all 4 new screens:
1. Analytics (Аналитика)
2. Health / Readiness (Состояние)
3. Logs (Журнал событий)
4. Settings (Настройки)
"""
from __future__ import annotations
import os
from pathlib import Path
import socket
import subprocess
import sys
import threading
import time
REPO_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO_ROOT / "src"))
import uvicorn
from antigravity_provider.router.web.server import app
from antigravity_provider.router.unified_health import EventLogService
ARTIFACTS_DIR = REPO_ROOT / "artifacts" / "a21-screenshots"
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
CHROME_PATHS = [
r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
r"C:\Program Files\Google\Chrome\Application\chrome.exe",
r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
r"C:\Program Files\Microsoft\Edge\Application\msedge.exe",
]
def get_free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(("127.0.0.1", 0))
return s.getsockname()[1]
def seed_event_logs():
svc = EventLogService.get()
svc.log("system", "Hermes Hub запущен в нативном режиме Windows.", level="info")
svc.log("account", "Обновлены квоты для 22 аккаунтов (Antigravity, Codex, Grok, Claude, OpenCode).", level="info")
svc.log("routing", "Основной маршрут 'coder-primary' переключен на ag-w1.", level="info")
svc.log("quota", "Превышен лимит запросов для резервного профиля codex-2.", level="warning", details="HTTP 429 Too Many Requests от OpenAI API")
svc.log("system", "Фоновая синхронизация конфигурации завершена успешно.", level="info")
svc.log("routing", "Автоматический failover: 'reviewer' переведён на claude-main.", level="warning", details="Таймаут первичного узла grok-fast")
def main():
seed_event_logs()
port = get_free_port()
config = uvicorn.Config(app, host="127.0.0.1", port=port, log_level="warning")
server = uvicorn.Server(config)
t = threading.Thread(target=server.run, daemon=True)
t.start()
time.sleep(1.0)
chrome_exe = None
for p in CHROME_PATHS:
if os.path.isfile(p):
chrome_exe = p
break
if not chrome_exe:
raise RuntimeError("No Chrome/Edge executable found")
temp_profile = REPO_ROOT / "artifacts" / "temp_chrome_profile_a21"
temp_profile.mkdir(parents=True, exist_ok=True)
scenarios = [
("01_analytics_view.png", f"http://127.0.0.1:{port}/index.html?view=analytics"),
("02_health_view.png", f"http://127.0.0.1:{port}/index.html?view=health"),
("03_logs_view.png", f"http://127.0.0.1:{port}/index.html?view=logs"),
("04_settings_view.png", f"http://127.0.0.1:{port}/index.html?view=settings"),
]
captured = 0
for filename, url in scenarios:
out_file = ARTIFACTS_DIR / filename
cmd = [
chrome_exe,
"--headless=new",
"--disable-gpu",
"--no-sandbox",
"--hide-scrollbars",
"--virtual-time-budget=2500",
f"--user-data-dir={temp_profile}",
"--window-size=1440,920",
f"--screenshot={out_file}",
url,
]
print(f"Capturing: {filename}...")
subprocess.run(cmd, capture_output=True, timeout=15)
if out_file.is_file() and out_file.stat().st_size > 1000:
print(f" [OK] Saved {out_file.name} ({out_file.stat().st_size // 1024} KB)")
captured += 1
else:
print(f" [FAIL] Could not generate {out_file.name}")
server.should_exit = True
print(f"\nCaptured {captured}/{len(scenarios)} screenshots in {ARTIFACTS_DIR}")
if __name__ == "__main__":
main()