From e2a1b93f604b1109fabac14e05c8f703c53348ff Mon Sep 17 00:00:00 2001 From: Skyber_2 Date: Sat, 4 Apr 2026 13:41:01 +0300 Subject: [PATCH] some changes --- .env.example | 2 +- READ.md | 18 +-- browser_env/entrypoint.sh | 192 +++----------------------- docker-compose.yml | 20 ++- hermes_code/tools/browser_use_tool.py | 13 +- 5 files changed, 45 insertions(+), 200 deletions(-) diff --git a/.env.example b/.env.example index 30e3b386..e0dc121a 100644 --- a/.env.example +++ b/.env.example @@ -13,4 +13,4 @@ TELEGRAM_ALLOWED_USERS= TELEGRAM_HOME_CHANNEL= BROWSER_URL=http://browser:9222 -BROWSER_VIEW_URL= \ No newline at end of file +BROWSER_VIEW_URL=http://localhost:6080 \ No newline at end of file diff --git a/READ.md b/READ.md index 3eb1421c..41abd358 100644 --- a/READ.md +++ b/READ.md @@ -6,30 +6,16 @@ git clone https://git.lambda.coredump.ru/APEX/BrowserUse_and_ComputerUse_skills. git switch feature/telegram-browser-integration touch .env ``` - В создавшемся .env файле заполните переменные в соответствии с шаблоном, расположенном в .env.example BROWSER_VIEW_URL заполняется после запуска - -#### Запуск удаленно - ```commandline -docker compose --profile remote up --build +docker compose up -d --build docker compose logs tunnel ``` После команды логов листаешь терминал и ищешь ссылку https в рамке. Её вписываешь в переменную BROWSER_VIEW_URL. -Чтобы увидеть действия агента, переходишь по данной ссылке и выбираешь vnc.html. +Чтобы увидеть действия агента, переходишь по данной сслыке и выбираешь vnc.html. Далее в мессенджере просишь агента сделать что-то через tool browser-use. Возможно придётся перезапустить контейнеры, но при перезапуске контейнеров меняется ссылка. - -#### Запуск локально - -BROWSER_VIEW_URL устанавливается как http://localhost:6080 - -```commandline -docker compose up -``` - ---- ```commandline docker compose down docker compose up -d diff --git a/browser_env/entrypoint.sh b/browser_env/entrypoint.sh index e35c57da..6d88936b 100644 --- a/browser_env/entrypoint.sh +++ b/browser_env/entrypoint.sh @@ -1,191 +1,41 @@ -#!/usr/bin/env bash -set -Eeuo pipefail +#!/bin/bash -export DISPLAY="${DISPLAY:-:99}" -DISPLAY_NUM="${DISPLAY#:}" -XVFB_LOG="/tmp/xvfb.log" +export DISPLAY=:99 -VNC_PORT="${VNC_PORT:-5900}" -NOVNC_PORT="${NOVNC_PORT:-6080}" -CHROME_LOCAL_DEBUG_PORT="${CHROME_LOCAL_DEBUG_PORT:-9223}" -CHROME_PUBLIC_DEBUG_PORT="${CHROME_PUBLIC_DEBUG_PORT:-9222}" -CHROME_PROFILE_DIR="${CHROME_PROFILE_DIR:-/src/browser_data}" +mkdir -p /var/run/dbus +dbus-uuidgen > /var/lib/dbus/machine-id +dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address & -MAX_RESTARTS="${MAX_RESTARTS:-10}" -RESTART_WINDOW_SEC="${RESTART_WINDOW_SEC:-60}" -RESTART_BACKOFF_SEC="${RESTART_BACKOFF_SEC:-2}" +Xvfb :99 -screen 0 1280x720x16 -ac +extension GLX +render -noreset & +sleep 2 -PIDS=() -STOPPING=0 -WINDOW_START="$(date +%s)" -RESTART_COUNT=0 +fluxbox & +x11vnc -display :99 -nopw -listen 0.0.0.0 -xkb -forever -shared & +websockify --web=/usr/share/novnc/ 6080 localhost:5900 & -log() { - printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" -} +socat TCP-LISTEN:9222,fork,reuseaddr TCP:127.0.0.1:9223 & -start_bg() { - "$@" & - local pid=$! - PIDS+=("$pid") - log "started: $* (pid=$pid)" -} - -wait_for_port() { - local host=$1 - local port=$2 - local timeout_sec=$3 - local end_ts=$(( $(date +%s) + timeout_sec )) - - while [ "$(date +%s)" -lt "$end_ts" ]; do - if bash -c "/dev/null 2>&1; then - return 0 - fi - sleep 0.2 - done - return 1 -} - -wait_for_x_display() { - local timeout_sec=$1 - local end_ts=$(( $(date +%s) + timeout_sec )) - - while [ "$(date +%s)" -lt "$end_ts" ]; do - if [ -S "/tmp/.X11-unix/X${DISPLAY_NUM}" ] && DISPLAY="$DISPLAY" bash -c 'echo >/dev/null' >/dev/null 2>&1; then - return 0 - fi - sleep 0.2 - done - return 1 -} - -cleanup() { - if [ "$STOPPING" -eq 1 ]; then - return - fi - STOPPING=1 - - log "shutdown signal received, stopping processes..." - - if [ -n "${CHROME_PID:-}" ] && kill -0 "$CHROME_PID" >/dev/null 2>&1; then - kill "$CHROME_PID" >/dev/null 2>&1 || true - fi - - for pid in "${PIDS[@]:-}"; do - kill "$pid" >/dev/null 2>&1 || true - done - - sleep 1 - - if [ -n "${CHROME_PID:-}" ] && kill -0 "$CHROME_PID" >/dev/null 2>&1; then - kill -9 "$CHROME_PID" >/dev/null 2>&1 || true - fi - - for pid in "${PIDS[@]:-}"; do - if kill -0 "$pid" >/dev/null 2>&1; then - kill -9 "$pid" >/dev/null 2>&1 || true - fi - done - - log "shutdown complete" -} - -trap cleanup SIGTERM SIGINT EXIT - -mkdir -p /var/run/dbus /var/lib/dbus "$CHROME_PROFILE_DIR" -if [ ! -f /var/lib/dbus/machine-id ]; then - dbus-uuidgen > /var/lib/dbus/machine-id 2>/dev/null || true -fi - -# Удаляем stale lock/socket от прошлых падений Xvfb на том же DISPLAY. -rm -f "/tmp/.X${DISPLAY_NUM}-lock" "/tmp/.X11-unix/X${DISPLAY_NUM}" || true - -log "starting X stack on DISPLAY=${DISPLAY}" -Xvfb "$DISPLAY" -screen 0 1280x720x24 -ac +extension GLX +render -noreset >"$XVFB_LOG" 2>&1 & -XVFB_PID=$! -PIDS+=("$XVFB_PID") -log "started: Xvfb $DISPLAY (pid=$XVFB_PID)" - -if ! wait_for_x_display 15; then - log "fatal: Xvfb did not initialize DISPLAY=${DISPLAY}" - if [ -f "$XVFB_LOG" ]; then - log "xvfb log tail:" - tail -n 40 "$XVFB_LOG" || true - fi - exit 1 -fi - -start_bg fluxbox -start_bg x11vnc -display "$DISPLAY" -rfbport "$VNC_PORT" -nopw -listen 0.0.0.0 -xkb -forever -shared -start_bg websockify --web=/usr/share/novnc/ "$NOVNC_PORT" "localhost:${VNC_PORT}" -start_bg socat "TCP-LISTEN:${CHROME_PUBLIC_DEBUG_PORT},fork,reuseaddr" "TCP:127.0.0.1:${CHROME_LOCAL_DEBUG_PORT}" - -if ! wait_for_port 127.0.0.1 "$VNC_PORT" 20; then - log "fatal: x11vnc did not open port ${VNC_PORT}" - exit 1 -fi -if ! wait_for_port 127.0.0.1 "$NOVNC_PORT" 20; then - log "fatal: websockify did not open port ${NOVNC_PORT}" - exit 1 -fi - -log "browser infrastructure is ready (noVNC:${NOVNC_PORT}, DevTools proxy:${CHROME_PUBLIC_DEBUG_PORT})" +echo "--- Запуск Chromium в режиме Local-Only (Port 9223) ---" while true; do - for pid in "${PIDS[@]}"; do - if ! kill -0 "$pid" >/dev/null 2>&1; then - log "fatal: required background process died (pid=${pid})" - exit 1 - fi - done - - rm -f "${CHROME_PROFILE_DIR}/SingletonLock" "${CHROME_PROFILE_DIR}/SingletonCookie" "${CHROME_PROFILE_DIR}/SingletonSocket" 2>/dev/null || true - - log "starting Chromium (local DevTools:${CHROME_LOCAL_DEBUG_PORT})" + rm -f /src/browser_data/SingletonLock + chromium \ --no-sandbox \ --disable-dev-shm-usage \ - --ozone-platform=x11 \ - --remote-debugging-port="${CHROME_LOCAL_DEBUG_PORT}" \ + --remote-debugging-port=9223 \ --remote-debugging-address=127.0.0.1 \ - --remote-allow-origins='*' \ + --remote-allow-origins=* \ --window-size=1280,720 \ - --user-data-dir="${CHROME_PROFILE_DIR}" \ + --user-data-dir=/src/browser_data \ --disable-blink-features=AutomationControlled \ --no-first-run \ --disable-gpu \ --mute-audio \ --no-default-browser-check \ --disable-software-rasterizer \ - --disable-features=site-per-process \ - --disable-crash-reporter \ - --disable-extensions \ - --disable-sync & - - CHROME_PID=$! - wait "$CHROME_PID" || CHROME_EXIT=$? - CHROME_EXIT=${CHROME_EXIT:-0} - - if [ "$STOPPING" -eq 1 ]; then - break - fi - - now="$(date +%s)" - if [ $(( now - WINDOW_START )) -gt "$RESTART_WINDOW_SEC" ]; then - WINDOW_START="$now" - RESTART_COUNT=0 - fi - - RESTART_COUNT=$((RESTART_COUNT + 1)) - log "Chromium exited with code=${CHROME_EXIT}; restart ${RESTART_COUNT}/${MAX_RESTARTS} in current window" - - if [ "$RESTART_COUNT" -ge "$MAX_RESTARTS" ]; then - log "fatal: too many Chromium restarts in ${RESTART_WINDOW_SEC}s" - exit 1 - fi - - sleep "$RESTART_BACKOFF_SEC" - unset CHROME_EXIT - unset CHROME_PID -done + --disable-features=site-per-process + echo "Chromium упал или был закрыт агентом, рестарт через 2 секунды..." + sleep 2 +done \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e64e93bb..d2cdd82f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,10 @@ services: context: ./hermes_code dockerfile: Dockerfile container_name: hermes-brain + sysctls: + - net.ipv4.tcp_keepalive_time=60 + - net.ipv4.tcp_keepalive_intvl=10 + - net.ipv4.tcp_keepalive_probes=3 env_file: - .env environment: @@ -20,6 +24,12 @@ services: stdin_open: true tty: true restart: always + healthcheck: + test: ["CMD-SHELL", "pgrep -f 'python -m gateway.run' || exit 1"] + interval: 2m + timeout: 10s + retries: 3 + start_period: 1m networks: - hermes-net deploy: @@ -52,16 +62,14 @@ services: - browser_profiles:/src/browser_data restart: always healthcheck: - test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:9222/json/version >/dev/null || exit 1"] + test: ["CMD", "curl", "-f", "http://localhost:9222/json/version"] interval: 10s - timeout: 3s - retries: 12 - start_period: 20s + timeout: 5s + retries: 5 + start_period: 10s tunnel: image: cloudflare/cloudflared:latest - profiles: - - remote container_name: hermes-tunnel restart: always command: tunnel --protocol http2 --url http://browser:6080 --no-tls-verify diff --git a/hermes_code/tools/browser_use_tool.py b/hermes_code/tools/browser_use_tool.py index cb886cd0..32043ea9 100644 --- a/hermes_code/tools/browser_use_tool.py +++ b/hermes_code/tools/browser_use_tool.py @@ -18,14 +18,15 @@ async def run_browser_task(task): cdp_url = f"http://{browser_host}:{browser_port}" browser = Browser(cdp_url=cdp_url) + + # Для подключения к Chrome на виртуальной машине раскомментируй # browser = Browser( - # config=BrowserConfig( - # chrome_instance_path="/usr/bin/google-chrome", # путь к Chrome на ВМ - # # Для Windows: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" - # # Для macOS: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" - # ) + # executable_path="/usr/bin/google-chrome", # Linux + # # Windows: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" + # # macOS: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" # ) - # для хрома на вирутальной машине + # или + # browser = Browser.from_system_chrome() для автоопределения llm = ChatOpenAI( model=os.getenv("MODEL_DEFAULT", "qwen3.5-122b"),