From fbb37866553b59d9d48e434a398bd8aa740fa48a Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 07:53:43 +0000 Subject: [PATCH 01/11] feat: remove driver --- pyproject.toml | 5 ++- src/lavague/cli/commands.py | 7 +++- src/lavague/command_center.py | 63 +++++++++++++++-------------------- src/lavague/driver.py | 50 +++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 39 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5094b782..925a36bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,10 @@ dependencies = [ "gradio==4.21.0", "ipython", "langchain==0.1.10", - "datasets" + "datasets", + "fastapi", + "uvicorn", + "starlette" ] [project.optional-dependencies] diff --git a/src/lavague/cli/commands.py b/src/lavague/cli/commands.py index 22e422b6..193f6cc3 100644 --- a/src/lavague/cli/commands.py +++ b/src/lavague/cli/commands.py @@ -18,6 +18,8 @@ def launch(ctx): """Start a local gradio demo of lavague""" from .config import Config, Instructions from ..command_center import GradioDemo + from ..browser_server import run_server + from multiprocessing import Process config = Config.from_path(ctx.obj["config"]) if ctx.obj["instructions"] is not None: @@ -28,8 +30,11 @@ def launch(ctx): # We will just pass the get driver func name to the Gradio demo. # We will call this during driver initialization in init_driver() get_driver = config.get_driver - command_center = GradioDemo(action_engine, get_driver) + command_center = GradioDemo(action_engine, (get_driver)) + p = Process(target=run_server, args=(get_driver, ())) + p.start() command_center.run(instructions.url, instructions.instructions) + p.join() @cli.command() diff --git a/src/lavague/command_center.py b/src/lavague/command_center.py index a21e07a9..6ddc7443 100644 --- a/src/lavague/command_center.py +++ b/src/lavague/command_center.py @@ -2,17 +2,9 @@ from abc import ABC, abstractmethod import gradio as gr -try: - from selenium.webdriver.common.by import By # import used by generated selenium code - from selenium.webdriver.common.keys import ( - Keys, -) -except Exception as e: - pass - from .telemetry import send_telemetry from .action_engine import ActionEngine -from .driver import AbstractDriver +from .driver import RemoteDriver import base64 class CommandCenter(ABC): @@ -46,34 +38,28 @@ class GradioDemo(CommandCenter): def __init__(self, actionEngine: ActionEngine, get_driver: callable): self.actionEngine = actionEngine self.get_driver = get_driver - self.driver = None + self.driver = RemoteDriver("127.0.0.1", 16500) self.base_url = "" self.success = False self.error = "" def init_driver(self): def init_driver_impl(url): - driver = self.get_driver() - driver.goTo(url) - driver.getScreenshot("screenshot.png") - # This function is supposed to fetch and return the image from the URL. - # Placeholder function: replace with actual image fetching logic. - driver.destroy() + self.driver.goTo(url) + self.driver.getScreenshot("screenshot.png") return "screenshot.png" return init_driver_impl def process_instructions(self): def process_instructions_impl(query, url_input): - driver = self.get_driver() - driver.goTo(url_input) - state = driver.getHtml() + self.driver.goTo(url_input) + state = self.driver.getHtml() response = "" for text in self.actionEngine.get_action_streaming(query, state, url_input): # do something with text as they arrive. response += text yield response - driver.destroy() return process_instructions_impl @@ -105,27 +91,30 @@ def telemetry(query, code, html, url_input): def __exec_code(self): def exec_code(url_input, code, full_code): - driver_o = self.get_driver() - self.error = "" + html = self.driver.getHtml() code = self.actionEngine.cleaning_function(code) - driver_o.goTo(url_input) - html = driver_o.getHtml() - driver_name, driver = driver_o.getDriver() # define driver for exec - exec(f"{driver_name.strip()} = driver") # define driver in case its name is different try: - exec(code) - output = "Successful code execution" - status = """

Success!

""" - self.success = True - full_code += code - url_input = driver_o.getUrl() - driver_o.getScreenshot("screenshot.png") + res = self.driver.execCode(code) + if res["success"] == True: + html = self.driver.getHtml() + url_input = self.driver.getUrl() + self.driver.getScreenshot("screenshot.png") + output = "Successful code execution" + status = """

Success!

""" + self.success = True + full_code += code + else: + err = res["error"] + output = f"Error in code execution: {err}" + status = """

Failure! Open the Debug tab for more information

""" + self.success = False + self.error = err except Exception as e: - output = f"Error in code execution: {str(e)}" + err = repr(e) + output = f"Error in code execution: {err}" status = """

Failure! Open the Debug tab for more information

""" self.success = False - self.error = repr(e) - driver_o.destroy() + self.error = err return output, code, html, status, full_code, "screenshot.png", url_input return exec_code @@ -211,4 +200,4 @@ def run(self, base_url: str, instructions: List[str], server_port: int = 7860): self.__telemetry(), inputs=[text_area, code_display, full_html, url_input], ) - demo.launch(server_port=server_port, share=True, debug=True) + demo.launch(server_port=server_port, share=True, debug=True, max_threads=1) diff --git a/src/lavague/driver.py b/src/lavague/driver.py index 6f92d01f..49ab53cd 100644 --- a/src/lavague/driver.py +++ b/src/lavague/driver.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from typing import Any, Tuple from .format_utils import clean_html +import requests try: from selenium.webdriver.remote.webdriver import WebDriver @@ -64,6 +65,55 @@ def destroy(self) -> None: pass +class RemoteDriver(AbstractDriver): + def __init__(self, addr: str, port: int = 16500): + self.addr = addr + self.port = port + + def getDriver(self) -> Tuple[str, WebDriver]: + return "driver", None + + def getUrl(self) -> str: + url = requests.get(f"http://{self.addr}:{self.port}/get_url") + url.raise_for_status() + url = url.text.strip('\"') + return url + + def goToUrlCode(self, url: str) -> str: + return f'' + + def goTo(self, url: str) -> None: + res = requests.get(f"http://{self.addr}:{self.port}/go_to", params={"url": url}) + res.raise_for_status() + + def getHtml(self, clean: bool = True) -> str: + html = requests.get(f"http://{self.addr}:{self.port}/get_html").json() + html = html["html"] + return clean_html(html) if clean else html + + def getScreenshot(self, filename: str) -> None: + import base64 + res_txt = requests.get(f"http://{self.addr}:{self.port}/screenshot") + res_txt.raise_for_status() + res_txt = res_txt.text + res = base64.b64decode(res_txt) + f = open(filename, "wb") + f.write(res) + f.close() + + def execCode(self, code: str) -> Any: + res = requests.post(f"http://{self.addr}:{self.port}/exec_code", json={"code": code}) + res.raise_for_status() + res = res.json() + return res + + def getDummyCode(self) -> str: + return '' + + def destroy(self) -> None: + res = requests.get(f"http://{self.addr}:{self.port}/destroy") + res.raise_for_status() + if SELENIUM_IMPORT: class SeleniumDriver(AbstractDriver): From ac14bd7febdc288f1e5b72d5ece517ffbe042624 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 08:28:21 +0000 Subject: [PATCH 02/11] chore: clean driver --- src/lavague/defaults.py | 2 +- src/lavague/driver.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lavague/defaults.py b/src/lavague/defaults.py index da17f9b0..b4cd389c 100644 --- a/src/lavague/defaults.py +++ b/src/lavague/defaults.py @@ -156,4 +156,4 @@ def default_get_playwright_driver() -> PlaywrightDriver: p = sync_playwright().start() browser = p.chromium.launch() page = browser.new_page() - return PlaywrightDriver(page, p) + return PlaywrightDriver(page) diff --git a/src/lavague/driver.py b/src/lavague/driver.py index 49ab53cd..6deb31a8 100644 --- a/src/lavague/driver.py +++ b/src/lavague/driver.py @@ -86,7 +86,7 @@ def goTo(self, url: str) -> None: res = requests.get(f"http://{self.addr}:{self.port}/go_to", params={"url": url}) res.raise_for_status() - def getHtml(self, clean: bool = True) -> str: + def getHtml(self, clean: bool = False) -> str: html = requests.get(f"http://{self.addr}:{self.port}/get_html").json() html = html["html"] return clean_html(html) if clean else html @@ -149,9 +149,8 @@ def destroy(self) -> None: if PLAYWRIGHT_IMPORT: class PlaywrightDriver(AbstractDriver): - def __init__(self, sync_playwright_page: Page, context: Playwright): + def __init__(self, sync_playwright_page: Page): self.driver = sync_playwright_page - self.context = context def getDriver(self) -> Tuple[str, Page]: return "page", self.driver @@ -176,4 +175,3 @@ def getDummyCode(self) -> str: def destroy(self) -> None: self.driver.close() - self.context.stop() From 95db12b93db007171e5f48cc99f72eeaf43e2fa7 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 13:13:04 +0300 Subject: [PATCH 03/11] chore: remote driver fix ret --- src/lavague/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lavague/driver.py b/src/lavague/driver.py index 6deb31a8..b65d5638 100644 --- a/src/lavague/driver.py +++ b/src/lavague/driver.py @@ -70,7 +70,7 @@ def __init__(self, addr: str, port: int = 16500): self.addr = addr self.port = port - def getDriver(self) -> Tuple[str, WebDriver]: + def getDriver(self) -> Tuple[str, Any]: return "driver", None def getUrl(self) -> str: From c5e1b003c58f243eebb724f9b84a1bdc7dfa5134 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 10:14:23 +0000 Subject: [PATCH 04/11] fix: add browser server --- src/lavague/browser_server.py | 123 ++++++++++++++++++++++++++++++++++ src/lavague/cli/commands.py | 18 ++++- src/lavague/cli/main.py | 1 + src/lavague/format_utils.py | 7 ++ 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/lavague/browser_server.py diff --git a/src/lavague/browser_server.py b/src/lavague/browser_server.py new file mode 100644 index 00000000..6f462894 --- /dev/null +++ b/src/lavague/browser_server.py @@ -0,0 +1,123 @@ +# server.py +import os +import sys +from typing import Callable +from fastapi import FastAPI +import lavague.defaults +from pydantic import BaseModel +from sqlalchemy import func +import uvicorn +import lavague +import base64 +from lavague.driver import AbstractDriver +from lavague.format_utils import list_to_str, extract_code_from_funct, extract_imports_from_lines + +class Request(BaseModel): + code: str + +driver_global: AbstractDriver = None +get_driver: Callable[[], AbstractDriver] + +# fastapi set-up +app = FastAPI() + +@app.get("/screenshot") +def scr(): + global driver_global + if driver_global is None: + driver_global = get_driver() + driver_global.getScreenshot("screenshot.png") + f = open("screenshot.png", "rb") + scr = base64.b64encode(f.read()) + return scr.decode("ascii") + +@app.post("/exec_code") +def exec_code(req: Request): + global driver_global + if driver_global is None: + driver_global = get_driver() + success = False + error = "" + driver_name, driver = driver_global.getDriver() # define driver for exec + exec(f"{driver_name.strip()} = driver") # define driver in case its name is different + source_code_lines = extract_code_from_funct(get_driver) + import_lines = extract_imports_from_lines(source_code_lines) + code_to_exec = f""" +{import_lines} +{req.code} +""" + print(code_to_exec) + try: + exec(code_to_exec) + success = True + except Exception as e: + error = repr(e) + return {"success": success, "error": error} + + +@app.get("/get_url") +def geturl(): + global driver_global + if driver_global is None: + driver_global = get_driver() + url = driver_global.getUrl() + return url + +@app.get("/get_html") +def gethtml(): + global driver_global + if driver_global is None: + driver_global = get_driver() + html = driver_global.getHtml() + return {"html": html} + +@app.get("/go_to") +def goto(url: str): + global driver_global + if driver_global is None: + driver_global = get_driver() + if url != driver_global.getUrl(): + driver_global.goTo(url) + return "" + +@app.get("/destroy") +def destroy(): + global driver_global + if driver_global is not None: + driver_global.destroy() + return "" + +@app.get("/") +def default(): + return "" + +@app.post("/driver_code") +def driver_code(req: Request): + global get_driver + global driver_global + + success = False + error = "" + code = req.code + print(code) + code_to_exec = f""" +def get_driver_func() -> AbstractDriver: +{code} +""" + print(code_to_exec) + exec(code_to_exec, globals()) + get_driver = get_driver_func + print(get_driver_func) + print(get_driver) + driver_global = get_driver_func() + print(driver_global) + return "" + +def run_server(driver_func: Callable[[], AbstractDriver], debug: bool = False): + global get_driver + if driver_func is not None: + get_driver = driver_func + uvicorn.run(app, host="127.0.0.1", port=16500, log_level="debug", workers=1, limit_concurrency=3) + +if __name__ == "__main__": + run_server(None) \ No newline at end of file diff --git a/src/lavague/cli/commands.py b/src/lavague/cli/commands.py index 193f6cc3..5d550c66 100644 --- a/src/lavague/cli/commands.py +++ b/src/lavague/cli/commands.py @@ -4,13 +4,29 @@ import os from lavague.evaluator import Evaluator, SeleniumActionEvaluator -from ..format_utils import extract_code_from_funct, extract_imports_from_lines +from ..format_utils import extract_code_from_funct, list_to_str @click.group() def cli(): pass +@cli.command() +@click.pass_context +def driver_server(ctx): + """Start a server containing the driver""" + from .config import Config, Instructions + from ..browser_server import run_server + import subprocess + import pkg_resources + import sys + + config = Config.from_path(ctx.obj["config"]) + get_driver = config.get_driver + distribution = pkg_resources.get_distribution("lavague") + subprocess_script_path = distribution.get_resource_filename("lavague", "lavague/browser_server.py") + subprocess.run([sys.executable, subprocess_script_path] + [list_to_str(extract_code_from_funct(get_driver))]) + @cli.command() @click.pass_context diff --git a/src/lavague/cli/main.py b/src/lavague/cli/main.py index a495d8d3..83d29e7a 100644 --- a/src/lavague/cli/main.py +++ b/src/lavague/cli/main.py @@ -42,6 +42,7 @@ def _lazy_load(self, cmd_name): cls=LazyGroup, lazy_subcommands={ "launch": "lavague.cli.commands.launch", + "driver_server": "lavague.cli.commands.driver_server", "build": "lavague.cli.commands.build", "eval": "lavague.cli.commands.evaluation", "test": "lavague.cli.commands.test", diff --git a/src/lavague/format_utils.py b/src/lavague/format_utils.py index b41c6bde..5d83f8b2 100644 --- a/src/lavague/format_utils.py +++ b/src/lavague/format_utils.py @@ -15,6 +15,13 @@ def extract_code_from_funct(funct: Callable) -> List[str]: ] # every line except the return +def list_to_str(lines: List[str], add_before: str = "") -> str: + """""" + return "\n".join( + [add_before + line for line in lines] + ) + + def extract_imports_from_lines(lines: List[str]) -> str: """Only keep import lines from python code lines and join them""" return "\n".join( From 7536ec3440b20c11432951259a79a7f6b2096ece Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 14:20:56 +0000 Subject: [PATCH 05/11] fix: timeout after 5 seconds --- src/lavague/browser_server.py | 35 +++-------------------------------- src/lavague/cli/commands.py | 11 ++++------- src/lavague/cli/main.py | 1 + src/lavague/defaults.py | 1 + 4 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/lavague/browser_server.py b/src/lavague/browser_server.py index 6f462894..89779cc6 100644 --- a/src/lavague/browser_server.py +++ b/src/lavague/browser_server.py @@ -1,16 +1,12 @@ # server.py -import os -import sys from typing import Callable from fastapi import FastAPI -import lavague.defaults from pydantic import BaseModel from sqlalchemy import func import uvicorn -import lavague import base64 from lavague.driver import AbstractDriver -from lavague.format_utils import list_to_str, extract_code_from_funct, extract_imports_from_lines +from lavague.format_utils import extract_code_from_funct, extract_imports_from_lines class Request(BaseModel): code: str @@ -91,33 +87,8 @@ def destroy(): def default(): return "" -@app.post("/driver_code") -def driver_code(req: Request): - global get_driver - global driver_global - - success = False - error = "" - code = req.code - print(code) - code_to_exec = f""" -def get_driver_func() -> AbstractDriver: -{code} -""" - print(code_to_exec) - exec(code_to_exec, globals()) - get_driver = get_driver_func - print(get_driver_func) - print(get_driver) - driver_global = get_driver_func() - print(driver_global) - return "" - -def run_server(driver_func: Callable[[], AbstractDriver], debug: bool = False): +def run_server(driver_func: Callable[[], AbstractDriver] = None, debug: bool = False): global get_driver if driver_func is not None: get_driver = driver_func - uvicorn.run(app, host="127.0.0.1", port=16500, log_level="debug", workers=1, limit_concurrency=3) - -if __name__ == "__main__": - run_server(None) \ No newline at end of file + uvicorn.run(app, host="127.0.0.1", port=16500, log_level="debug", workers=1, limit_concurrency=3) \ No newline at end of file diff --git a/src/lavague/cli/commands.py b/src/lavague/cli/commands.py index 5d550c66..d9aa8191 100644 --- a/src/lavague/cli/commands.py +++ b/src/lavague/cli/commands.py @@ -1,3 +1,4 @@ +from multiprocessing import Process from typing import Optional import click import warnings @@ -15,17 +16,13 @@ def cli(): @click.pass_context def driver_server(ctx): """Start a server containing the driver""" - from .config import Config, Instructions + from .config import Config from ..browser_server import run_server - import subprocess - import pkg_resources - import sys + from multiprocessing import Process config = Config.from_path(ctx.obj["config"]) get_driver = config.get_driver - distribution = pkg_resources.get_distribution("lavague") - subprocess_script_path = distribution.get_resource_filename("lavague", "lavague/browser_server.py") - subprocess.run([sys.executable, subprocess_script_path] + [list_to_str(extract_code_from_funct(get_driver))]) + run_server(get_driver) @cli.command() diff --git a/src/lavague/cli/main.py b/src/lavague/cli/main.py index 83d29e7a..81713aa8 100644 --- a/src/lavague/cli/main.py +++ b/src/lavague/cli/main.py @@ -42,6 +42,7 @@ def _lazy_load(self, cmd_name): cls=LazyGroup, lazy_subcommands={ "launch": "lavague.cli.commands.launch", + "driver_server_jupyter": "lavague.cli.commands.driver_server_jupyter", "driver_server": "lavague.cli.commands.driver_server", "build": "lavague.cli.commands.build", "eval": "lavague.cli.commands.evaluation", diff --git a/src/lavague/defaults.py b/src/lavague/defaults.py index b4cd389c..ea96881c 100644 --- a/src/lavague/defaults.py +++ b/src/lavague/defaults.py @@ -156,4 +156,5 @@ def default_get_playwright_driver() -> PlaywrightDriver: p = sync_playwright().start() browser = p.chromium.launch() page = browser.new_page() + page.set_default_timeout(5000) return PlaywrightDriver(page) From f9420540090fc30cce31a3dfc7f5de2fc0f8a438 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 14:36:44 +0000 Subject: [PATCH 06/11] fix: remove buggy jupyter entrypoint --- src/lavague/cli/commands.py | 1 - src/lavague/cli/main.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/lavague/cli/commands.py b/src/lavague/cli/commands.py index d9aa8191..41377104 100644 --- a/src/lavague/cli/commands.py +++ b/src/lavague/cli/commands.py @@ -24,7 +24,6 @@ def driver_server(ctx): get_driver = config.get_driver run_server(get_driver) - @cli.command() @click.pass_context def launch(ctx): diff --git a/src/lavague/cli/main.py b/src/lavague/cli/main.py index 81713aa8..83d29e7a 100644 --- a/src/lavague/cli/main.py +++ b/src/lavague/cli/main.py @@ -42,7 +42,6 @@ def _lazy_load(self, cmd_name): cls=LazyGroup, lazy_subcommands={ "launch": "lavague.cli.commands.launch", - "driver_server_jupyter": "lavague.cli.commands.driver_server_jupyter", "driver_server": "lavague.cli.commands.driver_server", "build": "lavague.cli.commands.build", "eval": "lavague.cli.commands.evaluation", From 6a67fbd203483bec7edb2c41307552b6683cd9fe Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 14:38:27 +0000 Subject: [PATCH 07/11] chore: version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 925a36bd..ae7024d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "lavague" -version = "1.0.13" +version = "1.0.14" description = "Selenium & Playwright code generation from text instructions" readme = "README.md" requires-python = ">=3.8" From 625cf2cf94d844d0307becfdc70e149f802eaf48 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 14:50:44 +0000 Subject: [PATCH 08/11] fix: add back import in cli --- src/lavague/cli/commands.py | 4 ++-- src/lavague/format_utils.py | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/lavague/cli/commands.py b/src/lavague/cli/commands.py index 41377104..7e85ee22 100644 --- a/src/lavague/cli/commands.py +++ b/src/lavague/cli/commands.py @@ -4,8 +4,8 @@ import warnings import os -from lavague.evaluator import Evaluator, SeleniumActionEvaluator -from ..format_utils import extract_code_from_funct, list_to_str +from lavague.evaluator import Evaluator +from ..format_utils import extract_code_from_funct, extract_imports_from_lines @click.group() diff --git a/src/lavague/format_utils.py b/src/lavague/format_utils.py index 5d83f8b2..c5a545a3 100644 --- a/src/lavague/format_utils.py +++ b/src/lavague/format_utils.py @@ -14,14 +14,6 @@ def extract_code_from_funct(funct: Callable) -> List[str]: line[nident:] for line in source_code_lines[:-1] ] # every line except the return - -def list_to_str(lines: List[str], add_before: str = "") -> str: - """""" - return "\n".join( - [add_before + line for line in lines] - ) - - def extract_imports_from_lines(lines: List[str]) -> str: """Only keep import lines from python code lines and join them""" return "\n".join( From 5f2eaad9778b92e340d5ae64ce44e7f9aa2651c5 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Fri, 10 May 2024 14:54:27 +0000 Subject: [PATCH 09/11] chore: remove code print --- src/lavague/browser_server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lavague/browser_server.py b/src/lavague/browser_server.py index 89779cc6..f3050033 100644 --- a/src/lavague/browser_server.py +++ b/src/lavague/browser_server.py @@ -42,7 +42,6 @@ def exec_code(req: Request): {import_lines} {req.code} """ - print(code_to_exec) try: exec(code_to_exec) success = True From 8480680aa1e59c19121dea897b728ec5d07ebfe5 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Sun, 12 May 2024 07:42:00 +0000 Subject: [PATCH 10/11] fix: action engine tel --- src/lavague/action_engine.py | 4 ++-- src/lavague/browser_server.py | 1 + src/lavague/command_center.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lavague/action_engine.py b/src/lavague/action_engine.py index f5764704..b5be828e 100644 --- a/src/lavague/action_engine.py +++ b/src/lavague/action_engine.py @@ -165,7 +165,7 @@ def get_action_streaming(self, query: str, html: str, url: str = "") -> Generato finally: source_nodes = self.get_nodes(query, html) retrieved_context = "\n".join(source_nodes) - send_telemetry(self.llm.metadata.model_name, code, "", html, query, url, "action-engine", success, False, err, retrieved_context) + send_telemetry(self.llm.metadata.model_name, code, "", html, query, url, "action-engine", None, False, err, retrieved_context) def get_action_streaming_vscode(self, query: str, html: str, url: str) -> Generator[str, None, None]: from .telemetry import send_telemetry @@ -185,7 +185,7 @@ def get_action_streaming_vscode(self, query: str, html: str, url: str) -> Genera finally: source_nodes = self.get_nodes(query, html) retrieved_context = "\n".join(source_nodes) - send_telemetry(self.llm.metadata.model_name, full_text, "", html, query, url, "lavague-vscode", success, False, err, retrieved_context) + send_telemetry(self.llm.metadata.model_name, full_text, "", html, query, url, "lavague-vscode", None, False, err, retrieved_context) class TestActionEngine(BaseActionEngine): """ diff --git a/src/lavague/browser_server.py b/src/lavague/browser_server.py index f3050033..eaaf2b73 100644 --- a/src/lavague/browser_server.py +++ b/src/lavague/browser_server.py @@ -47,6 +47,7 @@ def exec_code(req: Request): success = True except Exception as e: error = repr(e) + success = False return {"success": success, "error": error} diff --git a/src/lavague/command_center.py b/src/lavague/command_center.py index 6ddc7443..0d10be21 100644 --- a/src/lavague/command_center.py +++ b/src/lavague/command_center.py @@ -103,6 +103,7 @@ def exec_code(url_input, code, full_code): status = """

Success!

""" self.success = True full_code += code + self.error = "" else: err = res["error"] output = f"Error in code execution: {err}" From 8ae0b3f5bfe7e05d3f0baee617ea6b70e0994966 Mon Sep 17 00:00:00 2001 From: JoFrost Date: Sun, 12 May 2024 08:55:06 +0000 Subject: [PATCH 11/11] fix: wait for page load --- src/lavague/action_engine.py | 3 +++ src/lavague/browser_server.py | 4 ++-- src/lavague/command_center.py | 8 ++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lavague/action_engine.py b/src/lavague/action_engine.py index b5be828e..9c565803 100644 --- a/src/lavague/action_engine.py +++ b/src/lavague/action_engine.py @@ -75,6 +75,7 @@ def __init__( self.retriever = retriever self.prompt_template = prompt_template self.cleaning_function = cleaning_function + self.retrieved_context = "" def get_query_engine( self, html: str, streaming: bool = True @@ -123,6 +124,7 @@ def get_action(self, query: str, html: str, url: str = "") -> str: finally: source_nodes = self.get_nodes(query, html) retrieved_context = "\n".join(source_nodes) + self.retrieved_context = retrieved_context send_telemetry(self.llm.metadata.model_name, code, "", html, query, url, "action-engine", success, False, err, retrieved_context) return code @@ -165,6 +167,7 @@ def get_action_streaming(self, query: str, html: str, url: str = "") -> Generato finally: source_nodes = self.get_nodes(query, html) retrieved_context = "\n".join(source_nodes) + self.retrieved_context = retrieved_context send_telemetry(self.llm.metadata.model_name, code, "", html, query, url, "action-engine", None, False, err, retrieved_context) def get_action_streaming_vscode(self, query: str, html: str, url: str) -> Generator[str, None, None]: diff --git a/src/lavague/browser_server.py b/src/lavague/browser_server.py index eaaf2b73..eac9f5ec 100644 --- a/src/lavague/browser_server.py +++ b/src/lavague/browser_server.py @@ -1,5 +1,5 @@ # server.py -from typing import Callable +from typing import Callable, Optional from fastapi import FastAPI from pydantic import BaseModel from sqlalchemy import func @@ -9,7 +9,7 @@ from lavague.format_utils import extract_code_from_funct, extract_imports_from_lines class Request(BaseModel): - code: str + code: Optional[str] = None driver_global: AbstractDriver = None get_driver: Callable[[], AbstractDriver] diff --git a/src/lavague/command_center.py b/src/lavague/command_center.py index 0d10be21..7990f3fd 100644 --- a/src/lavague/command_center.py +++ b/src/lavague/command_center.py @@ -56,6 +56,7 @@ def process_instructions_impl(query, url_input): self.driver.goTo(url_input) state = self.driver.getHtml() response = "" + print("Generating code...") for text in self.actionEngine.get_action_streaming(query, state, url_input): # do something with text as they arrive. response += text @@ -71,8 +72,11 @@ def telemetry(query, code, html, url_input): screenshot = base64.b64encode(scr.read()) except: pass - source_nodes = self.actionEngine.get_nodes(query, html) - retrieved_context = "\n".join(source_nodes) + try: + source_nodes = self.actionEngine.get_nodes(query, html) + retrieved_context = "\n".join(source_nodes) + except: + retrieved_context = self.actionEngine.retrieved_context send_telemetry( self.actionEngine.llm.metadata.model_name, code,