Skip to content

Commit

Permalink
fix: return instructions to correctly playwright install if browser…
Browse files Browse the repository at this point in the history
… binaries unavailable (#358)
  • Loading branch information
ErikBjare authored Dec 20, 2024
1 parent 1fd407c commit ebf5675
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
2 changes: 1 addition & 1 deletion gptme/tools/_browser_playwright.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pathlib import Path

from playwright.sync_api import Browser, ElementHandle

from ._browser_thread import BrowserThread

_browser: BrowserThread | None = None
Expand All @@ -19,7 +20,6 @@
def get_browser() -> BrowserThread:
global _browser
if _browser is None:
logger.info("Starting browser thread")
_browser = BrowserThread()
atexit.register(_browser.stop)
return _browser
Expand Down
26 changes: 22 additions & 4 deletions gptme/tools/_browser_thread.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib
import logging
import time
from collections.abc import Callable
Expand Down Expand Up @@ -31,19 +32,35 @@ def __init__(self):
self.results: dict[object, tuple[Any, Exception | None]] = {}
self.lock = Lock()
self.ready = Event()
self._init_error: Exception | None = None
self.thread = Thread(target=self._run, daemon=True)
self.thread.start()
# Wait for browser to be ready
if not self.ready.wait(timeout=TIMEOUT):
raise TimeoutError("Browser failed to start")
logger.info("Browser thread started")
if self._init_error:
raise self._init_error

logger.debug("Browser thread started")

def _run(self):
try:
playwright = sync_playwright().start()
browser = playwright.chromium.launch()
logger.info("Browser launched")
self.ready.set()
try:
browser = playwright.chromium.launch()
logger.info("Browser launched")
except Exception as e:
if "Executable doesn't exist" in str(e):
pw_version = importlib.metadata.version("playwright")
self._init_error = RuntimeError(
f"Browser executable not found. Run: pipx run playwright=={pw_version} install chromium-headless-shell"
)
else:
self._init_error = e
self.ready.set() # Signal init complete (with error)
return

self.ready.set() # Signal successful init

while True:
try:
Expand Down Expand Up @@ -88,6 +105,7 @@ def execute(self, func: Callable[..., T], *args, **kwargs) -> T:
result, error = self.results.pop(cmd_id)
if error:
raise error
logger.info("Browser operation completed")
return result
time.sleep(0.1) # Prevent busy-waiting

Expand Down
10 changes: 8 additions & 2 deletions gptme/tools/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
pipx install 'gptme[browser]'
# We need to use the same version of Playwright as the one installed by gptme
# when downloading the browser binaries.
# when downloading the browser binaries. gptme will attempt this automatically
PW_VERSION=$(pipx runpip gptme show playwright | grep Version | cut -d' ' -f2)
pipx run playwright==$PW_VERSION install chromium
pipx run playwright==$PW_VERSION install chromium-headless-shell
Lynx backend:
- Text-only browser for basic page reading and searching
Expand All @@ -38,11 +38,13 @@
"""

import importlib.util
import importlib.metadata
import logging
import shutil
from pathlib import Path
from typing import Literal

from ..util import console
from .base import ToolSpec, ToolUse

has_playwright = lambda: importlib.util.find_spec("playwright") is not None # noqa
Expand Down Expand Up @@ -103,6 +105,10 @@ def examples(tool_format):


def has_browser_tool():
if browser == "playwright":
console.log("Browser tool available (using playwright)")
elif browser == "lynx":
console.log("Browser tool available (using lynx)")
return browser is not None


Expand Down

0 comments on commit ebf5675

Please sign in to comment.