some changes
This commit is contained in:
parent
bb5ce8e762
commit
e2a1b93f60
5 changed files with 45 additions and 200 deletions
|
|
@ -13,4 +13,4 @@ TELEGRAM_ALLOWED_USERS=
|
||||||
TELEGRAM_HOME_CHANNEL=
|
TELEGRAM_HOME_CHANNEL=
|
||||||
|
|
||||||
BROWSER_URL=http://browser:9222
|
BROWSER_URL=http://browser:9222
|
||||||
BROWSER_VIEW_URL=
|
BROWSER_VIEW_URL=http://localhost:6080
|
||||||
18
READ.md
18
READ.md
|
|
@ -6,30 +6,16 @@ git clone https://git.lambda.coredump.ru/APEX/BrowserUse_and_ComputerUse_skills.
|
||||||
git switch feature/telegram-browser-integration
|
git switch feature/telegram-browser-integration
|
||||||
touch .env
|
touch .env
|
||||||
```
|
```
|
||||||
|
|
||||||
В создавшемся .env файле заполните переменные в соответствии с шаблоном, расположенном в .env.example
|
В создавшемся .env файле заполните переменные в соответствии с шаблоном, расположенном в .env.example
|
||||||
BROWSER_VIEW_URL заполняется после запуска
|
BROWSER_VIEW_URL заполняется после запуска
|
||||||
|
|
||||||
#### Запуск удаленно
|
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
docker compose --profile remote up --build
|
docker compose up -d --build
|
||||||
docker compose logs tunnel
|
docker compose logs tunnel
|
||||||
```
|
```
|
||||||
После команды логов листаешь терминал и ищешь ссылку https в рамке. Её вписываешь в переменную BROWSER_VIEW_URL.
|
После команды логов листаешь терминал и ищешь ссылку https в рамке. Её вписываешь в переменную BROWSER_VIEW_URL.
|
||||||
Чтобы увидеть действия агента, переходишь по данной ссылке и выбираешь vnc.html.
|
Чтобы увидеть действия агента, переходишь по данной сслыке и выбираешь vnc.html.
|
||||||
Далее в мессенджере просишь агента сделать что-то через tool browser-use.
|
Далее в мессенджере просишь агента сделать что-то через tool browser-use.
|
||||||
Возможно придётся перезапустить контейнеры, но при перезапуске контейнеров меняется ссылка.
|
Возможно придётся перезапустить контейнеры, но при перезапуске контейнеров меняется ссылка.
|
||||||
|
|
||||||
#### Запуск локально
|
|
||||||
|
|
||||||
BROWSER_VIEW_URL устанавливается как http://localhost:6080
|
|
||||||
|
|
||||||
```commandline
|
|
||||||
docker compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
```commandline
|
```commandline
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
|
||||||
|
|
@ -1,191 +1,41 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
set -Eeuo pipefail
|
|
||||||
|
|
||||||
export DISPLAY="${DISPLAY:-:99}"
|
export DISPLAY=:99
|
||||||
DISPLAY_NUM="${DISPLAY#:}"
|
|
||||||
XVFB_LOG="/tmp/xvfb.log"
|
|
||||||
|
|
||||||
VNC_PORT="${VNC_PORT:-5900}"
|
mkdir -p /var/run/dbus
|
||||||
NOVNC_PORT="${NOVNC_PORT:-6080}"
|
dbus-uuidgen > /var/lib/dbus/machine-id
|
||||||
CHROME_LOCAL_DEBUG_PORT="${CHROME_LOCAL_DEBUG_PORT:-9223}"
|
dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address &
|
||||||
CHROME_PUBLIC_DEBUG_PORT="${CHROME_PUBLIC_DEBUG_PORT:-9222}"
|
|
||||||
CHROME_PROFILE_DIR="${CHROME_PROFILE_DIR:-/src/browser_data}"
|
|
||||||
|
|
||||||
MAX_RESTARTS="${MAX_RESTARTS:-10}"
|
Xvfb :99 -screen 0 1280x720x16 -ac +extension GLX +render -noreset &
|
||||||
RESTART_WINDOW_SEC="${RESTART_WINDOW_SEC:-60}"
|
sleep 2
|
||||||
RESTART_BACKOFF_SEC="${RESTART_BACKOFF_SEC:-2}"
|
|
||||||
|
|
||||||
PIDS=()
|
fluxbox &
|
||||||
STOPPING=0
|
x11vnc -display :99 -nopw -listen 0.0.0.0 -xkb -forever -shared &
|
||||||
WINDOW_START="$(date +%s)"
|
websockify --web=/usr/share/novnc/ 6080 localhost:5900 &
|
||||||
RESTART_COUNT=0
|
|
||||||
|
|
||||||
log() {
|
socat TCP-LISTEN:9222,fork,reuseaddr TCP:127.0.0.1:9223 &
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
start_bg() {
|
echo "--- Запуск Chromium в режиме Local-Only (Port 9223) ---"
|
||||||
"$@" &
|
|
||||||
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/tcp/${host}/${port}" >/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})"
|
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
for pid in "${PIDS[@]}"; do
|
rm -f /src/browser_data/SingletonLock
|
||||||
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})"
|
|
||||||
chromium \
|
chromium \
|
||||||
--no-sandbox \
|
--no-sandbox \
|
||||||
--disable-dev-shm-usage \
|
--disable-dev-shm-usage \
|
||||||
--ozone-platform=x11 \
|
--remote-debugging-port=9223 \
|
||||||
--remote-debugging-port="${CHROME_LOCAL_DEBUG_PORT}" \
|
|
||||||
--remote-debugging-address=127.0.0.1 \
|
--remote-debugging-address=127.0.0.1 \
|
||||||
--remote-allow-origins='*' \
|
--remote-allow-origins=* \
|
||||||
--window-size=1280,720 \
|
--window-size=1280,720 \
|
||||||
--user-data-dir="${CHROME_PROFILE_DIR}" \
|
--user-data-dir=/src/browser_data \
|
||||||
--disable-blink-features=AutomationControlled \
|
--disable-blink-features=AutomationControlled \
|
||||||
--no-first-run \
|
--no-first-run \
|
||||||
--disable-gpu \
|
--disable-gpu \
|
||||||
--mute-audio \
|
--mute-audio \
|
||||||
--no-default-browser-check \
|
--no-default-browser-check \
|
||||||
--disable-software-rasterizer \
|
--disable-software-rasterizer \
|
||||||
--disable-features=site-per-process \
|
--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
|
|
||||||
|
|
||||||
|
echo "Chromium упал или был закрыт агентом, рестарт через 2 секунды..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
@ -4,6 +4,10 @@ services:
|
||||||
context: ./hermes_code
|
context: ./hermes_code
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: hermes-brain
|
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_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|
@ -20,6 +24,12 @@ services:
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: true
|
tty: true
|
||||||
restart: always
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pgrep -f 'python -m gateway.run' || exit 1"]
|
||||||
|
interval: 2m
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 1m
|
||||||
networks:
|
networks:
|
||||||
- hermes-net
|
- hermes-net
|
||||||
deploy:
|
deploy:
|
||||||
|
|
@ -52,16 +62,14 @@ services:
|
||||||
- browser_profiles:/src/browser_data
|
- browser_profiles:/src/browser_data
|
||||||
restart: always
|
restart: always
|
||||||
healthcheck:
|
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
|
interval: 10s
|
||||||
timeout: 3s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 5
|
||||||
start_period: 20s
|
start_period: 10s
|
||||||
|
|
||||||
tunnel:
|
tunnel:
|
||||||
image: cloudflare/cloudflared:latest
|
image: cloudflare/cloudflared:latest
|
||||||
profiles:
|
|
||||||
- remote
|
|
||||||
container_name: hermes-tunnel
|
container_name: hermes-tunnel
|
||||||
restart: always
|
restart: always
|
||||||
command: tunnel --protocol http2 --url http://browser:6080 --no-tls-verify
|
command: tunnel --protocol http2 --url http://browser:6080 --no-tls-verify
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,15 @@ async def run_browser_task(task):
|
||||||
cdp_url = f"http://{browser_host}:{browser_port}"
|
cdp_url = f"http://{browser_host}:{browser_port}"
|
||||||
|
|
||||||
browser = Browser(cdp_url=cdp_url)
|
browser = Browser(cdp_url=cdp_url)
|
||||||
|
|
||||||
|
# Для подключения к Chrome на виртуальной машине раскомментируй
|
||||||
# browser = Browser(
|
# browser = Browser(
|
||||||
# config=BrowserConfig(
|
# executable_path="/usr/bin/google-chrome", # Linux
|
||||||
# chrome_instance_path="/usr/bin/google-chrome", # путь к Chrome на ВМ
|
# # Windows: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
|
||||||
# # Для Windows: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
|
# # macOS: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||||
# # Для macOS: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
||||||
# )
|
|
||||||
# )
|
# )
|
||||||
# для хрома на вирутальной машине
|
# или
|
||||||
|
# browser = Browser.from_system_chrome() для автоопределения
|
||||||
|
|
||||||
llm = ChatOpenAI(
|
llm = ChatOpenAI(
|
||||||
model=os.getenv("MODEL_DEFAULT", "qwen3.5-122b"),
|
model=os.getenv("MODEL_DEFAULT", "qwen3.5-122b"),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue