From 363d304e6207144b2bee061794381c3904407a2b Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 10:23:53 -0600 Subject: [PATCH 01/43] feat:web toolkit with stagehand (#1406) --- camel/toolkits/web_toolkit.py | 321 ++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 camel/toolkits/web_toolkit.py diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py new file mode 100644 index 0000000000..354194608c --- /dev/null +++ b/camel/toolkits/web_toolkit.py @@ -0,0 +1,321 @@ +import os +import subprocess +import json +from typing import Any, Dict, List + +from camel.toolkits.base import BaseToolkit +from camel.toolkits.function_tool import FunctionTool +from camel.agents import ChatAgent +from camel.models import ModelFactory +from camel.types import ModelPlatformType, ModelType +from camel.configs import ChatGPTConfig +from camel.messages import BaseMessage + + +class WebToolkit(BaseToolkit): + r"""A class representing a toolkit for web use. + + This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. + """ + + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: + r""" + Single entry point that: + 1) Generates Stagehand JavaScript code to interact with the web + 2) Executes it under Node.js + 3) Returns the final JSON result + + Args: + task_prompt (str): Description of the task to automate. + + Returns: + Dict[str, Any]: JSON result from the Stagehand script, or an error. + """ + + # Generate Stagehand code + js_code = self._generate_stagehand_code(task_prompt) + + # Run code in Node, capture JSON + result_str = self._run_stagehand_script_in_node(js_code) + + # Attempt to parse JSON + try: + return json.loads(result_str) + except json.JSONDecodeError: + return { + "status": "error", + "message": f"No valid JSON output. Last script line:\n{result_str}", + } + + # + # Internals + # + def _generate_stagehand_code(self, high_level_task: str) -> str: + r""" + Internal method for generating Stagehand code. + """ + model = ModelFactory.create( + model_platform=ModelPlatformType.OPENAI, + model_type=ModelType.GPT_4O_MINI, + model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + ) + + # A system message to instruct how to generate Stagehand code + agent = ChatAgent( + BaseMessage.make_assistant_message( + "Stagehand Agent", + "You are an intelligent assistant that searches the web to answer the given question.", + ), + model, + ) + + # The prompt with guidelines for Stagehand snippet generation + stagehand_prompt = f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} + The snippet must only contain Stagehand action commands (no imports, setup, or wrapping function). + For example: + - `await page.goto("https://www.example.com/");` + - `await page.act({{ action: "Click the Sign In button." }});` + - `const actions = await page.observe();` + - `const data = await page.extract({{ instruction: "Get user info." }});` + + Do not include: + 1. Any import statements like `require('@browserbasehq/stagehand')`. + 2. Any declarations like `const stagehand = new Stagehand()`. + 3. Any outer `async` function or IIFE wrapper. + 4. Console log lines for setup or imports. + - Include a console log for each step to indicate success. + - Avoid using any CSS selectors directly in `act()`—Stagehand AI will infer what to do from plain language. + - Extract structured information using `await page.extract()` with instructions like "Get the module details". + - Extract structured information using `await page.extract()` with instructions like "Get the module details". + - Use `observe()` to get actionable suggestions from the current page: + ```javascript + const actions = await page.observe(); + console.log("Possible actions:", actions); + + const buttons = await page.observe({{ + instruction: "Find all the buttons on the page." + }}); + + - Use await page.extract({{ instruction: "..." }}) for structured data extraction in natural language. Example extractions: + "Extract the current balance displayed on the account summary page." + "Extract the recent transactions list." + - extract() must always use instruction, never action. + - The `extract` function requires a `schema` that defines the expected structure of the extracted data. + For example, if you are extracting module details, the schema should specify the fields and types, such as: + ```javascript + const data = await page.extract({{ + instruction: "extract the title, description, and link of the quickstart", + schema: z.object({{ + title: z.string(), + description: z.string(), + link: z.string() + }}) + }}); + - IMPORTANT: Stagehand / OpenAI extraction requires that all top-level schemas be an 'object'. + Therefore, if you want to extract an array of items, wrap it in a top-level object with a + field like 'results' or 'items'. For example: + + // CORRECT: + schema: z.object({{ + results: z.array(z.object({{ + title: z.string(), + link: z.string() + }})) + }}) + + // INCORRECT (will fail): + schema: z.array(z.object({{ + title: z.string(), + link: z.string() + }})) + + So always wrap arrays in an object at the top level of your 'schema'. + - Do NOT combine multiple actions into one instruction—each action must be atomic. + - Keep the script concise, and use no more than one action per line. + - Avoid any advanced planning—just deliver direct, concrete instructions based on the task. + - Do not include backticks or a "javascript" label in your response. Just return the plain JavaScript code. + - First go to the link in the state. + - If the url is google.com, then search for the term you want. + - Add a small wait ight after searching on Google, do something like + - await page.act({{ action: "Wait a few seconds for results to load." }}); Then do the extraction. (Stagehand supports a small “Wait for N seconds” or “Wait for results to appear” approach using act({{ action: "Wait ..." }}).) + - Address specific shortcomings highlighted in the feedback, such as: + - Missed steps. + - Insufficient exploration of page elements. + - Incomplete or incorrect data extraction. + - Follow actionable suggestions to refine and expand your approach. + - Your plans should focus on exploring different elements on the page, especially those likely to yield useful data or advance the task. + - Include actions such as clicking buttons, links, toggles, and interacting with dropdowns or search bars. + - Aim to uncover new information or pathways that could help solve the task. + - Then proceed with rest of the plan. + - If a search yields no results, do not stop. Try alternative search terms or synonyms. + - If the page says “No results found,” instruct Stagehand to search for synonyms or check for similar items. + - If the plan is stuck, propose an alternative approach, such as returning to Google and refining the query with additional keywords. + - If initial attempts fail or yield incomplete data, refine or expand your approach using the feedback from the calling agent or from the search results. + - Use fallback steps like “try synonyms,” “use partial matches,” or “check for recommended articles” if the direct query fails. + - You can go back to a previous plan if you think that was leading you in the correct direction. + - Keep scope of the plan limited to solving the high level task of {high_level_task}. + You are a web automation assistant using Stagehand. Your role is to: + + Visit pages or perform searches. + Extract data from the page. + If needed, filter or process that data locally in your snippet. + Optionally, re-visit or do additional atomic actions based on the new info. + Print final results as JSON so the calling process can read them. + Important guidelines: + Atomic Stagehand instructions only. For example: + await page.goto("https://www.example.com"); + await page.act({{ action: "Click on the Login button."}}); + const data = await page.extract({{ instruction: "...", schema: z.object({ ... }) }}); + const actions = await page.observe(); + Do not combine multiple steps into one act() instruction—each line should be one discrete action. + Broad-to-narrow extraction pattern: + Broad extraction: “Extract all text, headings, or visible links.” + Local filter: Evaluate which items or links are relevant. + If you find a relevant link or portion, navigate or click. + Second extraction: Now specifically request the data you actually need (like “Extract all the bubble metrics,” or “Extract the largest bubble’s label,” etc.). + If the data is behind multiple clicks or expansions, continue with atomic steps (act() to click or scroll) until you see the data. Then extract again. + If you cannot find what you need, log that “No relevant data found” and end gracefully, or try an alternate approach (like refining your search). + This approach is generic and not tied to one site. It works as follows: + + “Load a page or perform a search” → atomic act({{ action: "Search for 'some phrase'" }}) or goto(...). + “Extract everything” with a broad instruction + broad schema. + “Filter locally in JS,” if needed, to pick the relevant link. + “Goto or click” to expand or open that detail. + “Extract again” with a narrower instruction + schema. + “Print final result.” + Keep your snippet’s instructions short and direct. Provide one action per act(). For extractions, use one extraction call for each chunk. + + Remember: + + Use observe() to see potential clickable items or possible actions. + Use extract() with a carefully chosen instruction and schema to gather data. + If you need more data, do another extraction. + - Incorporate feedback from previous iterations to improve the plan. + Based on this high level task: "{high_level_task}", generate a Stagehand JavaScript snippet with step-by-step instructions. + + - IMPORTANT: + 1. You are a Low-Level Planner that writes a Stagehand JavaScript snippet. + Remember to produce the final result as a JSON object called 'updated_state', which the system will read as: + + {{ + "status": "success", + "updated_state": {{ + "title": ..., + "finalAnswer": ..., + "uniqueItems": [...], + "link": ... + }} + }} + + The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. At the end of your snippet, always do the final extraction to fill these fields. For example: + + const updated_state = {{ + status: "success", + updated_state: {{ + title: extractedTitle, + finalAnswer: extractedFinalAnswer, + uniqueItems: extractedUniqueItems, + link: extractedLink + }} + }}; + + 2. Print or log the final data in a JSON-friendly format so the pipeline can read it. For example: + console.log("Final updated_state:", updated_state); + + 3. If you cannot find the necessary info after multiple steps, log "No relevant data found. Attempt an alternative approach or refine the search." + + 4. Keep your snippet concise. + + **Examples of valid atomic instructions** (one per line): + await page.goto("https://www.example.com"); await page.act({{ action: "Click the Sign In button." }}); const data = await page.extract({{ instruction: "Extract all text on page.", schema: z.object({{ text: z.string() }}) }}); + + **Do not** wrap multiple steps into a single act call. For instance, don’t do: + await page.act({{ action: "Click the sign in button and fill the form." }}); + + That should be two lines: one for the click, one for the fill. + + Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. + """ + + response = agent.step(BaseMessage.make_user_message("User", stagehand_prompt)) + if response and response.msgs: + return response.msgs[-1].content.strip() + else: + raise ValueError("Failed to generate Stagehand code.") + + def _run_stagehand_script_in_node(self, js_code: str) -> str: + r""" + Internal method that executes the Stagehand code under Node.js and returns + the final JSON line from stdout. + """ + script_path = "stagehand_script.js" + + # Wrap the user snippet with Stagehand environment + wrapper_code = f""" +const {{ Stagehand }} = require('@browserbasehq/stagehand'); +const chalk = require('chalk'); +const z = require('zod'); + +(async () => {{ + const stagehand = new Stagehand({{ headless: false }}); + await stagehand.init(); + const page = stagehand.page; + console.log(chalk.blue("Starting Stagehand automation...")); + try {{ + // Insert the generated snippet + {js_code} + + console.log(JSON.stringify({{ + status: "success", + updated_state + }})); + }} catch (error) {{ + console.error(JSON.stringify({{ + status: "failure", + error: error.message + }})); + }} finally {{ + await stagehand.close(); + console.log(chalk.green("Stagehand session closed.")); + }} +}})(); +""" + + # Write to temporary file + with open(script_path, "w") as f: + f.write(wrapper_code) + + # Run the script in Node.js + process = subprocess.Popen( + ["node", script_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + + output_lines = [] + while True: + line = process.stdout.readline() + if not line: + break + print(line.strip()) + output_lines.append(line.strip()) + + process.wait() + + # Return the second-last line or fallback to last line + if len(output_lines) >= 2: + return output_lines[-2] + elif output_lines: + return output_lines[-1] + return "Failure: No output from Node.js script." + + def get_tools(self) -> List[FunctionTool]: + r"""Returns a list of FunctionTool objects representing the + functions in the toolkit. + + Returns: + List[FunctionTool]: A list of FunctionTool objects + representing the functions in the toolkit. + """ + return [FunctionTool(self.stagehand_tool)] \ No newline at end of file From cfa29139564e4ba2b778854db73c21f5d5ee072e Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 13:57:20 -0600 Subject: [PATCH 02/43] refac: moved the model platform to class init --- camel/toolkits/web_toolkit.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 354194608c..18f14ccaca 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -18,6 +18,16 @@ class WebToolkit(BaseToolkit): This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. """ + def __init__( + self, + model_platform=ModelPlatformType.OPENAI, + model_type=ModelType.GPT_4O_MINI, + model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + ): + self.model_platform = model_platform + self.model_type = model_type + self.model_config_dict = model_config_dict + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: r""" Single entry point that: @@ -55,9 +65,9 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: Internal method for generating Stagehand code. """ model = ModelFactory.create( - model_platform=ModelPlatformType.OPENAI, - model_type=ModelType.GPT_4O_MINI, - model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + model_platform=self.model_platform, + model_type=self.model_type, + model_config_dict=self.model_config_dict, ) # A system message to instruct how to generate Stagehand code @@ -318,4 +328,4 @@ def get_tools(self) -> List[FunctionTool]: List[FunctionTool]: A list of FunctionTool objects representing the functions in the toolkit. """ - return [FunctionTool(self.stagehand_tool)] \ No newline at end of file + return [FunctionTool(self.stagehand_tool)] From 1c9b431bde523f91e08bf0c6a3d7b26431db6624 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 18:11:52 -0600 Subject: [PATCH 03/43] feat: use interpreter module --- camel/interpreters/subprocess_interpreter.py | 31 ++++++++++--- camel/toolkits/web_toolkit.py | 49 +++++++------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index b5ba04d310..214f3344cc 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -1,6 +1,6 @@ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= # Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. +# You may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 @@ -23,6 +23,7 @@ from camel.interpreters.base import BaseInterpreter from camel.interpreters.interpreter_error import InterpreterError from camel.logger import get_logger +import os logger = get_logger(__name__) @@ -32,7 +33,7 @@ class SubprocessInterpreter(BaseInterpreter): strings in a subprocess. This class handles the execution of code in different scripting languages - (currently Python and Bash) within a subprocess, capturing their + (currently Python, Bash, and Node.js) within a subprocess, capturing their stdout and stderr streams, and allowing user checking before executing code strings. @@ -48,11 +49,13 @@ class SubprocessInterpreter(BaseInterpreter): _CODE_EXECUTE_CMD_MAPPING: ClassVar[Dict[str, str]] = { "python": "python {file_name}", "bash": "bash {file_name}", + "node": "node {file_name}", } _CODE_EXTENSION_MAPPING: ClassVar[Dict[str, str]] = { "python": "py", "bash": "sh", + "node": "js", } _CODE_TYPE_MAPPING: ClassVar[Dict[str, str]] = { @@ -63,6 +66,9 @@ class SubprocessInterpreter(BaseInterpreter): "shell": "bash", "bash": "bash", "sh": "bash", + "node": "node", + "javascript": "node", + "js": "node", } def __init__( @@ -70,10 +76,20 @@ def __init__( require_confirm: bool = True, print_stdout: bool = False, print_stderr: bool = True, + node_path: str = "/usr/local/lib/node_modules", + env: Dict[str, str] = None, ) -> None: self.require_confirm = require_confirm self.print_stdout = print_stdout self.print_stderr = print_stderr + + # Set up environment variables + self.env = os.environ.copy() # Start with the current environment + if node_path: + print(f"Changing node path from {self.env['NODE_PATH']}\nTo {node_path}") + self.env["NODE_PATH"] = node_path # Add NODE_PATH for Node.js + if env: + self.env.update(env) def run_file( self, @@ -85,7 +101,7 @@ def run_file( Args: file (Path): The path object of the file to run. code_type (str): The type of code to execute (e.g., 'python', - 'bash'). + 'bash', 'node'). Returns: str: A string containing the captured stdout and stderr of the @@ -103,8 +119,9 @@ def run_file( file_name=str(file) ) ) + proc = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=self.env ) stdout, stderr = proc.communicate() if self.print_stdout and stdout: @@ -130,7 +147,7 @@ def run( Args: code (str): The code string to execute. code_type (str): The type of code to execute (e.g., 'python', - 'bash'). + 'bash', 'node'). Returns: str: A string containing the captured stdout and stderr of the @@ -142,7 +159,6 @@ def run( """ code_type = self._check_code_type(code_type) - # Print code for security checking if self.require_confirm: logger.info( f"The following {code_type} code will run on your " @@ -158,12 +174,13 @@ def run( "This choice stops the current operation and any " "further code execution." ) + temp_file_path = self._create_temp_file( code=code, extension=self._CODE_EXTENSION_MAPPING[code_type] ) result = self.run_file(temp_file_path, code_type) - + print(f"temp_file_path: {temp_file_path}") temp_file_path.unlink() return result diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 18f14ccaca..d1c7c82e34 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -10,7 +10,7 @@ from camel.types import ModelPlatformType, ModelType from camel.configs import ChatGPTConfig from camel.messages import BaseMessage - +from camel.interpreters.subprocess_interpreter import SubprocessInterpreter class WebToolkit(BaseToolkit): r"""A class representing a toolkit for web use. @@ -98,7 +98,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: - Extract structured information using `await page.extract()` with instructions like "Get the module details". - Extract structured information using `await page.extract()` with instructions like "Get the module details". - Use `observe()` to get actionable suggestions from the current page: - ```javascript + const actions = await page.observe(); console.log("Possible actions:", actions); @@ -112,7 +112,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: - extract() must always use instruction, never action. - The `extract` function requires a `schema` that defines the expected structure of the extracted data. For example, if you are extracting module details, the schema should specify the fields and types, such as: - ```javascript + const data = await page.extract({{ instruction: "extract the title, description, and link of the quickstart", schema: z.object({{ @@ -143,7 +143,9 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: - Do NOT combine multiple actions into one instruction—each action must be atomic. - Keep the script concise, and use no more than one action per line. - Avoid any advanced planning—just deliver direct, concrete instructions based on the task. - - Do not include backticks or a "javascript" label in your response. Just return the plain JavaScript code. + - IMPORTANT: + - ```javascript is NOT allowed in your response, even in the beginning. + - Do not include backticks or a "javascript" label in your response. Just return the plain JavaScript code. - First go to the link in the state. - If the url is google.com, then search for the term you want. - Add a small wait ight after searching on Google, do something like @@ -217,7 +219,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: }} }} - The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. At the end of your snippet, always do the final extraction to fill these fields. For example: + The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. At the end of your snippet, always do the final extraction to fill these fields in a variable called 'updated_state'. For example: const updated_state = {{ status: "success", @@ -258,19 +260,17 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: Internal method that executes the Stagehand code under Node.js and returns the final JSON line from stdout. """ - script_path = "stagehand_script.js" # Wrap the user snippet with Stagehand environment wrapper_code = f""" const {{ Stagehand }} = require('@browserbasehq/stagehand'); -const chalk = require('chalk'); const z = require('zod'); (async () => {{ const stagehand = new Stagehand({{ headless: false }}); await stagehand.init(); const page = stagehand.page; - console.log(chalk.blue("Starting Stagehand automation...")); + console.log("Starting Stagehand automation..."); try {{ // Insert the generated snippet {js_code} @@ -286,39 +286,22 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: }})); }} finally {{ await stagehand.close(); - console.log(chalk.green("Stagehand session closed.")); + console.log("Stagehand session closed."); }} }})(); """ - # Write to temporary file - with open(script_path, "w") as f: - f.write(wrapper_code) # Run the script in Node.js - process = subprocess.Popen( - ["node", script_path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - ) - - output_lines = [] - while True: - line = process.stdout.readline() - if not line: - break - print(line.strip()) - output_lines.append(line.strip()) - - process.wait() + node_process = SubprocessInterpreter(require_confirm=True, print_stdout=True, print_stderr=True) + + exec_result = node_process.run(wrapper_code, "node") # Return the second-last line or fallback to last line - if len(output_lines) >= 2: - return output_lines[-2] - elif output_lines: - return output_lines[-1] - return "Failure: No output from Node.js script." + if exec_result.startswith("(stderr"): + return "Failure: No output from Node.js script." + + return exec_result def get_tools(self) -> List[FunctionTool]: r"""Returns a list of FunctionTool objects representing the From 60b813629291fc2a374b8927be4322d3fa9cd9ab Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 18:18:38 -0600 Subject: [PATCH 04/43] fix: removed make methods from BaseMessage --- camel/toolkits/web_toolkit.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index d1c7c82e34..13f29c05ec 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -7,7 +7,7 @@ from camel.toolkits.function_tool import FunctionTool from camel.agents import ChatAgent from camel.models import ModelFactory -from camel.types import ModelPlatformType, ModelType +from camel.types import ModelPlatformType, ModelType, RoleType from camel.configs import ChatGPTConfig from camel.messages import BaseMessage from camel.interpreters.subprocess_interpreter import SubprocessInterpreter @@ -72,9 +72,11 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: # A system message to instruct how to generate Stagehand code agent = ChatAgent( - BaseMessage.make_assistant_message( - "Stagehand Agent", - "You are an intelligent assistant that searches the web to answer the given question.", + BaseMessage( + role_name="Stagehand Agent", + role_type=RoleType.ASSISTANT, + meta_dict=None, + content="You are an intelligent assistant that searches the web to answer the given question.", ), model, ) @@ -249,7 +251,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. """ - response = agent.step(BaseMessage.make_user_message("User", stagehand_prompt)) + response = agent.step(BaseMessage(role_name="User", role_type=RoleType.USER, meta_dict=None, content=stagehand_prompt)) if response and response.msgs: return response.msgs[-1].content.strip() else: From 24b5aa04115fb6d2e79527504fc4db5542a6898f Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 18:21:59 -0600 Subject: [PATCH 05/43] refac: formatting and removed debug statements --- camel/interpreters/subprocess_interpreter.py | 19 +++++++------------ camel/toolkits/web_toolkit.py | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index 214f3344cc..9a8153707a 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -23,7 +23,7 @@ from camel.interpreters.base import BaseInterpreter from camel.interpreters.interpreter_error import InterpreterError from camel.logger import get_logger -import os +import os logger = get_logger(__name__) @@ -82,7 +82,7 @@ def __init__( self.require_confirm = require_confirm self.print_stdout = print_stdout self.print_stderr = print_stderr - + # Set up environment variables self.env = os.environ.copy() # Start with the current environment if node_path: @@ -115,11 +115,9 @@ def run_file( raise RuntimeError(f"{file} is not a file.") code_type = self._check_code_type(code_type) cmd = shlex.split( - self._CODE_EXECUTE_CMD_MAPPING[code_type].format( - file_name=str(file) - ) + self._CODE_EXECUTE_CMD_MAPPING[code_type].format(file_name=str(file)) ) - + proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=self.env ) @@ -161,8 +159,7 @@ def run( if self.require_confirm: logger.info( - f"The following {code_type} code will run on your " - "computer: {code}" + f"The following {code_type} code will run on your " "computer: {code}" ) while True: choice = input("Running code? [Y/n]:").lower() @@ -180,7 +177,7 @@ def run( ) result = self.run_file(temp_file_path, code_type) - print(f"temp_file_path: {temp_file_path}") + temp_file_path.unlink() return result @@ -207,6 +204,4 @@ def supported_code_types(self) -> List[str]: def update_action_space(self, action_space: Dict[str, Any]) -> None: r"""Updates action space for *python* interpreter""" - raise RuntimeError( - "SubprocessInterpreter doesn't support " "`action_space`." - ) + raise RuntimeError("SubprocessInterpreter doesn't support " "`action_space`.") diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 13f29c05ec..8d54b0d0d9 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -12,6 +12,7 @@ from camel.messages import BaseMessage from camel.interpreters.subprocess_interpreter import SubprocessInterpreter + class WebToolkit(BaseToolkit): r"""A class representing a toolkit for web use. @@ -251,7 +252,14 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. """ - response = agent.step(BaseMessage(role_name="User", role_type=RoleType.USER, meta_dict=None, content=stagehand_prompt)) + response = agent.step( + BaseMessage( + role_name="User", + role_type=RoleType.USER, + meta_dict=None, + content=stagehand_prompt, + ) + ) if response and response.msgs: return response.msgs[-1].content.strip() else: @@ -293,10 +301,11 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: }})(); """ - # Run the script in Node.js - node_process = SubprocessInterpreter(require_confirm=True, print_stdout=True, print_stderr=True) - + node_process = SubprocessInterpreter( + require_confirm=True, print_stdout=True, print_stderr=True + ) + exec_result = node_process.run(wrapper_code, "node") # Return the second-last line or fallback to last line From f94bdc15a80e40544614e67b288348f7422e202d Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 20 Jan 2025 18:39:11 -0600 Subject: [PATCH 06/43] fix: removed the code to choose the runtime env --- camel/interpreters/subprocess_interpreter.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index 9a8153707a..7ed62b11fc 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -76,21 +76,11 @@ def __init__( require_confirm: bool = True, print_stdout: bool = False, print_stderr: bool = True, - node_path: str = "/usr/local/lib/node_modules", - env: Dict[str, str] = None, ) -> None: self.require_confirm = require_confirm self.print_stdout = print_stdout self.print_stderr = print_stderr - # Set up environment variables - self.env = os.environ.copy() # Start with the current environment - if node_path: - print(f"Changing node path from {self.env['NODE_PATH']}\nTo {node_path}") - self.env["NODE_PATH"] = node_path # Add NODE_PATH for Node.js - if env: - self.env.update(env) - def run_file( self, file: Path, @@ -119,7 +109,7 @@ def run_file( ) proc = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=self.env + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) stdout, stderr = proc.communicate() if self.print_stdout and stdout: From a9328767726b9909e7e333e4417c078c8e9c699d Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 02:39:56 -0600 Subject: [PATCH 07/43] feat: added arg for headless_mode --- camel/toolkits/web_toolkit.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 8d54b0d0d9..37bbbb4338 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -24,10 +24,12 @@ def __init__( model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI, model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + headless_mode=True ): self.model_platform = model_platform self.model_type = model_type self.model_config_dict = model_config_dict + self.headless_mode = headless_mode def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: r""" @@ -277,7 +279,7 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: const z = require('zod'); (async () => {{ - const stagehand = new Stagehand({{ headless: false }}); + const stagehand = new Stagehand({{ headless: {"true" if self.headless_mode else "false"} }}); await stagehand.init(); const page = stagehand.page; console.log("Starting Stagehand automation..."); From 4cf4a6c787a88b7cc622e9616d15665e6063ad40 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 02:43:35 -0600 Subject: [PATCH 08/43] fix: ModelPlatformType & Type to DEFAULT --- camel/toolkits/web_toolkit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 37bbbb4338..16f646b85c 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -21,8 +21,8 @@ class WebToolkit(BaseToolkit): def __init__( self, - model_platform=ModelPlatformType.OPENAI, - model_type=ModelType.GPT_4O_MINI, + model_platform=ModelPlatformType.DEFAULT, + model_type=ModelType.DEFAULT, model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), headless_mode=True ): From db87affd0250df49aa0814d2393b226051f20455 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 02:48:01 -0600 Subject: [PATCH 09/43] fix: moved Agent to __init__ --- camel/toolkits/web_toolkit.py | 40 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 16f646b85c..3f29ec14d9 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -30,10 +30,28 @@ def __init__( self.model_type = model_type self.model_config_dict = model_config_dict self.headless_mode = headless_mode + + self.model = ModelFactory.create( + model_platform=self.model_platform, + model_type=self.model_type, + model_config_dict=self.model_config_dict, + ) + + # A system message to instruct how to generate Stagehand code + self.agent = ChatAgent( + BaseMessage( + role_name="Stagehand Agent", + role_type=RoleType.ASSISTANT, + meta_dict=None, + content="You are an intelligent assistant that searches the web to answer the given question.", + ), + self.model, + ) + + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: - r""" - Single entry point that: + r"""Single entry point that: 1) Generates Stagehand JavaScript code to interact with the web 2) Executes it under Node.js 3) Returns the final JSON result @@ -67,22 +85,6 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: r""" Internal method for generating Stagehand code. """ - model = ModelFactory.create( - model_platform=self.model_platform, - model_type=self.model_type, - model_config_dict=self.model_config_dict, - ) - - # A system message to instruct how to generate Stagehand code - agent = ChatAgent( - BaseMessage( - role_name="Stagehand Agent", - role_type=RoleType.ASSISTANT, - meta_dict=None, - content="You are an intelligent assistant that searches the web to answer the given question.", - ), - model, - ) # The prompt with guidelines for Stagehand snippet generation stagehand_prompt = f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} @@ -254,7 +256,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. """ - response = agent.step( + response = self.agent.step( BaseMessage( role_name="User", role_type=RoleType.USER, From fd6a47e8eaa4d5d77f71fe69d42f3dda27284282 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 02:50:06 -0600 Subject: [PATCH 10/43] refac: simplified agent.step() --- camel/toolkits/web_toolkit.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 3f29ec14d9..f7c05e1e8b 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -256,14 +256,8 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. """ - response = self.agent.step( - BaseMessage( - role_name="User", - role_type=RoleType.USER, - meta_dict=None, - content=stagehand_prompt, - ) - ) + response = self.agent.step(input_message=stagehand_prompt) + if response and response.msgs: return response.msgs[-1].content.strip() else: From 88cda9e20911863fe812a7b0601b105ecf719fe8 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 03:51:40 -0600 Subject: [PATCH 11/43] refac: long-context prompt to the top of the file --- camel/toolkits/web_toolkit.py | 170 +++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 75 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index f7c05e1e8b..715372a0b8 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -11,83 +11,16 @@ from camel.configs import ChatGPTConfig from camel.messages import BaseMessage from camel.interpreters.subprocess_interpreter import SubprocessInterpreter +from camel.prompts import TextPrompt - -class WebToolkit(BaseToolkit): - r"""A class representing a toolkit for web use. - - This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. +class StagehandPrompts: """ - - def __init__( - self, - model_platform=ModelPlatformType.DEFAULT, - model_type=ModelType.DEFAULT, - model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), - headless_mode=True - ): - self.model_platform = model_platform - self.model_type = model_type - self.model_config_dict = model_config_dict - self.headless_mode = headless_mode - - self.model = ModelFactory.create( - model_platform=self.model_platform, - model_type=self.model_type, - model_config_dict=self.model_config_dict, - ) - - # A system message to instruct how to generate Stagehand code - self.agent = ChatAgent( - BaseMessage( - role_name="Stagehand Agent", - role_type=RoleType.ASSISTANT, - meta_dict=None, - content="You are an intelligent assistant that searches the web to answer the given question.", - ), - self.model, - ) - - - - def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: - r"""Single entry point that: - 1) Generates Stagehand JavaScript code to interact with the web - 2) Executes it under Node.js - 3) Returns the final JSON result - - Args: - task_prompt (str): Description of the task to automate. - - Returns: - Dict[str, Any]: JSON result from the Stagehand script, or an error. - """ - - # Generate Stagehand code - js_code = self._generate_stagehand_code(task_prompt) - - # Run code in Node, capture JSON - result_str = self._run_stagehand_script_in_node(js_code) - - # Attempt to parse JSON - try: - return json.loads(result_str) - except json.JSONDecodeError: - return { - "status": "error", - "message": f"No valid JSON output. Last script line:\n{result_str}", - } - - # - # Internals - # - def _generate_stagehand_code(self, high_level_task: str) -> str: - r""" - Internal method for generating Stagehand code. - """ - - # The prompt with guidelines for Stagehand snippet generation - stagehand_prompt = f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} + A centralized class for Stagehand-related prompts, leveraging TextPrompt for better modularity and reuse. + """ + + def __init__(self, high_level_task: str): + self.high_level_task = high_level_task + self.stagehand_prompt = TextPrompt(f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} The snippet must only contain Stagehand action commands (no imports, setup, or wrapping function). For example: - `await page.goto("https://www.example.com/");` @@ -254,8 +187,89 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: That should be two lines: one for the click, one for the fill. Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. + """) + +class WebToolkit(BaseToolkit): + r"""A class representing a toolkit for web use. + + This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. """ + def __init__( + self, + model_platform=ModelPlatformType.DEFAULT, + model_type=ModelType.DEFAULT, + model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + headless_mode=True + ): + self.model_platform = model_platform + self.model_type = model_type + self.model_config_dict = model_config_dict + self.headless_mode = headless_mode + + self.model = ModelFactory.create( + model_platform=self.model_platform, + model_type=self.model_type, + model_config_dict=self.model_config_dict, + ) + + # A system message to instruct how to generate Stagehand code + self.agent = ChatAgent( + BaseMessage( + role_name="Stagehand Agent", + role_type=RoleType.ASSISTANT, + meta_dict=None, + content="You are an intelligent assistant that searches the web to answer the given question.", + ), + self.model, + ) + + + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: + r"""Single entry point that: + 1) Generates Stagehand JavaScript code to interact with the web + 2) Executes it under Node.js + 3) Returns the final JSON result + + Args: + task_prompt (str): Description of the task to automate. + + Returns: + Dict[str, Any]: JSON result from the Stagehand script, or an error. + """ + + # Generate Stagehand code + js_code = self._generate_stagehand_code(task_prompt) + + # Run code in Node, capture JSON + result_str = self._run_stagehand_script_in_node(js_code) + + # Attempt to parse JSON + try: + return json.loads(result_str) + except json.JSONDecodeError: + return { + "status": "error", + "message": f"No valid JSON output. Last script line:\n{result_str}", + } + + # + # Internals + # + def _generate_stagehand_code(self, high_level_task: str) -> str: + r""" + Internal method for generating Stagehand code. + + Args: + high_level_task (str): Description of the task to automate. + + Returns: + str: The generated JavaScript code. + """ + + # The prompt with guidelines for Stagehand snippet generation + stagehand_prompt = StagehandPrompts(high_level_task).stagehand_prompt + response = self.agent.step(input_message=stagehand_prompt) if response and response.msgs: @@ -267,6 +281,12 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" Internal method that executes the Stagehand code under Node.js and returns the final JSON line from stdout. + + Args: + js_code (str): The JavaScript code to execute. + + Returns: + str: The final output of the script or an error message. """ # Wrap the user snippet with Stagehand environment From ade8012569c61491158fa5cbf4d5664c7754d1a7 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Fri, 24 Jan 2025 03:55:33 -0600 Subject: [PATCH 12/43] doc: undo modify content in the license --- camel/interpreters/subprocess_interpreter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index 7ed62b11fc..fa2cd310c8 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -1,6 +1,6 @@ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= # Licensed under the Apache License, Version 2.0 (the "License"); -# You may not use this file except in compliance with the License. +# you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 From 8c0285eda6a8ef997d5d760182986ab1b56fb2a3 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Fri, 24 Jan 2025 04:24:09 -0600 Subject: [PATCH 13/43] doc: removed dysfunctional comment --- camel/toolkits/web_toolkit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 715372a0b8..cf10d44bc9 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -326,7 +326,6 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: exec_result = node_process.run(wrapper_code, "node") - # Return the second-last line or fallback to last line if exec_result.startswith("(stderr"): return "Failure: No output from Node.js script." From e8a2f2395c2cc026b4264b2ff0db41b576b27398 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Sun, 26 Jan 2025 12:21:49 -0600 Subject: [PATCH 14/43] fix: for E501 Line too long errors --- camel/toolkits/__init__.py | 2 + camel/toolkits/web_toolkit.py | 146 +++++++++++++++++++++------------- 2 files changed, 94 insertions(+), 54 deletions(-) diff --git a/camel/toolkits/__init__.py b/camel/toolkits/__init__.py index 30909f9f4d..37037bafe4 100644 --- a/camel/toolkits/__init__.py +++ b/camel/toolkits/__init__.py @@ -45,6 +45,7 @@ from .stripe_toolkit import StripeToolkit from .video_toolkit import VideoDownloaderToolkit from .dappier_toolkit import DappierToolkit +from .web_toolkit import WebToolkit __all__ = [ 'BaseToolkit', @@ -77,4 +78,5 @@ 'MeshyToolkit', 'OpenBBToolkit', 'DappierToolkit', + 'WebToolkit' ] diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index cf10d44bc9..83311a5a3f 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -15,13 +15,17 @@ class StagehandPrompts: """ - A centralized class for Stagehand-related prompts, leveraging TextPrompt for better modularity and reuse. + A centralized class for Stagehand-related prompts, + leveraging TextPrompt for better modularity and reuse. """ def __init__(self, high_level_task: str): self.high_level_task = high_level_task - self.stagehand_prompt = TextPrompt(f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} - The snippet must only contain Stagehand action commands (no imports, setup, or wrapping function). + self.stagehand_prompt = TextPrompt(f"""You an assistant that helps in writing a + JavaScript snippet for a web automation task using Stagehand. that acts + as a low level plan for getting the information for the high level task of {high_level_task} + The snippet must only contain Stagehand action commands (no imports, setup, + or wrapping function). For example: - `await page.goto("https://www.example.com/");` - `await page.act({{ action: "Click the Sign In button." }});` @@ -34,9 +38,12 @@ def __init__(self, high_level_task: str): 3. Any outer `async` function or IIFE wrapper. 4. Console log lines for setup or imports. - Include a console log for each step to indicate success. - - Avoid using any CSS selectors directly in `act()`—Stagehand AI will infer what to do from plain language. - - Extract structured information using `await page.extract()` with instructions like "Get the module details". - - Extract structured information using `await page.extract()` with instructions like "Get the module details". + - Avoid using any CSS selectors directly in `act()`—Stagehand AI will infer what to do + from plain language. + - Extract structured information using `await page.extract()` with instructions like + "Get the module details". + - Extract structured information using `await page.extract()` with instructions like + "Get the module details". - Use `observe()` to get actionable suggestions from the current page: const actions = await page.observe(); @@ -46,12 +53,15 @@ def __init__(self, high_level_task: str): instruction: "Find all the buttons on the page." }}); - - Use await page.extract({{ instruction: "..." }}) for structured data extraction in natural language. Example extractions: + - Use await page.extract({{ instruction: "..." }}) for structured data extraction + in natural language. Example extractions: "Extract the current balance displayed on the account summary page." "Extract the recent transactions list." - extract() must always use instruction, never action. - - The `extract` function requires a `schema` that defines the expected structure of the extracted data. - For example, if you are extracting module details, the schema should specify the fields and types, such as: + - The `extract` function requires a `schema` that defines the expected structure + of the extracted data. + For example, if you are extracting module details, the schema should specify the + fields and types, such as: const data = await page.extract({{ instruction: "extract the title, description, and link of the quickstart", @@ -85,57 +95,73 @@ def __init__(self, high_level_task: str): - Avoid any advanced planning—just deliver direct, concrete instructions based on the task. - IMPORTANT: - ```javascript is NOT allowed in your response, even in the beginning. - - Do not include backticks or a "javascript" label in your response. Just return the plain JavaScript code. + - Do not include backticks or a "javascript" label in your response. Just return the + plain JavaScript code. - First go to the link in the state. - If the url is google.com, then search for the term you want. - Add a small wait ight after searching on Google, do something like - - await page.act({{ action: "Wait a few seconds for results to load." }}); Then do the extraction. (Stagehand supports a small “Wait for N seconds” or “Wait for results to appear” approach using act({{ action: "Wait ..." }}).) + - await page.act({{ action: "Wait a few seconds for results to load." }}); + Then do the extraction. + (Stagehand supports a small “Wait for N seconds” or “Wait for results to appear” approach using + act({{ action: "Wait ..." }}).) - Address specific shortcomings highlighted in the feedback, such as: - Missed steps. - Insufficient exploration of page elements. - Incomplete or incorrect data extraction. - Follow actionable suggestions to refine and expand your approach. - - Your plans should focus on exploring different elements on the page, especially those likely to yield useful data or advance the task. - - Include actions such as clicking buttons, links, toggles, and interacting with dropdowns or search bars. + - Your plans should focus on exploring different elements on the page, especially those likely + to yield useful data or advance the task. + - Include actions such as clicking buttons, links, toggles, and interacting with dropdowns + or search bars. - Aim to uncover new information or pathways that could help solve the task. - Then proceed with rest of the plan. - If a search yields no results, do not stop. Try alternative search terms or synonyms. - - If the page says “No results found,” instruct Stagehand to search for synonyms or check for similar items. - - If the plan is stuck, propose an alternative approach, such as returning to Google and refining the query with additional keywords. - - If initial attempts fail or yield incomplete data, refine or expand your approach using the feedback from the calling agent or from the search results. - - Use fallback steps like “try synonyms,” “use partial matches,” or “check for recommended articles” if the direct query fails. + - If the page says “No results found,” instruct Stagehand to search for synonyms or check for + similar items. + - If the plan is stuck, propose an alternative approach, such as returning to Google and + refining the query with additional keywords. + - If initial attempts fail or yield incomplete data, refine or expand your approach using + the feedback from the calling agent or from the search results. + - Use fallback steps like “try synonyms,” “use partial matches,” or “check for recommended + articles” if the direct query fails. - You can go back to a previous plan if you think that was leading you in the correct direction. - Keep scope of the plan limited to solving the high level task of {high_level_task}. You are a web automation assistant using Stagehand. Your role is to: - Visit pages or perform searches. - Extract data from the page. - If needed, filter or process that data locally in your snippet. - Optionally, re-visit or do additional atomic actions based on the new info. - Print final results as JSON so the calling process can read them. + - Visit pages or perform searches. + - Extract data from the page. + - If needed, filter or process that data locally in your snippet. + - Optionally, re-visit or do additional atomic actions based on the new info. + - Print final results as JSON so the calling process can read them. Important guidelines: - Atomic Stagehand instructions only. For example: - await page.goto("https://www.example.com"); - await page.act({{ action: "Click on the Login button."}}); - const data = await page.extract({{ instruction: "...", schema: z.object({ ... }) }}); - const actions = await page.observe(); - Do not combine multiple steps into one act() instruction—each line should be one discrete action. - Broad-to-narrow extraction pattern: - Broad extraction: “Extract all text, headings, or visible links.” - Local filter: Evaluate which items or links are relevant. - If you find a relevant link or portion, navigate or click. - Second extraction: Now specifically request the data you actually need (like “Extract all the bubble metrics,” or “Extract the largest bubble’s label,” etc.). - If the data is behind multiple clicks or expansions, continue with atomic steps (act() to click or scroll) until you see the data. Then extract again. - If you cannot find what you need, log that “No relevant data found” and end gracefully, or try an alternate approach (like refining your search). - This approach is generic and not tied to one site. It works as follows: - - “Load a page or perform a search” → atomic act({{ action: "Search for 'some phrase'" }}) or goto(...). - “Extract everything” with a broad instruction + broad schema. - “Filter locally in JS,” if needed, to pick the relevant link. - “Goto or click” to expand or open that detail. - “Extract again” with a narrower instruction + schema. - “Print final result.” - Keep your snippet’s instructions short and direct. Provide one action per act(). For extractions, use one extraction call for each chunk. + - Atomic Stagehand instructions only. For example: + await page.goto("https://www.example.com"); + await page.act({{ action: "Click on the Login button."}}); + const data = await page.extract({{ instruction: "...", schema: z.object({ ... }) }}); + const actions = await page.observe(); + - Do not combine multiple steps into one act() instruction—each line should be one discrete + action. + - Broad-to-narrow extraction pattern: + - Broad extraction: “Extract all text, headings, or visible links.” + - Local filter: Evaluate which items or links are relevant. + - If you find a relevant link or portion, navigate or click. + - Second extraction: Now specifically request the data you actually need (like “Extract all the + - bubble metrics,” or “Extract the largest bubble’s label,” etc.). + - If the data is behind multiple clicks or expansions, continue with atomic steps (act() to + click or scroll) until you see the data. Then extract again. + - If you cannot find what you need, log that “No relevant data found” and end gracefully, or + try an alternate approach (like refining your search). + - This approach is generic and not tied to one site. It works as follows: + + “Load a page or perform a search” → atomic act({{ action: "Search for 'some phrase'" }}) + or goto(...). + “Extract everything” with a broad instruction + broad schema. + “Filter locally in JS,” if needed, to pick the relevant link. + “Goto or click” to expand or open that detail. + “Extract again” with a narrower instruction + schema. + “Print final result.” + Keep your snippet’s instructions short and direct. Provide one action per act(). + For extractions, use one extraction call for each chunk. Remember: @@ -143,11 +169,13 @@ def __init__(self, high_level_task: str): Use extract() with a carefully chosen instruction and schema to gather data. If you need more data, do another extraction. - Incorporate feedback from previous iterations to improve the plan. - Based on this high level task: "{high_level_task}", generate a Stagehand JavaScript snippet with step-by-step instructions. + Based on this high level task: "{high_level_task}", generate a Stagehand JavaScript snippet + with step-by-step instructions. - IMPORTANT: 1. You are a Low-Level Planner that writes a Stagehand JavaScript snippet. - Remember to produce the final result as a JSON object called 'updated_state', which the system will read as: + Remember to produce the final result as a JSON object called 'updated_state', which the + system will read as: {{ "status": "success", @@ -159,7 +187,9 @@ def __init__(self, high_level_task: str): }} }} - The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. At the end of your snippet, always do the final extraction to fill these fields in a variable called 'updated_state'. For example: + The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. + At the end of your snippet, always do the final extraction to fill these fields in a + variable called 'updated_state'. For example: const updated_state = {{ status: "success", @@ -171,28 +201,35 @@ def __init__(self, high_level_task: str): }} }}; - 2. Print or log the final data in a JSON-friendly format so the pipeline can read it. For example: + 2. Print or log the final data in a JSON-friendly format so the pipeline can read it. + For example: console.log("Final updated_state:", updated_state); - 3. If you cannot find the necessary info after multiple steps, log "No relevant data found. Attempt an alternative approach or refine the search." + 3. If you cannot find the necessary info after multiple steps, log "No relevant data found. + Attempt an alternative approach or refine the search." 4. Keep your snippet concise. **Examples of valid atomic instructions** (one per line): - await page.goto("https://www.example.com"); await page.act({{ action: "Click the Sign In button." }}); const data = await page.extract({{ instruction: "Extract all text on page.", schema: z.object({{ text: z.string() }}) }}); + await page.goto("https://www.example.com"); + await page.act({{ action: "Click the Sign In button." }}); const data = await + page.extract({{ instruction: "Extract all text on page.", + schema: z.object({{ text: z.string() }}) }}); **Do not** wrap multiple steps into a single act call. For instance, don’t do: await page.act({{ action: "Click the sign in button and fill the form." }}); That should be two lines: one for the click, one for the fill. - Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. + Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, + always ending with the final extraction snippet for `updated_state`. """) class WebToolkit(BaseToolkit): r"""A class representing a toolkit for web use. - This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. + This class provides methods for interacting with websites by writing direct JavaScript code + via tools like Stagehand. """ def __init__( @@ -219,7 +256,8 @@ def __init__( role_name="Stagehand Agent", role_type=RoleType.ASSISTANT, meta_dict=None, - content="You are an intelligent assistant that searches the web to answer the given question.", + content="""You are an intelligent assistant that searches the web to answer the + given question.""", ), self.model, ) @@ -339,4 +377,4 @@ def get_tools(self) -> List[FunctionTool]: List[FunctionTool]: A list of FunctionTool objects representing the functions in the toolkit. """ - return [FunctionTool(self.stagehand_tool)] + return [FunctionTool(self.stagehand_tool)] \ No newline at end of file From c66e32fb7508d9bc6ea76d5434623b1e7eebf96a Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Sun, 26 Jan 2025 12:26:11 -0600 Subject: [PATCH 15/43] doc: formatting and remove unused imports --- camel/toolkits/web_toolkit.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 83311a5a3f..459e527144 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -1,5 +1,3 @@ -import os -import subprocess import json from typing import Any, Dict, List @@ -13,15 +11,17 @@ from camel.interpreters.subprocess_interpreter import SubprocessInterpreter from camel.prompts import TextPrompt + class StagehandPrompts: """ - A centralized class for Stagehand-related prompts, + A centralized class for Stagehand-related prompts, leveraging TextPrompt for better modularity and reuse. """ - + def __init__(self, high_level_task: str): self.high_level_task = high_level_task - self.stagehand_prompt = TextPrompt(f"""You an assistant that helps in writing a + self.stagehand_prompt = TextPrompt( + f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task} The snippet must only contain Stagehand action commands (no imports, setup, @@ -223,12 +223,14 @@ def __init__(self, high_level_task: str): Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, always ending with the final extraction snippet for `updated_state`. - """) + """ + ) + class WebToolkit(BaseToolkit): r"""A class representing a toolkit for web use. - This class provides methods for interacting with websites by writing direct JavaScript code + This class provides methods for interacting with websites by writing direct JavaScript code via tools like Stagehand. """ @@ -237,13 +239,13 @@ def __init__( model_platform=ModelPlatformType.DEFAULT, model_type=ModelType.DEFAULT, model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), - headless_mode=True + headless_mode=True, ): self.model_platform = model_platform self.model_type = model_type self.model_config_dict = model_config_dict self.headless_mode = headless_mode - + self.model = ModelFactory.create( model_platform=self.model_platform, model_type=self.model_type, @@ -261,8 +263,7 @@ def __init__( ), self.model, ) - - + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: r"""Single entry point that: 1) Generates Stagehand JavaScript code to interact with the web @@ -297,7 +298,7 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: def _generate_stagehand_code(self, high_level_task: str) -> str: r""" Internal method for generating Stagehand code. - + Args: high_level_task (str): Description of the task to automate. @@ -309,7 +310,7 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: stagehand_prompt = StagehandPrompts(high_level_task).stagehand_prompt response = self.agent.step(input_message=stagehand_prompt) - + if response and response.msgs: return response.msgs[-1].content.strip() else: @@ -319,7 +320,7 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" Internal method that executes the Stagehand code under Node.js and returns the final JSON line from stdout. - + Args: js_code (str): The JavaScript code to execute. @@ -377,4 +378,4 @@ def get_tools(self) -> List[FunctionTool]: List[FunctionTool]: A list of FunctionTool objects representing the functions in the toolkit. """ - return [FunctionTool(self.stagehand_tool)] \ No newline at end of file + return [FunctionTool(self.stagehand_tool)] From f4cece99ae39a2e4a16753a18be39d5569287e6a Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 03:28:47 -0600 Subject: [PATCH 16/43] fix: linting errs & webtoolkit in __init__ --- camel/toolkits/__init__.py | 2 +- camel/toolkits/web_toolkit.py | 209 +++++++++++++++++++++------------- 2 files changed, 129 insertions(+), 82 deletions(-) diff --git a/camel/toolkits/__init__.py b/camel/toolkits/__init__.py index 37037bafe4..867a2a2819 100644 --- a/camel/toolkits/__init__.py +++ b/camel/toolkits/__init__.py @@ -78,5 +78,5 @@ 'MeshyToolkit', 'OpenBBToolkit', 'DappierToolkit', - 'WebToolkit' + 'WebToolkit', ] diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 459e527144..2403a96d92 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -1,15 +1,31 @@ +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= import json from typing import Any, Dict, List -from camel.toolkits.base import BaseToolkit -from camel.toolkits.function_tool import FunctionTool from camel.agents import ChatAgent -from camel.models import ModelFactory -from camel.types import ModelPlatformType, ModelType, RoleType from camel.configs import ChatGPTConfig -from camel.messages import BaseMessage from camel.interpreters.subprocess_interpreter import SubprocessInterpreter +from camel.messages import BaseMessage +from camel.models import ModelFactory from camel.prompts import TextPrompt +from camel.toolkits.base import BaseToolkit +from camel.toolkits.function_tool import FunctionTool +from camel.types import ModelPlatformType, ModelType, RoleType + +# Define a module-level constant for the default ChatGPT configuration +_DEFAULT_CHATGPT_CONFIG_DICT = ChatGPTConfig(temperature=0.0).as_dict() class StagehandPrompts: @@ -23,9 +39,10 @@ def __init__(self, high_level_task: str): self.stagehand_prompt = TextPrompt( f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts - as a low level plan for getting the information for the high level task of {high_level_task} - The snippet must only contain Stagehand action commands (no imports, setup, - or wrapping function). + as a low level plan for getting the information for the high + level task of {high_level_task}The snippet must only contain + Stagehand action + commands (no imports, setup, or wrapping function). For example: - `await page.goto("https://www.example.com/");` - `await page.act({{ action: "Click the Sign In button." }});` @@ -38,12 +55,12 @@ def __init__(self, high_level_task: str): 3. Any outer `async` function or IIFE wrapper. 4. Console log lines for setup or imports. - Include a console log for each step to indicate success. - - Avoid using any CSS selectors directly in `act()`—Stagehand AI will infer what to do - from plain language. - - Extract structured information using `await page.extract()` with instructions like - "Get the module details". - - Extract structured information using `await page.extract()` with instructions like - "Get the module details". + - Avoid using any CSS selectors directly in `act()`—Stagehand + AI will infer what to do from plain language. + - Extract structured information using `await page.extract()` + with instructions like "Get the module details". + - Extract structured information using `await page.extract()` + with instructions like "Get the module details". - Use `observe()` to get actionable suggestions from the current page: const actions = await page.observe(); @@ -53,27 +70,29 @@ def __init__(self, high_level_task: str): instruction: "Find all the buttons on the page." }}); - - Use await page.extract({{ instruction: "..." }}) for structured data extraction - in natural language. Example extractions: + - Use await page.extract({{ instruction: "..." }}) for + structured data extraction in natural language. Example extractions: "Extract the current balance displayed on the account summary page." "Extract the recent transactions list." - extract() must always use instruction, never action. - - The `extract` function requires a `schema` that defines the expected structure - of the extracted data. - For example, if you are extracting module details, the schema should specify the - fields and types, such as: + - The `extract` function requires a `schema` that defines the expected + structure of the extracted data. + For example, if you are extracting module details, the schema + should specify the fields and types, such as: const data = await page.extract({{ - instruction: "extract the title, description, and link of the quickstart", + instruction: "extract the title, description, and + link of the quickstart", schema: z.object({{ title: z.string(), description: z.string(), link: z.string() }}) }}); - - IMPORTANT: Stagehand / OpenAI extraction requires that all top-level schemas be an 'object'. - Therefore, if you want to extract an array of items, wrap it in a top-level object with a - field like 'results' or 'items'. For example: + - IMPORTANT: Stagehand / OpenAI extraction requires that all top-level + schemas be an 'object'. + Therefore, if you want to extract an array of items, wrap it in a + top-level object with afield like 'results' or 'items'. For example: // CORRECT: schema: z.object({{ @@ -90,91 +109,109 @@ def __init__(self, high_level_task: str): }})) So always wrap arrays in an object at the top level of your 'schema'. - - Do NOT combine multiple actions into one instruction—each action must be atomic. + - Do NOT combine multiple actions into one instruction—each action + must be atomic. - Keep the script concise, and use no more than one action per line. - - Avoid any advanced planning—just deliver direct, concrete instructions based on the task. + - Avoid any advanced planning—just deliver direct, concrete + instructions based on the task. - IMPORTANT: - ```javascript is NOT allowed in your response, even in the beginning. - - Do not include backticks or a "javascript" label in your response. Just return the - plain JavaScript code. + - Do not include backticks or a "javascript" label in your response. + Just return the plain JavaScript code. - First go to the link in the state. - If the url is google.com, then search for the term you want. - Add a small wait ight after searching on Google, do something like - await page.act({{ action: "Wait a few seconds for results to load." }}); Then do the extraction. - (Stagehand supports a small “Wait for N seconds” or “Wait for results to appear” approach using + (Stagehand supports a small “Wait for N seconds” or “Wait for + results to appear” approach using act({{ action: "Wait ..." }}).) - Address specific shortcomings highlighted in the feedback, such as: - Missed steps. - Insufficient exploration of page elements. - Incomplete or incorrect data extraction. - Follow actionable suggestions to refine and expand your approach. - - Your plans should focus on exploring different elements on the page, especially those likely - to yield useful data or advance the task. - - Include actions such as clicking buttons, links, toggles, and interacting with dropdowns - or search bars. - - Aim to uncover new information or pathways that could help solve the task. + - Your plans should focus on exploring different elements on the page, + especially those likely to yield useful data or advance the task. + - Include actions such as clicking buttons, links, toggles, and + interacting with dropdowns or search bars. + - Aim to uncover new information or pathways that could help solve + the task. - Then proceed with rest of the plan. - - If a search yields no results, do not stop. Try alternative search terms or synonyms. - - If the page says “No results found,” instruct Stagehand to search for synonyms or check for - similar items. - - If the plan is stuck, propose an alternative approach, such as returning to Google and - refining the query with additional keywords. - - If initial attempts fail or yield incomplete data, refine or expand your approach using - the feedback from the calling agent or from the search results. - - Use fallback steps like “try synonyms,” “use partial matches,” or “check for recommended - articles” if the direct query fails. - - You can go back to a previous plan if you think that was leading you in the correct direction. - - Keep scope of the plan limited to solving the high level task of {high_level_task}. + - If a search yields no results, do not stop. Try alternative search + terms or synonyms. + - If the page says “No results found,” instruct Stagehand to search + for synonyms or check for similar items. + - If the plan is stuck, propose an alternative approach, such as + returning to Google and refining the query with additional keywords. + - If initial attempts fail or yield incomplete data, refine + or expand your approach using the feedback from the calling + agent or from the search results. + - Use fallback steps like “try synonyms,” “use partial matches, + ” or “check for recommended articles” if the direct query fails. + - You can go back to a previous plan if you think that was + leading you in the correct direction. + - Keep scope of the plan limited to solving the high level + task of {high_level_task}. You are a web automation assistant using Stagehand. Your role is to: - Visit pages or perform searches. - Extract data from the page. - If needed, filter or process that data locally in your snippet. - - Optionally, re-visit or do additional atomic actions based on the new info. + - Optionally, re-visit or do additional atomic actions based + on the new info. - Print final results as JSON so the calling process can read them. Important guidelines: - Atomic Stagehand instructions only. For example: await page.goto("https://www.example.com"); await page.act({{ action: "Click on the Login button."}}); - const data = await page.extract({{ instruction: "...", schema: z.object({ ... }) }}); + const data = await page.extract({{ instruction: "...", + schema: z.object({ ... }) }}); const actions = await page.observe(); - - Do not combine multiple steps into one act() instruction—each line should be one discrete - action. + - Do not combine multiple steps into one act() instruction—each line + should be one discrete action. - Broad-to-narrow extraction pattern: - Broad extraction: “Extract all text, headings, or visible links.” - Local filter: Evaluate which items or links are relevant. - If you find a relevant link or portion, navigate or click. - - Second extraction: Now specifically request the data you actually need (like “Extract all the - - bubble metrics,” or “Extract the largest bubble’s label,” etc.). - - If the data is behind multiple clicks or expansions, continue with atomic steps (act() to + - Second extraction: Now specifically request the data you + actually need (like “Extract all the + - bubble metrics,” or “Extract the largest bubble's label,” etc.). + - If the data is behind multiple clicks or expansions, continue with + atomic steps (act() to click or scroll) until you see the data. Then extract again. - - If you cannot find what you need, log that “No relevant data found” and end gracefully, or - try an alternate approach (like refining your search). + - If you cannot find what you need, log that “No relevant data found” + and end gracefully, or try an alternate approach + (like refining your search). - This approach is generic and not tied to one site. It works as follows: - “Load a page or perform a search” → atomic act({{ action: "Search for 'some phrase'" }}) - or goto(...). + “Load a page or perform a search” → + atomic act({{ action: "Search for 'some phrase'" }}) or goto(...). “Extract everything” with a broad instruction + broad schema. “Filter locally in JS,” if needed, to pick the relevant link. “Goto or click” to expand or open that detail. “Extract again” with a narrower instruction + schema. “Print final result.” - Keep your snippet’s instructions short and direct. Provide one action per act(). + Keep your snippet's instructions short and direct. + Provide one action per act(). For extractions, use one extraction call for each chunk. Remember: - Use observe() to see potential clickable items or possible actions. - Use extract() with a carefully chosen instruction and schema to gather data. - If you need more data, do another extraction. + - Use observe() to see potential clickable items or possible actions. + - Use extract() with a carefully chosen instruction and schema + to gather data. + - If you need more data, do another extraction. - Incorporate feedback from previous iterations to improve the plan. - Based on this high level task: "{high_level_task}", generate a Stagehand JavaScript snippet + Based on this high level task: "{high_level_task}", generate a Stagehand + JavaScript snippet with step-by-step instructions. - IMPORTANT: - 1. You are a Low-Level Planner that writes a Stagehand JavaScript snippet. - Remember to produce the final result as a JSON object called 'updated_state', which the + 1. You are a Low-Level Planner that writes a Stagehand + JavaScript snippet. + Remember to produce the final result as a JSON object called + 'updated_state', which the system will read as: {{ @@ -187,8 +224,10 @@ def __init__(self, high_level_task: str): }} }} - The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. - At the end of your snippet, always do the final extraction to fill these fields in a + The the calling agent will provide you feedback on what to inlcude + in the 'updated_state'. + At the end of your snippet, always do the final extraction to fill + these fields in a variable called 'updated_state'. For example: const updated_state = {{ @@ -201,27 +240,32 @@ def __init__(self, high_level_task: str): }} }}; - 2. Print or log the final data in a JSON-friendly format so the pipeline can read it. + 2. Print or log the final data in a JSON-friendly format so the + pipeline can read it. For example: console.log("Final updated_state:", updated_state); - 3. If you cannot find the necessary info after multiple steps, log "No relevant data found. + 3. If you cannot find the necessary info after multiple steps, + log "No relevant data found. Attempt an alternative approach or refine the search." 4. Keep your snippet concise. **Examples of valid atomic instructions** (one per line): await page.goto("https://www.example.com"); - await page.act({{ action: "Click the Sign In button." }}); const data = await + await page.act({{ action: "Click the Sign In button." }}); + const data = await page.extract({{ instruction: "Extract all text on page.", schema: z.object({{ text: z.string() }}) }}); - **Do not** wrap multiple steps into a single act call. For instance, don’t do: - await page.act({{ action: "Click the sign in button and fill the form." }}); + **Do not** wrap multiple steps into a single act call. + For instance, don't do: + await page.act({{action: "Click the sign in button and fill the form."}}); That should be two lines: one for the click, one for the fill. - Please produce the Stagehand JavaScript snippet now, following all of the above guidelines, + Please produce the Stagehand JavaScript snippet now, following all + of the above guidelines, always ending with the final extraction snippet for `updated_state`. """ ) @@ -229,8 +273,8 @@ def __init__(self, high_level_task: str): class WebToolkit(BaseToolkit): r"""A class representing a toolkit for web use. - - This class provides methods for interacting with websites by writing direct JavaScript code + This class provides methods for interacting with websites by + writing direct JavaScript code via tools like Stagehand. """ @@ -238,7 +282,7 @@ def __init__( self, model_platform=ModelPlatformType.DEFAULT, model_type=ModelType.DEFAULT, - model_config_dict=ChatGPTConfig(temperature=0.0).as_dict(), + model_config_dict=_DEFAULT_CHATGPT_CONFIG_DICT, headless_mode=True, ): self.model_platform = model_platform @@ -258,8 +302,8 @@ def __init__( role_name="Stagehand Agent", role_type=RoleType.ASSISTANT, meta_dict=None, - content="""You are an intelligent assistant that searches the web to answer the - given question.""", + content="""You are an intelligent assistant that searches + the web to answer the given question.""", ), self.model, ) @@ -274,7 +318,8 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: task_prompt (str): Description of the task to automate. Returns: - Dict[str, Any]: JSON result from the Stagehand script, or an error. + Dict[str, Any]: JSON result from the Stagehand script, + or an error. """ # Generate Stagehand code @@ -289,7 +334,8 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: except json.JSONDecodeError: return { "status": "error", - "message": f"No valid JSON output. Last script line:\n{result_str}", + "message": f"""No valid JSON output. + Last script line:\n{result_str}""", } # @@ -318,8 +364,8 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" - Internal method that executes the Stagehand code under Node.js and returns - the final JSON line from stdout. + Internal method that executes the Stagehand code under + Node.js and returns the final JSON line from stdout. Args: js_code (str): The JavaScript code to execute. @@ -334,7 +380,8 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: const z = require('zod'); (async () => {{ - const stagehand = new Stagehand({{ headless: {"true" if self.headless_mode else "false"} }}); + const stagehand = new Stagehand({{ headless: {"true" if + self.headless_mode else "false"} }}); await stagehand.init(); const page = stagehand.page; console.log("Starting Stagehand automation..."); From ee991b1fad831663fa0bdc6c4586ee3cebe82dcb Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 03:38:20 -0600 Subject: [PATCH 17/43] feat: example for webtoolkit --- examples/toolkits/web_toolkit.py | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 examples/toolkits/web_toolkit.py diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py new file mode 100644 index 0000000000..abf60f4271 --- /dev/null +++ b/examples/toolkits/web_toolkit.py @@ -0,0 +1,45 @@ +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= + +from camel.toolkits.web_toolkit import WebToolkit +from camel.agents import ChatAgent +from camel.toolkits.function_tool import FunctionTool +from camel.models import ModelFactory +from camel.types import ModelPlatformType, ModelType + +# Initialize the toolkit +toolkit = WebToolkit(headless_mode=False) + +stagehand_tool = FunctionTool(toolkit.stagehand_tool) + +model = ModelFactory.create( + model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI +) + +assistant_sys_msg = """You are a helpful assistant capable of performing web interactions +and answering questions. +When appropriate, use the available tools to automate web tasks and retrieve information.""" + +# Create a ChatAgent with just this single tool, wrapped in a list +tool_agent = ChatAgent( + assistant_sys_msg, + model=model, + tools=[stagehand_tool], +) + +# Interact with the agent +prompt = "What is the most visited website?" +injection_for_tool_use = "Please use the web tool to find the answer." +response = tool_agent.step(prompt + injection_for_tool_use) +print(response.msgs[0].content) From e1afcf2bc96a9aee2c64a9531365204b730d91a4 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 03:46:42 -0600 Subject: [PATCH 18/43] fix: unused import and E501 linting error --- camel/interpreters/subprocess_interpreter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index fa2cd310c8..9dd54d4ec1 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -23,7 +23,6 @@ from camel.interpreters.base import BaseInterpreter from camel.interpreters.interpreter_error import InterpreterError from camel.logger import get_logger -import os logger = get_logger(__name__) @@ -149,7 +148,8 @@ def run( if self.require_confirm: logger.info( - f"The following {code_type} code will run on your " "computer: {code}" + f"""The following {code_type} code will run on your + computer: {code}""" ) while True: choice = input("Running code? [Y/n]:").lower() From c837ef0a6c1288862fa39519d77995679f6f6b53 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 03:47:01 -0600 Subject: [PATCH 19/43] fix: E501 linting error --- examples/toolkits/web_toolkit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index abf60f4271..7740173e01 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -27,9 +27,9 @@ model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI ) -assistant_sys_msg = """You are a helpful assistant capable of performing web interactions -and answering questions. -When appropriate, use the available tools to automate web tasks and retrieve information.""" +assistant_sys_msg = """You are a helpful assistant capable of performing web +interactions and answering questions. When appropriate, use the available +tools to automate web tasks and retrieve information.""" # Create a ChatAgent with just this single tool, wrapped in a list tool_agent = ChatAgent( From 281306775cb135995f942d7cdc2c3b4ad03d5647 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 03:53:02 -0600 Subject: [PATCH 20/43] fx: linting error E501 --- camel/interpreters/subprocess_interpreter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index 9dd54d4ec1..8519644133 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -194,4 +194,5 @@ def supported_code_types(self) -> List[str]: def update_action_space(self, action_space: Dict[str, Any]) -> None: r"""Updates action space for *python* interpreter""" - raise RuntimeError("SubprocessInterpreter doesn't support " "`action_space`.") + raise RuntimeError("SubprocessInterpreter doesn't support " + "`action_space`.") From 61851e63a663ba1bee489c55913b083e58acbb22 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 27 Jan 2025 04:02:27 -0600 Subject: [PATCH 21/43] fix: sort imports --- examples/toolkits/web_toolkit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index 7740173e01..ea5905d9af 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -12,10 +12,10 @@ # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= -from camel.toolkits.web_toolkit import WebToolkit from camel.agents import ChatAgent -from camel.toolkits.function_tool import FunctionTool from camel.models import ModelFactory +from camel.toolkits.function_tool import FunctionTool +from camel.toolkits.web_toolkit import WebToolkit from camel.types import ModelPlatformType, ModelType # Initialize the toolkit From 64e03b2ca8bf9c82ba2e49672f7e0d950b7ea40a Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Sat, 1 Feb 2025 12:32:21 +0530 Subject: [PATCH 22/43] fix: pre-commit --- camel/interpreters/subprocess_interpreter.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/camel/interpreters/subprocess_interpreter.py b/camel/interpreters/subprocess_interpreter.py index 8519644133..910b9e7e44 100644 --- a/camel/interpreters/subprocess_interpreter.py +++ b/camel/interpreters/subprocess_interpreter.py @@ -104,7 +104,9 @@ def run_file( raise RuntimeError(f"{file} is not a file.") code_type = self._check_code_type(code_type) cmd = shlex.split( - self._CODE_EXECUTE_CMD_MAPPING[code_type].format(file_name=str(file)) + self._CODE_EXECUTE_CMD_MAPPING[code_type].format( + file_name=str(file) + ) ) proc = subprocess.Popen( @@ -194,5 +196,6 @@ def supported_code_types(self) -> List[str]: def update_action_space(self, action_space: Dict[str, Any]) -> None: r"""Updates action space for *python* interpreter""" - raise RuntimeError("SubprocessInterpreter doesn't support " - "`action_space`.") + raise RuntimeError( + "SubprocessInterpreter doesn't support " "`action_space`." + ) From 4e726e8284fada1032ee13ee7cf8f271e0fe2c83 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 3 Feb 2025 11:51:05 +0530 Subject: [PATCH 23/43] fix: merged master --- poetry.lock | 403 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 3 +- 2 files changed, 400 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index a359ddd00b..8eed512a7c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4355,11 +4355,21 @@ dev = ["black", "flake8", "isort", "pre-commit", "pyproject-flake8"] doc = ["myst-parser", "sphinx", "sphinx-book-theme"] test = ["coverage", "pytest", "pytest-cov"] +[[package]] +name = "linkup" +version = "0.1.3" +description = "Making mappings operable." +optional = false +python-versions = "*" +files = [ + {file = "linkup-0.1.3.tar.gz", hash = "sha256:b5fc62d827797d78d9b08bfa068f1e455f4428cf94d2f359a815f9474228ad3c"}, +] + [[package]] name = "linkup-sdk" version = "0.2.2" description = "A Python Client SDK for the Linkup API" -optional = true +optional = false python-versions = ">=3.9" files = [ {file = "linkup_sdk-0.2.2-py3-none-any.whl", hash = "sha256:23b15e950e2c2023a5cf3c5c7c0188ed3f38889dd7b2e61e08494a953e30c31f"}, @@ -5510,6 +5520,17 @@ files = [ {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.1.3.1" +description = "CUBLAS native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, +] + [[package]] name = "nvidia-cublas-cu12" version = "12.4.5.8" @@ -5522,6 +5543,17 @@ files = [ {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, ] +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.1.105" +description = "CUDA profiling tools runtime libs." +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, +] + [[package]] name = "nvidia-cuda-cupti-cu12" version = "12.4.127" @@ -5534,6 +5566,17 @@ files = [ {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, ] +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.1.105" +description = "NVRTC native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, +] + [[package]] name = "nvidia-cuda-nvrtc-cu12" version = "12.4.127" @@ -5546,6 +5589,17 @@ files = [ {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, ] +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.1.105" +description = "CUDA Runtime native Libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, +] + [[package]] name = "nvidia-cuda-runtime-cu12" version = "12.4.127" @@ -5558,6 +5612,19 @@ files = [ {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, ] +[[package]] +name = "nvidia-cudnn-cu12" +version = "8.9.2.26" +description = "cuDNN runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + [[package]] name = "nvidia-cudnn-cu12" version = "9.1.0.70" @@ -5572,6 +5639,17 @@ files = [ [package.dependencies] nvidia-cublas-cu12 = "*" +[[package]] +name = "nvidia-cufft-cu12" +version = "11.0.2.54" +description = "CUFFT native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, +] + [[package]] name = "nvidia-cufft-cu12" version = "11.2.1.3" @@ -5587,6 +5665,17 @@ files = [ [package.dependencies] nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.2.106" +description = "CURAND native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, +] + [[package]] name = "nvidia-curand-cu12" version = "10.3.5.147" @@ -5599,6 +5688,22 @@ files = [ {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, ] +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.4.5.107" +description = "CUDA solver native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-cusolver-cu12" version = "11.6.1.9" @@ -5616,6 +5721,20 @@ nvidia-cublas-cu12 = "*" nvidia-cusparse-cu12 = "*" nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.1.0.106" +description = "CUSPARSE native runtime libraries" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + [[package]] name = "nvidia-cusparse-cu12" version = "12.3.1.170" @@ -5631,6 +5750,27 @@ files = [ [package.dependencies] nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-nccl-cu12" +version = "2.19.3" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d"}, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.20.5" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01"}, + {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56"}, +] + [[package]] name = "nvidia-nccl-cu12" version = "2.21.5" @@ -5653,6 +5793,17 @@ files = [ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, ] +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.1.105" +description = "NVIDIA Tools Extension" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, +] + [[package]] name = "nvidia-nvtx-cu12" version = "12.4.127" @@ -6370,8 +6521,8 @@ files = [ numpy = [ {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, ] [[package]] @@ -6849,6 +7000,10 @@ requests = ">=2.31.0,<3.0.0" scipy = ">=1.9.0,<2.0.0" sqlalchemy = ">=1.4,<3" sqlglot = {version = ">=25.0.3,<26.0.0", extras = ["rs"]} +torch = [ + {version = "2.2.0", markers = "sys_platform == \"darwin\" and platform_machine == \"x86_64\""}, + {version = "2.4.1", markers = "sys_platform != \"darwin\""}, +] [package.extras] bedrock = ["boto3 (>=1.34.59)"] @@ -10814,6 +10969,64 @@ files = [ {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] +[[package]] +name = "torch" +version = "2.2.0" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = true +python-versions = ">=3.8.0" +files = [ + {file = "torch-2.2.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d366158d6503a3447e67f8c0ad1328d54e6c181d88572d688a625fac61b13a97"}, + {file = "torch-2.2.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:707f2f80402981e9f90d0038d7d481678586251e6642a7a6ef67fc93511cb446"}, + {file = "torch-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:15c8f0a105c66b28496092fca1520346082e734095f8eaf47b5786bac24b8a31"}, + {file = "torch-2.2.0-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:0ca4df4b728515ad009b79f5107b00bcb2c63dc202d991412b9eb3b6a4f24349"}, + {file = "torch-2.2.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:3d3eea2d5969b9a1c9401429ca79efc668120314d443d3463edc3289d7f003c7"}, + {file = "torch-2.2.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:0d1c580e379c0d48f0f0a08ea28d8e373295aa254de4f9ad0631f9ed8bc04c24"}, + {file = "torch-2.2.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9328e3c1ce628a281d2707526b4d1080eae7c4afab4f81cea75bde1f9441dc78"}, + {file = "torch-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:03c8e660907ac1b8ee07f6d929c4e15cd95be2fb764368799cca02c725a212b8"}, + {file = "torch-2.2.0-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:da0cefe7f84ece3e3b56c11c773b59d1cb2c0fd83ddf6b5f7f1fd1a987b15c3e"}, + {file = "torch-2.2.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:f81d23227034221a4a4ff8ef24cc6cec7901edd98d9e64e32822778ff01be85e"}, + {file = "torch-2.2.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:dcbfb2192ac41ca93c756ebe9e2af29df0a4c14ee0e7a0dd78f82c67a63d91d4"}, + {file = "torch-2.2.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:9eeb42971619e24392c9088b5b6d387d896e267889d41d267b1fec334f5227c5"}, + {file = "torch-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:c718b2ca69a6cac28baa36d86d8c0ec708b102cebd1ceb1b6488e404cd9be1d1"}, + {file = "torch-2.2.0-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:f11d18fceb4f9ecb1ac680dde7c463c120ed29056225d75469c19637e9f98d12"}, + {file = "torch-2.2.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:ee1da852bfd4a7e674135a446d6074c2da7194c1b08549e31eae0b3138c6b4d2"}, + {file = "torch-2.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0d819399819d0862268ac531cf12a501c253007df4f9e6709ede8a0148f1a7b8"}, + {file = "torch-2.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:08f53ccc38c49d839bc703ea1b20769cc8a429e0c4b20b56921a9f64949bf325"}, + {file = "torch-2.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:93bffe3779965a71dab25fc29787538c37c5d54298fd2f2369e372b6fb137d41"}, + {file = "torch-2.2.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:c17ec323da778efe8dad49d8fb534381479ca37af1bfc58efdbb8607a9d263a3"}, + {file = "torch-2.2.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:c02685118008834e878f676f81eab3a952b7936fa31f474ef8a5ff4b5c78b36d"}, + {file = "torch-2.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d9f39d6f53cec240a0e3baa82cb697593340f9d4554cee6d3d6ca07925c2fac0"}, + {file = "torch-2.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:51770c065206250dc1222ea7c0eff3f88ab317d3e931cca2aee461b85fbc2472"}, + {file = "torch-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:008e4c6ad703de55af760c73bf937ecdd61a109f9b08f2bbb9c17e7c7017f194"}, + {file = "torch-2.2.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:de8680472dd14e316f42ceef2a18a301461a9058cd6e99a1f1b20f78f11412f1"}, + {file = "torch-2.2.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:99e1dcecb488e3fd25bcaac56e48cdb3539842904bdc8588b0b255fde03a254c"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +jinja2 = "*" +networkx = "*" +nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +sympy = "*" +triton = {version = "2.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +typing-extensions = ">=4.8.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.9.1)"] + [[package]] name = "torch" version = "2.2.1" @@ -10860,6 +11073,60 @@ typing-extensions = ">=4.8.0" opt-einsum = ["opt-einsum (>=3.3)"] optree = ["optree (>=0.9.1)"] +[[package]] +name = "torch" +version = "2.4.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = true +python-versions = ">=3.8.0" +files = [ + {file = "torch-2.4.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:362f82e23a4cd46341daabb76fba08f04cd646df9bfaf5da50af97cb60ca4971"}, + {file = "torch-2.4.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:e8ac1985c3ff0f60d85b991954cfc2cc25f79c84545aead422763148ed2759e3"}, + {file = "torch-2.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:91e326e2ccfb1496e3bee58f70ef605aeb27bd26be07ba64f37dcaac3d070ada"}, + {file = "torch-2.4.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:d36a8ef100f5bff3e9c3cea934b9e0d7ea277cb8210c7152d34a9a6c5830eadd"}, + {file = "torch-2.4.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:0b5f88afdfa05a335d80351e3cea57d38e578c8689f751d35e0ff36bce872113"}, + {file = "torch-2.4.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:ef503165f2341942bfdf2bd520152f19540d0c0e34961232f134dc59ad435be8"}, + {file = "torch-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:092e7c2280c860eff762ac08c4bdcd53d701677851670695e0c22d6d345b269c"}, + {file = "torch-2.4.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:ddddbd8b066e743934a4200b3d54267a46db02106876d21cf31f7da7a96f98ea"}, + {file = "torch-2.4.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:fdc4fe11db3eb93c1115d3e973a27ac7c1a8318af8934ffa36b0370efe28e042"}, + {file = "torch-2.4.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:18835374f599207a9e82c262153c20ddf42ea49bc76b6eadad8e5f49729f6e4d"}, + {file = "torch-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:ebea70ff30544fc021d441ce6b219a88b67524f01170b1c538d7d3ebb5e7f56c"}, + {file = "torch-2.4.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:72b484d5b6cec1a735bf3fa5a1c4883d01748698c5e9cfdbeb4ffab7c7987e0d"}, + {file = "torch-2.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c99e1db4bf0c5347107845d715b4aa1097e601bdc36343d758963055e9599d93"}, + {file = "torch-2.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b57f07e92858db78c5b72857b4f0b33a65b00dc5d68e7948a8494b0314efb880"}, + {file = "torch-2.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:f18197f3f7c15cde2115892b64f17c80dbf01ed72b008020e7da339902742cf6"}, + {file = "torch-2.4.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:5fc1d4d7ed265ef853579caf272686d1ed87cebdcd04f2a498f800ffc53dab71"}, + {file = "torch-2.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:40f6d3fe3bae74efcf08cb7f8295eaddd8a838ce89e9d26929d4edd6d5e4329d"}, + {file = "torch-2.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c9299c16c9743001ecef515536ac45900247f4338ecdf70746f2461f9e4831db"}, + {file = "torch-2.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:6bce130f2cd2d52ba4e2c6ada461808de7e5eccbac692525337cfb4c19421846"}, + {file = "torch-2.4.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:a38de2803ee6050309aac032676536c3d3b6a9804248537e38e098d0e14817ec"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +jinja2 = "*" +networkx = "*" +nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.1.0.70", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.20.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +setuptools = "*" +sympy = "*" +triton = {version = "3.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.13\""} +typing-extensions = ">=4.8.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.11.0)"] + [[package]] name = "torch" version = "2.5.1" @@ -10912,6 +11179,49 @@ typing-extensions = ">=4.8.0" opt-einsum = ["opt-einsum (>=3.3)"] optree = ["optree (>=0.12.0)"] +[[package]] +name = "torchvision" +version = "0.17.0" +description = "image and video datasets and models for torch deep learning" +optional = true +python-versions = ">=3.8" +files = [ + {file = "torchvision-0.17.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:153882cd8ff8e3dbef5c5054fdd15df64e85420546805a90c0b2221f2f119c4a"}, + {file = "torchvision-0.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c55c2f86e3f3a21ddd92739a972366244e9b17916e836ec47167b0a0c083c65f"}, + {file = "torchvision-0.17.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:605950cdcefe6c5aef85709ade17b1525bcf171e122cce1df09e666d96525b90"}, + {file = "torchvision-0.17.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3d86c212fc6379e9bec3ac647d062e34c2cf36c26b98840b66573eb9fbe1f1d9"}, + {file = "torchvision-0.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:71b314813faf13cecb09a4a635b5e4b274e8df0b1921681038d491c529555bb6"}, + {file = "torchvision-0.17.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:10d276821f115fb369e6cf1f1b77b2cca60cda12cbb39a41513a9d3d0f2a93ae"}, + {file = "torchvision-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3eef2daddadb5c21e802e0550dd7e3ee3d98c430f4aed212ae3ba0358558be1"}, + {file = "torchvision-0.17.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:acc0d098ab8c295a750f0218bf5bf7bfc2f2c21f9c2fe3fc30b695cd94f4c759"}, + {file = "torchvision-0.17.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3d2e9552d72e4037f2db6f7d97989a2e2f95763aa1861963a3faf521bb1610c4"}, + {file = "torchvision-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8e542cf71e1294fcb5635038eae6702df543dc90706f0836ec80e75efc511fc"}, + {file = "torchvision-0.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:816ae1a4506b1cb0f638e1827cae7ab768c731369ab23e86839f177926197143"}, + {file = "torchvision-0.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be39874c239215a39b3c431c7016501f1a45bfbbebf2fe8e11d8339b5ea23bca"}, + {file = "torchvision-0.17.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:8fe14d580557aef2c45dd462c069ff936b6507b215c4b496f30973ae8cff917d"}, + {file = "torchvision-0.17.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:4608ba3246c45c968ede40e7640e4eed64556210faa154cf1ffccb1cadabe445"}, + {file = "torchvision-0.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:b755d6d3e021239d2408bf3794d0d3dcffbc629f1fd808c43d8b346045a098c4"}, + {file = "torchvision-0.17.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:870d7cda57420e44d20eb07bfe37bf5344a06434a7a6195b4c7f3dd55838587d"}, + {file = "torchvision-0.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:477f6e64a9d798c0f5adefc300acc220da6f17ef5c1e110d20108f66554fee4d"}, + {file = "torchvision-0.17.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a54a15bd6f3dbb04ebd36c5a87530b2e090ee4b9b15eb89eda558ab3e50396a0"}, + {file = "torchvision-0.17.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e041ce3336364413bab051a3966d884bab25c200f98ca8a065f0abe758c3005e"}, + {file = "torchvision-0.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:7887f767670c72aa20f5237042d0ca1462da18f66a3ea8c36b6ba67ce26b82fc"}, + {file = "torchvision-0.17.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b1ced438b81ef662a71c8c81debaf0c80455b35b811ca55a4c3c593d721b560a"}, + {file = "torchvision-0.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b53569c52bd4bd1176a1e49d8ea55883bcf57e1614cb97e2e8ce372768299b70"}, + {file = "torchvision-0.17.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7f373507afcd9022ebd9f50b31da8dbac1ea6783ffb77d1f1ab8806425c0a83b"}, + {file = "torchvision-0.17.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:085251ab36340206dc7e1be59a15fa5e307d45ccd66889f5d7bf1ba5e7ecdc57"}, + {file = "torchvision-0.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4c0d4c0af58af2752aad235150bd794d0f324e6eeac5cd13c440bda5dce622d3"}, +] + +[package.dependencies] +numpy = "*" +pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" +requests = "*" +torch = "2.2.0" + +[package.extras] +scipy = ["scipy"] + [[package]] name = "torchvision" version = "0.17.1" @@ -10954,6 +11264,44 @@ torch = "2.2.1" [package.extras] scipy = ["scipy"] +[[package]] +name = "torchvision" +version = "0.19.1" +description = "image and video datasets and models for torch deep learning" +optional = true +python-versions = ">=3.8" +files = [ + {file = "torchvision-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:54e8513099e6f586356c70f809d34f391af71ad182fe071cc328a28af2c40608"}, + {file = "torchvision-0.19.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:20a1f5e02bfdad7714e55fa3fa698347c11d829fa65e11e5a84df07d93350eed"}, + {file = "torchvision-0.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:7b063116164be52fc6deb4762de7f8c90bfa3a65f8d5caf17f8e2d5aadc75a04"}, + {file = "torchvision-0.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:f40b6acabfa886da1bc3768f47679c61feee6bde90deb979d9f300df8c8a0145"}, + {file = "torchvision-0.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:40514282b4896d62765b8e26d7091c32e17c35817d00ec4be2362ea3ba3d1787"}, + {file = "torchvision-0.19.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:5a91be061ae5d6d5b95e833b93e57ca4d3c56c5a57444dd15da2e3e7fba96050"}, + {file = "torchvision-0.19.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d71a6a6fe3a5281ca3487d4c56ad4aad20ff70f82f1d7c79bcb6e7b0c2af00c8"}, + {file = "torchvision-0.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:70dea324174f5e9981b68e4b7cd524512c106ba64aedef560a86a0bbf2fbf62c"}, + {file = "torchvision-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27ece277ff0f6cdc7fed0627279c632dcb2e58187da771eca24b0fbcf3f8590d"}, + {file = "torchvision-0.19.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:c659ff92a61f188a1a7baef2850f3c0b6c85685447453c03d0e645ba8f1dcc1c"}, + {file = "torchvision-0.19.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:c07bf43c2a145d792ecd9d0503d6c73577147ece508d45600d8aac77e4cdfcf9"}, + {file = "torchvision-0.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b4283d283675556bb0eae31d29996f53861b17cbdcdf3509e6bc050414ac9289"}, + {file = "torchvision-0.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c4e4f5b24ea6b087b02ed492ab1e21bba3352c4577e2def14248cfc60732338"}, + {file = "torchvision-0.19.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9281d63ead929bb19143731154cd1d8bf0b5e9873dff8578a40e90a6bec3c6fa"}, + {file = "torchvision-0.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:4d10bc9083c4d5fadd7edd7b729700a7be48dab4f62278df3bc73fa48e48a155"}, + {file = "torchvision-0.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:ccf085ef1824fb9e16f1901285bf89c298c62dfd93267a39e8ee42c71255242f"}, + {file = "torchvision-0.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:731f434d91586769e255b5d70ed1a4457e0a1394a95f4aacf0e1e7e21f80c098"}, + {file = "torchvision-0.19.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:febe4f14d4afcb47cc861d8be7760ab6a123cd0817f97faf5771488cb6aa90f4"}, + {file = "torchvision-0.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e328309b8670a2e889b2fe76a1c2744a099c11c984da9a822357bd9debd699a5"}, + {file = "torchvision-0.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:6616f12e00a22e7f3fedbd0fccb0804c05e8fe22871668f10eae65cf3f283614"}, +] + +[package.dependencies] +numpy = "*" +pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" +torch = "2.4.1" + +[package.extras] +gdown = ["gdown (>=4.7.3)"] +scipy = ["scipy"] + [[package]] name = "torchvision" version = "0.20.1" @@ -11223,6 +11571,51 @@ exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} trio = ">=0.11" wsproto = ">=0.14" +[[package]] +name = "triton" +version = "2.2.0" +description = "A language and compiler for custom Deep Learning operations" +optional = true +python-versions = "*" +files = [ + {file = "triton-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2294514340cfe4e8f4f9e5c66c702744c4a117d25e618bd08469d0bfed1e2e5"}, + {file = "triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0"}, + {file = "triton-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af58716e721460a61886668b205963dc4d1e4ac20508cc3f623aef0d70283d5"}, + {file = "triton-2.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8fe46d3ab94a8103e291bd44c741cc294b91d1d81c1a2888254cbf7ff846dab"}, + {file = "triton-2.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ce26093e539d727e7cf6f6f0d932b1ab0574dc02567e684377630d86723ace"}, + {file = "triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:227cc6f357c5efcb357f3867ac2a8e7ecea2298cd4606a8ba1e931d1d5a947df"}, +] + +[package.dependencies] +filelock = "*" + +[package.extras] +build = ["cmake (>=3.20)", "lit"] +tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"] +tutorials = ["matplotlib", "pandas", "tabulate", "torch"] + +[[package]] +name = "triton" +version = "3.0.0" +description = "A language and compiler for custom Deep Learning operations" +optional = true +python-versions = "*" +files = [ + {file = "triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a"}, + {file = "triton-3.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ce8520437c602fb633f1324cc3871c47bee3b67acf9756c1a66309b60e3216c"}, + {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, + {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, + {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, +] + +[package.dependencies] +filelock = "*" + +[package.extras] +build = ["cmake (>=3.20)", "lit"] +tests = ["autopep8", "flake8", "isort", "llnl-hatchet", "numpy", "pytest", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + [[package]] name = "triton" version = "3.1.0" @@ -12551,7 +12944,7 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\ cffi = ["cffi (>=1.11)"] [extras] -all = ["PyMuPDF", "accelerate", "agentops", "aiosqlite", "anthropic", "apify_client", "arxiv", "arxiv2text", "asknews", "azure-storage-blob", "beautifulsoup4", "botocore", "cohere", "dappier", "datacommons", "datacommons_pandas", "datasets", "diffusers", "discord.py", "docker", "docx2txt", "duckduckgo-search", "e2b-code-interpreter", "ffmpeg-python", "firecrawl-py", "fish-audio-sdk", "google-cloud-storage", "google-generativeai", "googlemaps", "imageio", "ipykernel", "jupyter_client", "linkup-sdk", "litellm", "mistralai", "nebula3-python", "neo4j", "newspaper3k", "notion-client", "openapi-spec-validator", "openbb", "opencv-python", "outlines", "pandas", "pandasai", "pdfplumber", "pillow", "prance", "praw", "pyTelegramBotAPI", "pydub", "pygithub", "pymilvus", "pyowm", "qdrant-client", "ragas", "rank-bm25", "redis", "reka-api", "requests_oauthlib", "rouge", "scholarly", "sentence-transformers", "sentencepiece", "sglang", "slack-bolt", "slack-sdk", "soundfile", "stripe", "tavily-python", "textblob", "torch", "torch", "transformers", "tree-sitter", "tree-sitter-python", "unstructured", "wikipedia", "wolframalpha", "yt-dlp"] +all = ["PyMuPDF", "accelerate", "agentops", "aiosqlite", "anthropic", "apify_client", "arxiv", "arxiv2text", "asknews", "azure-storage-blob", "beautifulsoup4", "botocore", "cohere", "dappier", "datacommons", "datacommons_pandas", "datasets", "diffusers", "discord.py", "docker", "docx2txt", "duckduckgo-search", "e2b-code-interpreter", "ffmpeg-python", "firecrawl-py", "fish-audio-sdk", "google-cloud-storage", "google-generativeai", "googlemaps", "imageio", "ipykernel", "jupyter_client", "litellm", "mistralai", "nebula3-python", "neo4j", "newspaper3k", "notion-client", "openapi-spec-validator", "openbb", "opencv-python", "outlines", "pandas", "pandasai", "pdfplumber", "pillow", "prance", "praw", "pyTelegramBotAPI", "pydub", "pygithub", "pymilvus", "pyowm", "qdrant-client", "ragas", "rank-bm25", "redis", "reka-api", "requests_oauthlib", "rouge", "scholarly", "sentence-transformers", "sentencepiece", "sglang", "slack-bolt", "slack-sdk", "soundfile", "stripe", "tavily-python", "textblob", "torch", "torch", "transformers", "tree-sitter", "tree-sitter-python", "unstructured", "wikipedia", "wolframalpha", "yt-dlp"] communication-tools = ["discord.py", "notion-client", "praw", "pyTelegramBotAPI", "pygithub", "slack-bolt", "slack-sdk"] data-tools = ["aiosqlite", "datacommons", "datacommons_pandas", "openbb", "pandas", "rouge", "stripe", "textblob"] dev-tools = ["agentops", "docker", "e2b-code-interpreter", "ipykernel", "jupyter_client", "tree-sitter", "tree-sitter-python"] @@ -12563,9 +12956,9 @@ rag = ["cohere", "nebula3-python", "neo4j", "pandasai", "pymilvus", "qdrant-clie research-tools = ["arxiv", "arxiv2text", "scholarly"] storage = ["azure-storage-blob", "botocore", "google-cloud-storage", "nebula3-python", "neo4j", "pymilvus", "qdrant-client", "redis"] test = ["mock", "pytest", "pytest-asyncio"] -web-tools = ["apify_client", "asknews", "dappier", "duckduckgo-search", "firecrawl-py", "googlemaps", "linkup-sdk", "newspaper3k", "pyowm", "requests_oauthlib", "tavily-python", "wikipedia", "wolframalpha"] +web-tools = ["apify_client", "asknews", "dappier", "duckduckgo-search", "firecrawl-py", "googlemaps", "newspaper3k", "pyowm", "requests_oauthlib", "tavily-python", "wikipedia", "wolframalpha"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "8fca0a7de0e85e69a72a5fab1376afa4a92ff322e8ecdf286c6c7fa9c1f50196" +content-hash = "6b85e5a8abfd6b25803d6b36edd9cb69e3dfbb119a9015601065746e6d40ae8c" diff --git a/pyproject.toml b/pyproject.toml index 8b9dfd3369..1e8491697c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,7 +101,6 @@ ffmpeg-python = { version = "^0.2.0", optional = true } # Web and API tools wikipedia = { version = "^1", optional = true } -linkup-sdk = { version = "^0.2.1", optional = true } duckduckgo-search = { version = "^6.3.5", optional = true } newspaper3k = { version = "^0.2.8", optional = true } wolframalpha = { version = "^5.0.0", optional = true } @@ -153,6 +152,8 @@ pyyaml = { version = "^6.0.2", optional = true } pytest = { version = "^7", optional = true } pytest-asyncio = { version = "^0.23.0", optional = true } mock = { version = "^5", optional = true} +linkup = "^0.1.3" +linkup-sdk = "^0.2.2" [tool.poetry.extras] test = ["pytest", "mock", "pytest-asyncio"] From d79ba4010b4f884109d96d7a43f90f83a4209f90 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Mon, 3 Feb 2025 12:10:24 +0530 Subject: [PATCH 24/43] fix: merged master --- poetry.lock | 403 +------------------------------------------------ pyproject.toml | 3 +- 2 files changed, 6 insertions(+), 400 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8eed512a7c..0f70caf328 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4355,21 +4355,11 @@ dev = ["black", "flake8", "isort", "pre-commit", "pyproject-flake8"] doc = ["myst-parser", "sphinx", "sphinx-book-theme"] test = ["coverage", "pytest", "pytest-cov"] -[[package]] -name = "linkup" -version = "0.1.3" -description = "Making mappings operable." -optional = false -python-versions = "*" -files = [ - {file = "linkup-0.1.3.tar.gz", hash = "sha256:b5fc62d827797d78d9b08bfa068f1e455f4428cf94d2f359a815f9474228ad3c"}, -] - [[package]] name = "linkup-sdk" version = "0.2.2" description = "A Python Client SDK for the Linkup API" -optional = false +optional = true python-versions = ">=3.9" files = [ {file = "linkup_sdk-0.2.2-py3-none-any.whl", hash = "sha256:23b15e950e2c2023a5cf3c5c7c0188ed3f38889dd7b2e61e08494a953e30c31f"}, @@ -5520,17 +5510,6 @@ files = [ {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] -[[package]] -name = "nvidia-cublas-cu12" -version = "12.1.3.1" -description = "CUBLAS native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, - {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, -] - [[package]] name = "nvidia-cublas-cu12" version = "12.4.5.8" @@ -5543,17 +5522,6 @@ files = [ {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, ] -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.1.105" -description = "CUDA profiling tools runtime libs." -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, - {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, -] - [[package]] name = "nvidia-cuda-cupti-cu12" version = "12.4.127" @@ -5566,17 +5534,6 @@ files = [ {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, ] -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.1.105" -description = "NVRTC native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, - {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, -] - [[package]] name = "nvidia-cuda-nvrtc-cu12" version = "12.4.127" @@ -5589,17 +5546,6 @@ files = [ {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, ] -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.1.105" -description = "CUDA Runtime native Libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, - {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, -] - [[package]] name = "nvidia-cuda-runtime-cu12" version = "12.4.127" @@ -5612,19 +5558,6 @@ files = [ {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, ] -[[package]] -name = "nvidia-cudnn-cu12" -version = "8.9.2.26" -description = "cuDNN runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" - [[package]] name = "nvidia-cudnn-cu12" version = "9.1.0.70" @@ -5639,17 +5572,6 @@ files = [ [package.dependencies] nvidia-cublas-cu12 = "*" -[[package]] -name = "nvidia-cufft-cu12" -version = "11.0.2.54" -description = "CUFFT native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, - {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, -] - [[package]] name = "nvidia-cufft-cu12" version = "11.2.1.3" @@ -5665,17 +5587,6 @@ files = [ [package.dependencies] nvidia-nvjitlink-cu12 = "*" -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.2.106" -description = "CURAND native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, - {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, -] - [[package]] name = "nvidia-curand-cu12" version = "10.3.5.147" @@ -5688,22 +5599,6 @@ files = [ {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, ] -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.4.5.107" -description = "CUDA solver native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, - {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, -] - -[package.dependencies] -nvidia-cublas-cu12 = "*" -nvidia-cusparse-cu12 = "*" -nvidia-nvjitlink-cu12 = "*" - [[package]] name = "nvidia-cusolver-cu12" version = "11.6.1.9" @@ -5721,20 +5616,6 @@ nvidia-cublas-cu12 = "*" nvidia-cusparse-cu12 = "*" nvidia-nvjitlink-cu12 = "*" -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.1.0.106" -description = "CUSPARSE native runtime libraries" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, - {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, -] - -[package.dependencies] -nvidia-nvjitlink-cu12 = "*" - [[package]] name = "nvidia-cusparse-cu12" version = "12.3.1.170" @@ -5750,27 +5631,6 @@ files = [ [package.dependencies] nvidia-nvjitlink-cu12 = "*" -[[package]] -name = "nvidia-nccl-cu12" -version = "2.19.3" -description = "NVIDIA Collective Communication Library (NCCL) Runtime" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d"}, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.20.5" -description = "NVIDIA Collective Communication Library (NCCL) Runtime" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01"}, - {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56"}, -] - [[package]] name = "nvidia-nccl-cu12" version = "2.21.5" @@ -5793,17 +5653,6 @@ files = [ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, ] -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.1.105" -description = "NVIDIA Tools Extension" -optional = true -python-versions = ">=3" -files = [ - {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, - {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, -] - [[package]] name = "nvidia-nvtx-cu12" version = "12.4.127" @@ -6521,8 +6370,8 @@ files = [ numpy = [ {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, + {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, ] [[package]] @@ -7000,10 +6849,6 @@ requests = ">=2.31.0,<3.0.0" scipy = ">=1.9.0,<2.0.0" sqlalchemy = ">=1.4,<3" sqlglot = {version = ">=25.0.3,<26.0.0", extras = ["rs"]} -torch = [ - {version = "2.2.0", markers = "sys_platform == \"darwin\" and platform_machine == \"x86_64\""}, - {version = "2.4.1", markers = "sys_platform != \"darwin\""}, -] [package.extras] bedrock = ["boto3 (>=1.34.59)"] @@ -10969,64 +10814,6 @@ files = [ {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] -[[package]] -name = "torch" -version = "2.2.0" -description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" -optional = true -python-versions = ">=3.8.0" -files = [ - {file = "torch-2.2.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d366158d6503a3447e67f8c0ad1328d54e6c181d88572d688a625fac61b13a97"}, - {file = "torch-2.2.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:707f2f80402981e9f90d0038d7d481678586251e6642a7a6ef67fc93511cb446"}, - {file = "torch-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:15c8f0a105c66b28496092fca1520346082e734095f8eaf47b5786bac24b8a31"}, - {file = "torch-2.2.0-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:0ca4df4b728515ad009b79f5107b00bcb2c63dc202d991412b9eb3b6a4f24349"}, - {file = "torch-2.2.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:3d3eea2d5969b9a1c9401429ca79efc668120314d443d3463edc3289d7f003c7"}, - {file = "torch-2.2.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:0d1c580e379c0d48f0f0a08ea28d8e373295aa254de4f9ad0631f9ed8bc04c24"}, - {file = "torch-2.2.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9328e3c1ce628a281d2707526b4d1080eae7c4afab4f81cea75bde1f9441dc78"}, - {file = "torch-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:03c8e660907ac1b8ee07f6d929c4e15cd95be2fb764368799cca02c725a212b8"}, - {file = "torch-2.2.0-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:da0cefe7f84ece3e3b56c11c773b59d1cb2c0fd83ddf6b5f7f1fd1a987b15c3e"}, - {file = "torch-2.2.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:f81d23227034221a4a4ff8ef24cc6cec7901edd98d9e64e32822778ff01be85e"}, - {file = "torch-2.2.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:dcbfb2192ac41ca93c756ebe9e2af29df0a4c14ee0e7a0dd78f82c67a63d91d4"}, - {file = "torch-2.2.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:9eeb42971619e24392c9088b5b6d387d896e267889d41d267b1fec334f5227c5"}, - {file = "torch-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:c718b2ca69a6cac28baa36d86d8c0ec708b102cebd1ceb1b6488e404cd9be1d1"}, - {file = "torch-2.2.0-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:f11d18fceb4f9ecb1ac680dde7c463c120ed29056225d75469c19637e9f98d12"}, - {file = "torch-2.2.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:ee1da852bfd4a7e674135a446d6074c2da7194c1b08549e31eae0b3138c6b4d2"}, - {file = "torch-2.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0d819399819d0862268ac531cf12a501c253007df4f9e6709ede8a0148f1a7b8"}, - {file = "torch-2.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:08f53ccc38c49d839bc703ea1b20769cc8a429e0c4b20b56921a9f64949bf325"}, - {file = "torch-2.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:93bffe3779965a71dab25fc29787538c37c5d54298fd2f2369e372b6fb137d41"}, - {file = "torch-2.2.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:c17ec323da778efe8dad49d8fb534381479ca37af1bfc58efdbb8607a9d263a3"}, - {file = "torch-2.2.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:c02685118008834e878f676f81eab3a952b7936fa31f474ef8a5ff4b5c78b36d"}, - {file = "torch-2.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d9f39d6f53cec240a0e3baa82cb697593340f9d4554cee6d3d6ca07925c2fac0"}, - {file = "torch-2.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:51770c065206250dc1222ea7c0eff3f88ab317d3e931cca2aee461b85fbc2472"}, - {file = "torch-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:008e4c6ad703de55af760c73bf937ecdd61a109f9b08f2bbb9c17e7c7017f194"}, - {file = "torch-2.2.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:de8680472dd14e316f42ceef2a18a301461a9058cd6e99a1f1b20f78f11412f1"}, - {file = "torch-2.2.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:99e1dcecb488e3fd25bcaac56e48cdb3539842904bdc8588b0b255fde03a254c"}, -] - -[package.dependencies] -filelock = "*" -fsspec = "*" -jinja2 = "*" -networkx = "*" -nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -sympy = "*" -triton = {version = "2.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -typing-extensions = ">=4.8.0" - -[package.extras] -opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.9.1)"] - [[package]] name = "torch" version = "2.2.1" @@ -11073,60 +10860,6 @@ typing-extensions = ">=4.8.0" opt-einsum = ["opt-einsum (>=3.3)"] optree = ["optree (>=0.9.1)"] -[[package]] -name = "torch" -version = "2.4.1" -description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" -optional = true -python-versions = ">=3.8.0" -files = [ - {file = "torch-2.4.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:362f82e23a4cd46341daabb76fba08f04cd646df9bfaf5da50af97cb60ca4971"}, - {file = "torch-2.4.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:e8ac1985c3ff0f60d85b991954cfc2cc25f79c84545aead422763148ed2759e3"}, - {file = "torch-2.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:91e326e2ccfb1496e3bee58f70ef605aeb27bd26be07ba64f37dcaac3d070ada"}, - {file = "torch-2.4.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:d36a8ef100f5bff3e9c3cea934b9e0d7ea277cb8210c7152d34a9a6c5830eadd"}, - {file = "torch-2.4.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:0b5f88afdfa05a335d80351e3cea57d38e578c8689f751d35e0ff36bce872113"}, - {file = "torch-2.4.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:ef503165f2341942bfdf2bd520152f19540d0c0e34961232f134dc59ad435be8"}, - {file = "torch-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:092e7c2280c860eff762ac08c4bdcd53d701677851670695e0c22d6d345b269c"}, - {file = "torch-2.4.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:ddddbd8b066e743934a4200b3d54267a46db02106876d21cf31f7da7a96f98ea"}, - {file = "torch-2.4.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:fdc4fe11db3eb93c1115d3e973a27ac7c1a8318af8934ffa36b0370efe28e042"}, - {file = "torch-2.4.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:18835374f599207a9e82c262153c20ddf42ea49bc76b6eadad8e5f49729f6e4d"}, - {file = "torch-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:ebea70ff30544fc021d441ce6b219a88b67524f01170b1c538d7d3ebb5e7f56c"}, - {file = "torch-2.4.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:72b484d5b6cec1a735bf3fa5a1c4883d01748698c5e9cfdbeb4ffab7c7987e0d"}, - {file = "torch-2.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c99e1db4bf0c5347107845d715b4aa1097e601bdc36343d758963055e9599d93"}, - {file = "torch-2.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b57f07e92858db78c5b72857b4f0b33a65b00dc5d68e7948a8494b0314efb880"}, - {file = "torch-2.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:f18197f3f7c15cde2115892b64f17c80dbf01ed72b008020e7da339902742cf6"}, - {file = "torch-2.4.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:5fc1d4d7ed265ef853579caf272686d1ed87cebdcd04f2a498f800ffc53dab71"}, - {file = "torch-2.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:40f6d3fe3bae74efcf08cb7f8295eaddd8a838ce89e9d26929d4edd6d5e4329d"}, - {file = "torch-2.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c9299c16c9743001ecef515536ac45900247f4338ecdf70746f2461f9e4831db"}, - {file = "torch-2.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:6bce130f2cd2d52ba4e2c6ada461808de7e5eccbac692525337cfb4c19421846"}, - {file = "torch-2.4.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:a38de2803ee6050309aac032676536c3d3b6a9804248537e38e098d0e14817ec"}, -] - -[package.dependencies] -filelock = "*" -fsspec = "*" -jinja2 = "*" -networkx = "*" -nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "9.1.0.70", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.20.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -setuptools = "*" -sympy = "*" -triton = {version = "3.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.13\""} -typing-extensions = ">=4.8.0" - -[package.extras] -opt-einsum = ["opt-einsum (>=3.3)"] -optree = ["optree (>=0.11.0)"] - [[package]] name = "torch" version = "2.5.1" @@ -11179,49 +10912,6 @@ typing-extensions = ">=4.8.0" opt-einsum = ["opt-einsum (>=3.3)"] optree = ["optree (>=0.12.0)"] -[[package]] -name = "torchvision" -version = "0.17.0" -description = "image and video datasets and models for torch deep learning" -optional = true -python-versions = ">=3.8" -files = [ - {file = "torchvision-0.17.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:153882cd8ff8e3dbef5c5054fdd15df64e85420546805a90c0b2221f2f119c4a"}, - {file = "torchvision-0.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c55c2f86e3f3a21ddd92739a972366244e9b17916e836ec47167b0a0c083c65f"}, - {file = "torchvision-0.17.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:605950cdcefe6c5aef85709ade17b1525bcf171e122cce1df09e666d96525b90"}, - {file = "torchvision-0.17.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3d86c212fc6379e9bec3ac647d062e34c2cf36c26b98840b66573eb9fbe1f1d9"}, - {file = "torchvision-0.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:71b314813faf13cecb09a4a635b5e4b274e8df0b1921681038d491c529555bb6"}, - {file = "torchvision-0.17.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:10d276821f115fb369e6cf1f1b77b2cca60cda12cbb39a41513a9d3d0f2a93ae"}, - {file = "torchvision-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3eef2daddadb5c21e802e0550dd7e3ee3d98c430f4aed212ae3ba0358558be1"}, - {file = "torchvision-0.17.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:acc0d098ab8c295a750f0218bf5bf7bfc2f2c21f9c2fe3fc30b695cd94f4c759"}, - {file = "torchvision-0.17.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3d2e9552d72e4037f2db6f7d97989a2e2f95763aa1861963a3faf521bb1610c4"}, - {file = "torchvision-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8e542cf71e1294fcb5635038eae6702df543dc90706f0836ec80e75efc511fc"}, - {file = "torchvision-0.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:816ae1a4506b1cb0f638e1827cae7ab768c731369ab23e86839f177926197143"}, - {file = "torchvision-0.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be39874c239215a39b3c431c7016501f1a45bfbbebf2fe8e11d8339b5ea23bca"}, - {file = "torchvision-0.17.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:8fe14d580557aef2c45dd462c069ff936b6507b215c4b496f30973ae8cff917d"}, - {file = "torchvision-0.17.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:4608ba3246c45c968ede40e7640e4eed64556210faa154cf1ffccb1cadabe445"}, - {file = "torchvision-0.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:b755d6d3e021239d2408bf3794d0d3dcffbc629f1fd808c43d8b346045a098c4"}, - {file = "torchvision-0.17.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:870d7cda57420e44d20eb07bfe37bf5344a06434a7a6195b4c7f3dd55838587d"}, - {file = "torchvision-0.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:477f6e64a9d798c0f5adefc300acc220da6f17ef5c1e110d20108f66554fee4d"}, - {file = "torchvision-0.17.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a54a15bd6f3dbb04ebd36c5a87530b2e090ee4b9b15eb89eda558ab3e50396a0"}, - {file = "torchvision-0.17.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e041ce3336364413bab051a3966d884bab25c200f98ca8a065f0abe758c3005e"}, - {file = "torchvision-0.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:7887f767670c72aa20f5237042d0ca1462da18f66a3ea8c36b6ba67ce26b82fc"}, - {file = "torchvision-0.17.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b1ced438b81ef662a71c8c81debaf0c80455b35b811ca55a4c3c593d721b560a"}, - {file = "torchvision-0.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b53569c52bd4bd1176a1e49d8ea55883bcf57e1614cb97e2e8ce372768299b70"}, - {file = "torchvision-0.17.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7f373507afcd9022ebd9f50b31da8dbac1ea6783ffb77d1f1ab8806425c0a83b"}, - {file = "torchvision-0.17.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:085251ab36340206dc7e1be59a15fa5e307d45ccd66889f5d7bf1ba5e7ecdc57"}, - {file = "torchvision-0.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4c0d4c0af58af2752aad235150bd794d0f324e6eeac5cd13c440bda5dce622d3"}, -] - -[package.dependencies] -numpy = "*" -pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" -requests = "*" -torch = "2.2.0" - -[package.extras] -scipy = ["scipy"] - [[package]] name = "torchvision" version = "0.17.1" @@ -11264,44 +10954,6 @@ torch = "2.2.1" [package.extras] scipy = ["scipy"] -[[package]] -name = "torchvision" -version = "0.19.1" -description = "image and video datasets and models for torch deep learning" -optional = true -python-versions = ">=3.8" -files = [ - {file = "torchvision-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:54e8513099e6f586356c70f809d34f391af71ad182fe071cc328a28af2c40608"}, - {file = "torchvision-0.19.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:20a1f5e02bfdad7714e55fa3fa698347c11d829fa65e11e5a84df07d93350eed"}, - {file = "torchvision-0.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:7b063116164be52fc6deb4762de7f8c90bfa3a65f8d5caf17f8e2d5aadc75a04"}, - {file = "torchvision-0.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:f40b6acabfa886da1bc3768f47679c61feee6bde90deb979d9f300df8c8a0145"}, - {file = "torchvision-0.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:40514282b4896d62765b8e26d7091c32e17c35817d00ec4be2362ea3ba3d1787"}, - {file = "torchvision-0.19.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:5a91be061ae5d6d5b95e833b93e57ca4d3c56c5a57444dd15da2e3e7fba96050"}, - {file = "torchvision-0.19.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d71a6a6fe3a5281ca3487d4c56ad4aad20ff70f82f1d7c79bcb6e7b0c2af00c8"}, - {file = "torchvision-0.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:70dea324174f5e9981b68e4b7cd524512c106ba64aedef560a86a0bbf2fbf62c"}, - {file = "torchvision-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27ece277ff0f6cdc7fed0627279c632dcb2e58187da771eca24b0fbcf3f8590d"}, - {file = "torchvision-0.19.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:c659ff92a61f188a1a7baef2850f3c0b6c85685447453c03d0e645ba8f1dcc1c"}, - {file = "torchvision-0.19.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:c07bf43c2a145d792ecd9d0503d6c73577147ece508d45600d8aac77e4cdfcf9"}, - {file = "torchvision-0.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b4283d283675556bb0eae31d29996f53861b17cbdcdf3509e6bc050414ac9289"}, - {file = "torchvision-0.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c4e4f5b24ea6b087b02ed492ab1e21bba3352c4577e2def14248cfc60732338"}, - {file = "torchvision-0.19.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9281d63ead929bb19143731154cd1d8bf0b5e9873dff8578a40e90a6bec3c6fa"}, - {file = "torchvision-0.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:4d10bc9083c4d5fadd7edd7b729700a7be48dab4f62278df3bc73fa48e48a155"}, - {file = "torchvision-0.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:ccf085ef1824fb9e16f1901285bf89c298c62dfd93267a39e8ee42c71255242f"}, - {file = "torchvision-0.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:731f434d91586769e255b5d70ed1a4457e0a1394a95f4aacf0e1e7e21f80c098"}, - {file = "torchvision-0.19.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:febe4f14d4afcb47cc861d8be7760ab6a123cd0817f97faf5771488cb6aa90f4"}, - {file = "torchvision-0.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e328309b8670a2e889b2fe76a1c2744a099c11c984da9a822357bd9debd699a5"}, - {file = "torchvision-0.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:6616f12e00a22e7f3fedbd0fccb0804c05e8fe22871668f10eae65cf3f283614"}, -] - -[package.dependencies] -numpy = "*" -pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" -torch = "2.4.1" - -[package.extras] -gdown = ["gdown (>=4.7.3)"] -scipy = ["scipy"] - [[package]] name = "torchvision" version = "0.20.1" @@ -11571,51 +11223,6 @@ exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} trio = ">=0.11" wsproto = ">=0.14" -[[package]] -name = "triton" -version = "2.2.0" -description = "A language and compiler for custom Deep Learning operations" -optional = true -python-versions = "*" -files = [ - {file = "triton-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2294514340cfe4e8f4f9e5c66c702744c4a117d25e618bd08469d0bfed1e2e5"}, - {file = "triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0"}, - {file = "triton-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af58716e721460a61886668b205963dc4d1e4ac20508cc3f623aef0d70283d5"}, - {file = "triton-2.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8fe46d3ab94a8103e291bd44c741cc294b91d1d81c1a2888254cbf7ff846dab"}, - {file = "triton-2.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ce26093e539d727e7cf6f6f0d932b1ab0574dc02567e684377630d86723ace"}, - {file = "triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:227cc6f357c5efcb357f3867ac2a8e7ecea2298cd4606a8ba1e931d1d5a947df"}, -] - -[package.dependencies] -filelock = "*" - -[package.extras] -build = ["cmake (>=3.20)", "lit"] -tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"] -tutorials = ["matplotlib", "pandas", "tabulate", "torch"] - -[[package]] -name = "triton" -version = "3.0.0" -description = "A language and compiler for custom Deep Learning operations" -optional = true -python-versions = "*" -files = [ - {file = "triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a"}, - {file = "triton-3.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ce8520437c602fb633f1324cc3871c47bee3b67acf9756c1a66309b60e3216c"}, - {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, - {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, - {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, -] - -[package.dependencies] -filelock = "*" - -[package.extras] -build = ["cmake (>=3.20)", "lit"] -tests = ["autopep8", "flake8", "isort", "llnl-hatchet", "numpy", "pytest", "scipy (>=1.7.1)"] -tutorials = ["matplotlib", "pandas", "tabulate"] - [[package]] name = "triton" version = "3.1.0" @@ -12944,7 +12551,7 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\ cffi = ["cffi (>=1.11)"] [extras] -all = ["PyMuPDF", "accelerate", "agentops", "aiosqlite", "anthropic", "apify_client", "arxiv", "arxiv2text", "asknews", "azure-storage-blob", "beautifulsoup4", "botocore", "cohere", "dappier", "datacommons", "datacommons_pandas", "datasets", "diffusers", "discord.py", "docker", "docx2txt", "duckduckgo-search", "e2b-code-interpreter", "ffmpeg-python", "firecrawl-py", "fish-audio-sdk", "google-cloud-storage", "google-generativeai", "googlemaps", "imageio", "ipykernel", "jupyter_client", "litellm", "mistralai", "nebula3-python", "neo4j", "newspaper3k", "notion-client", "openapi-spec-validator", "openbb", "opencv-python", "outlines", "pandas", "pandasai", "pdfplumber", "pillow", "prance", "praw", "pyTelegramBotAPI", "pydub", "pygithub", "pymilvus", "pyowm", "qdrant-client", "ragas", "rank-bm25", "redis", "reka-api", "requests_oauthlib", "rouge", "scholarly", "sentence-transformers", "sentencepiece", "sglang", "slack-bolt", "slack-sdk", "soundfile", "stripe", "tavily-python", "textblob", "torch", "torch", "transformers", "tree-sitter", "tree-sitter-python", "unstructured", "wikipedia", "wolframalpha", "yt-dlp"] +all = ["PyMuPDF", "accelerate", "agentops", "aiosqlite", "anthropic", "apify_client", "arxiv", "arxiv2text", "asknews", "azure-storage-blob", "beautifulsoup4", "botocore", "cohere", "dappier", "datacommons", "datacommons_pandas", "datasets", "diffusers", "discord.py", "docker", "docx2txt", "duckduckgo-search", "e2b-code-interpreter", "ffmpeg-python", "firecrawl-py", "fish-audio-sdk", "google-cloud-storage", "google-generativeai", "googlemaps", "imageio", "ipykernel", "jupyter_client", "linkup-sdk", "litellm", "mistralai", "nebula3-python", "neo4j", "newspaper3k", "notion-client", "openapi-spec-validator", "openbb", "opencv-python", "outlines", "pandas", "pandasai", "pdfplumber", "pillow", "prance", "praw", "pyTelegramBotAPI", "pydub", "pygithub", "pymilvus", "pyowm", "qdrant-client", "ragas", "rank-bm25", "redis", "reka-api", "requests_oauthlib", "rouge", "scholarly", "sentence-transformers", "sentencepiece", "sglang", "slack-bolt", "slack-sdk", "soundfile", "stripe", "tavily-python", "textblob", "torch", "torch", "transformers", "tree-sitter", "tree-sitter-python", "unstructured", "wikipedia", "wolframalpha", "yt-dlp"] communication-tools = ["discord.py", "notion-client", "praw", "pyTelegramBotAPI", "pygithub", "slack-bolt", "slack-sdk"] data-tools = ["aiosqlite", "datacommons", "datacommons_pandas", "openbb", "pandas", "rouge", "stripe", "textblob"] dev-tools = ["agentops", "docker", "e2b-code-interpreter", "ipykernel", "jupyter_client", "tree-sitter", "tree-sitter-python"] @@ -12956,9 +12563,9 @@ rag = ["cohere", "nebula3-python", "neo4j", "pandasai", "pymilvus", "qdrant-clie research-tools = ["arxiv", "arxiv2text", "scholarly"] storage = ["azure-storage-blob", "botocore", "google-cloud-storage", "nebula3-python", "neo4j", "pymilvus", "qdrant-client", "redis"] test = ["mock", "pytest", "pytest-asyncio"] -web-tools = ["apify_client", "asknews", "dappier", "duckduckgo-search", "firecrawl-py", "googlemaps", "newspaper3k", "pyowm", "requests_oauthlib", "tavily-python", "wikipedia", "wolframalpha"] +web-tools = ["apify_client", "asknews", "dappier", "duckduckgo-search", "firecrawl-py", "googlemaps", "linkup-sdk", "newspaper3k", "pyowm", "requests_oauthlib", "tavily-python", "wikipedia", "wolframalpha"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "6b85e5a8abfd6b25803d6b36edd9cb69e3dfbb119a9015601065746e6d40ae8c" +content-hash = "8fca0a7de0e85e69a72a5fab1376afa4a92ff322e8ecdf286c6c7fa9c1f50196" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1e8491697c..8b9dfd3369 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,6 +101,7 @@ ffmpeg-python = { version = "^0.2.0", optional = true } # Web and API tools wikipedia = { version = "^1", optional = true } +linkup-sdk = { version = "^0.2.1", optional = true } duckduckgo-search = { version = "^6.3.5", optional = true } newspaper3k = { version = "^0.2.8", optional = true } wolframalpha = { version = "^5.0.0", optional = true } @@ -152,8 +153,6 @@ pyyaml = { version = "^6.0.2", optional = true } pytest = { version = "^7", optional = true } pytest-asyncio = { version = "^0.23.0", optional = true } mock = { version = "^5", optional = true} -linkup = "^0.1.3" -linkup-sdk = "^0.2.2" [tool.poetry.extras] test = ["pytest", "mock", "pytest-asyncio"] From 11013212cb825c80545330a8c078f7c6667d6169 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Tue, 4 Feb 2025 17:21:11 +0530 Subject: [PATCH 25/43] fix: removed prompt injection for tool use --- examples/toolkits/web_toolkit.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index ea5905d9af..3622dd5f3b 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -28,8 +28,10 @@ ) assistant_sys_msg = """You are a helpful assistant capable of performing web -interactions and answering questions. When appropriate, use the available -tools to automate web tasks and retrieve information.""" +interactions and answering questions with real-time data. When appropriate, +use the available +tools to automate web tasks and retrieve information. +""" # Create a ChatAgent with just this single tool, wrapped in a list tool_agent = ChatAgent( @@ -39,7 +41,6 @@ ) # Interact with the agent -prompt = "What is the most visited website?" -injection_for_tool_use = "Please use the web tool to find the answer." -response = tool_agent.step(prompt + injection_for_tool_use) +prompt = "What is the most visited website in the world?" +response = tool_agent.step(prompt) print(response.msgs[0].content) From d09b230ac1369ad10dcb411f418bc4afb11727d1 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Tue, 4 Feb 2025 17:22:55 +0530 Subject: [PATCH 26/43] fix: updated_state only with the extracted info --- camel/toolkits/web_toolkit.py | 54 +++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 2403a96d92..bf9ad991dd 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -226,6 +226,7 @@ def __init__(self, high_level_task: str): The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. + Always define this in the code before ending it. At the end of your snippet, always do the final extraction to fill these fields in a variable called 'updated_state'. For example: @@ -388,11 +389,6 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: try {{ // Insert the generated snippet {js_code} - - console.log(JSON.stringify({{ - status: "success", - updated_state - }})); }} catch (error) {{ console.error(JSON.stringify({{ status: "failure", @@ -412,10 +408,52 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: exec_result = node_process.run(wrapper_code, "node") - if exec_result.startswith("(stderr"): - return "Failure: No output from Node.js script." + # Attempt to parse final JSON from logs: + final_json = self._parse_json_from_output(exec_result) + if final_json is not None: + # Return as a JSON string for the caller to parse + return json.dumps(final_json) + else: + # If no valid JSON found in logs, return an error as JSON + return json.dumps( + { + "status": "error", + "message": "No valid JSON found in node logs.", + } + ) + + def _parse_json_from_output(self, text: str): + r""" + Extracts a substring that starts with the first '{' following + the keyword 'updated_state: ' and continues until the matching + '}' is found. + + Args: + text (str): The input text containing the Stagehand code. - return exec_result + Returns: + str: The extracted JSON snippet or an empty string if not found. + """ + start_marker = "updated_state: {" + start_index = text.find(start_marker) + if start_index == -1: + return "" + # Locate the first '{' after the marker + start_index = text.find("{", start_index) + if start_index == -1: + return "" + + stack = [] + for i in range(start_index, len(text)): + char = text[i] + if char == "{": + stack.append("{") + elif char == "}": + stack.pop() + if not stack: + # Return from the first '{' up to and including this '}' + return text[start_index : i + 1] + return "" def get_tools(self) -> List[FunctionTool]: r"""Returns a list of FunctionTool objects representing the From e749bb65f3f2b7e327917709b2fd1f1a2816e7d9 Mon Sep 17 00:00:00 2001 From: X-TRON404 Date: Sat, 8 Feb 2025 10:44:11 +0530 Subject: [PATCH 27/43] fix: link.includes() to string & new tool --- camel/toolkits/web_toolkit.py | 102 ++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index bf9ad991dd..042c2d699f 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -109,6 +109,15 @@ def __init__(self, high_level_task: str): }})) So always wrap arrays in an object at the top level of your 'schema'. + + - If needed use import {{ zodResponseFormat }} from "openai/helpers/zod"; + + const schema = z.object({{ + userId: z.string(), + }}); + + const format = zodResponseFormat(schema); + - Do NOT combine multiple actions into one instruction—each action must be atomic. - Keep the script concise, and use no more than one action per line. @@ -197,7 +206,7 @@ def __init__(self, high_level_task: str): For extractions, use one extraction call for each chunk. Remember: - + - Always use absolute URLs for links in page.goto(). - Use observe() to see potential clickable items or possible actions. - Use extract() with a carefully chosen instruction and schema to gather data. @@ -231,6 +240,13 @@ def __init__(self, high_level_task: str): these fields in a variable called 'updated_state'. For example: + - IMPORTANT: + All of the values of the 'updated_state' should always be a string or a number never a Object. + The link should be an absolute url extracted from the url bar. + + - Convert the value to a string or array before calling the includes() method on it. + - Retrieve the current date and time programmatically whenever a question pertains to 'today' or involves time-related inquiries. + const updated_state = {{ status: "success", updated_state: {{ @@ -309,6 +325,81 @@ def __init__( self.model, ) + def stagehand_extract_text_images(self, url: str) -> Dict[str, Any]: + r""" + Extracts all visible text and image URLs from a webpage using Stagehand if the correct URL to a webpage is known. + + Args: + url (str): The webpage URL to extract text and images from. + + Returns: + Dict[str, Any]: Extracted text and image URLs in JSON format. + """ + + print("[DEBUG]: Calling the text and image extraction tool") + # JavaScript code to extract text and images using Stagehand + js_code = f""" + const {{ Stagehand }} = require('@browserbasehq/stagehand'); + const z = require('zod'); + + (async () => {{ + const stagehand = new Stagehand({{ headless: false }}); + await stagehand.init(); + const page = stagehand.page; + try {{ + await page.goto("{url}"); + + // Extract visible text + const textData = await page.extract({{ + instruction: "Extract all visible text on the page.", + schema: z.object({{ text: z.string() }}) + }}); + + // Extract image URLs + const imageData = await page.extract({{ + instruction: "Extract all image URLs from the page.", + schema: z.object({{ images: z.array(z.string()) }}) + }}); + + // Create final JSON object + const extractedData = {{ + status: "success", + text: textData.text, + images: imageData.images, + link: "{url}" + }}; + + console.log(JSON.stringify(extractedData, null, 2)); + + }} catch (error) {{ + console.error("Final updated_state: ", JSON.stringify({{ + status: "failure", + error: error.message + }})); + }} finally {{ + await stagehand.close(); + }} + }})(); + """ + + # Run Stagehand script + node_process = SubprocessInterpreter(require_confirm=False, print_stdout=True, print_stderr=True) + exec_result = node_process.run(js_code, "node") + + # Attempt to parse final JSON from logs: + final_json = self._parse_json_from_output(exec_result) + if final_json is not None: + # Return as a JSON string for the caller to parse + return json.dumps(final_json) + else: + # If no valid JSON found in logs, return an error as JSON + return json.dumps( + { + "status": "error", + "message": "No valid JSON found in node logs.", + } + ) + def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: r"""Single entry point that: 1) Generates Stagehand JavaScript code to interact with the web @@ -323,6 +414,8 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: or an error. """ + print("[DEBUG]: Calling the web interaction tool") + # Generate Stagehand code js_code = self._generate_stagehand_code(task_prompt) @@ -390,7 +483,7 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: // Insert the generated snippet {js_code} }} catch (error) {{ - console.error(JSON.stringify({{ + console.error("Final updated_state: ", JSON.stringify({{ status: "failure", error: error.message }})); @@ -403,7 +496,7 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: # Run the script in Node.js node_process = SubprocessInterpreter( - require_confirm=True, print_stdout=True, print_stderr=True + require_confirm=False, print_stdout=True, print_stderr=True ) exec_result = node_process.run(wrapper_code, "node") @@ -463,4 +556,5 @@ def get_tools(self) -> List[FunctionTool]: List[FunctionTool]: A list of FunctionTool objects representing the functions in the toolkit. """ - return [FunctionTool(self.stagehand_tool)] + return [FunctionTool(self.stagehand_tool), + FunctionTool(self.stagehand_extract_text_images)] \ No newline at end of file From 00603d1122bb37ec88b0d570db24b8440984ac8e Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:18:17 +0530 Subject: [PATCH 28/43] refac: precommit formatting --- camel/toolkits/web_toolkit.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 042c2d699f..0d25d6ba34 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -241,11 +241,14 @@ def __init__(self, high_level_task: str): variable called 'updated_state'. For example: - IMPORTANT: - All of the values of the 'updated_state' should always be a string or a number never a Object. + All of the values of the 'updated_state' should always be a string + or a number never a Object. The link should be an absolute url extracted from the url bar. - - Convert the value to a string or array before calling the includes() method on it. - - Retrieve the current date and time programmatically whenever a question pertains to 'today' or involves time-related inquiries. + - Convert the value to a string or array before calling the includes() + method on it. + - Retrieve the current date and time programmatically whenever a question + pertains to 'today' or involves time-related inquiries. const updated_state = {{ status: "success", @@ -327,7 +330,8 @@ def __init__( def stagehand_extract_text_images(self, url: str) -> Dict[str, Any]: r""" - Extracts all visible text and image URLs from a webpage using Stagehand if the correct URL to a webpage is known. + Extracts all visible text and image URLs from a webpage using Stagehand + if the correct URL to a webpage is known. Args: url (str): The webpage URL to extract text and images from. @@ -383,7 +387,9 @@ def stagehand_extract_text_images(self, url: str) -> Dict[str, Any]: """ # Run Stagehand script - node_process = SubprocessInterpreter(require_confirm=False, print_stdout=True, print_stderr=True) + node_process = SubprocessInterpreter( + require_confirm=False, print_stdout=True, print_stderr=True + ) exec_result = node_process.run(js_code, "node") # Attempt to parse final JSON from logs: @@ -415,7 +421,7 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: """ print("[DEBUG]: Calling the web interaction tool") - + # Generate Stagehand code js_code = self._generate_stagehand_code(task_prompt) @@ -556,5 +562,7 @@ def get_tools(self) -> List[FunctionTool]: List[FunctionTool]: A list of FunctionTool objects representing the functions in the toolkit. """ - return [FunctionTool(self.stagehand_tool), - FunctionTool(self.stagehand_extract_text_images)] \ No newline at end of file + return [ + FunctionTool(self.stagehand_tool), + FunctionTool(self.stagehand_extract_text_images), + ] From ae573d45c13a6f765219c0ed4d6bca08dc6b0bee Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:20:07 +0530 Subject: [PATCH 29/43] fix: merge poetry.lock --- poetry.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 97c06e7ecc..67303807dc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12499,5 +12499,4 @@ web-tools = ["apify_client", "asknews", "dappier", "duckduckgo-search", "firecra [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "8fca0a7de0e85e69a72a5fab1376afa4a92ff322e8ecdf286c6c7fa9c1f50196" content-hash = "ccd7845251187d9c2bd3831125c486c75a62e259f6306a3ad92dba5d87892d4c" From 806db5c8f5db87c28040b15dc7174d4baefd7dad Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:42:56 +0530 Subject: [PATCH 30/43] fix: return type str --- camel/toolkits/web_toolkit.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 0d25d6ba34..eb90ef9962 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -12,7 +12,7 @@ # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= import json -from typing import Any, Dict, List +from typing import List from camel.agents import ChatAgent from camel.configs import ChatGPTConfig @@ -110,7 +110,8 @@ def __init__(self, high_level_task: str): So always wrap arrays in an object at the top level of your 'schema'. - - If needed use import {{ zodResponseFormat }} from "openai/helpers/zod"; + - If needed use import {{ zodResponseFormat }} + from "openai/helpers/zod"; const schema = z.object({{ userId: z.string(), @@ -245,10 +246,10 @@ def __init__(self, high_level_task: str): or a number never a Object. The link should be an absolute url extracted from the url bar. - - Convert the value to a string or array before calling the includes() - method on it. - - Retrieve the current date and time programmatically whenever a question - pertains to 'today' or involves time-related inquiries. + - Convert the value to a string or array before calling the + includes() method on it. + - Retrieve the current date and time programmatically whenever a + question pertains to 'today' or involves time-related inquiries. const updated_state = {{ status: "success", @@ -328,7 +329,7 @@ def __init__( self.model, ) - def stagehand_extract_text_images(self, url: str) -> Dict[str, Any]: + def stagehand_extract_text_images(self, url: str) -> str: r""" Extracts all visible text and image URLs from a webpage using Stagehand if the correct URL to a webpage is known. @@ -406,7 +407,7 @@ def stagehand_extract_text_images(self, url: str) -> Dict[str, Any]: } ) - def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: + def stagehand_tool(self, task_prompt: str) -> str: r"""Single entry point that: 1) Generates Stagehand JavaScript code to interact with the web 2) Executes it under Node.js @@ -430,13 +431,15 @@ def stagehand_tool(self, task_prompt: str) -> Dict[str, Any]: # Attempt to parse JSON try: - return json.loads(result_str) + return result_str except json.JSONDecodeError: - return { - "status": "error", - "message": f"""No valid JSON output. + return json.dumps( + { + "status": "error", + "message": f"""No valid JSON output. Last script line:\n{result_str}""", - } + } + ) # # Internals From 5c4c4241682488bd12544a2ceb7581177770536e Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sat, 8 Feb 2025 17:25:21 +0530 Subject: [PATCH 31/43] feat: added debug mode --- camel/toolkits/web_toolkit.py | 92 ++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index eb90ef9962..adee029a6a 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -37,7 +37,7 @@ class StagehandPrompts: def __init__(self, high_level_task: str): self.high_level_task = high_level_task self.stagehand_prompt = TextPrompt( - f"""You an assistant that helps in writing a + f"""You are an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task}The snippet must only contain @@ -234,7 +234,7 @@ def __init__(self, high_level_task: str): }} }} - The the calling agent will provide you feedback on what to inlcude + The calling agent will provide you feedback on what to inlcude in the 'updated_state'. Always define this in the code before ending it. At the end of your snippet, always do the final extraction to fill @@ -305,11 +305,13 @@ def __init__( model_type=ModelType.DEFAULT, model_config_dict=_DEFAULT_CHATGPT_CONFIG_DICT, headless_mode=True, + debug=False, ): self.model_platform = model_platform self.model_type = model_type self.model_config_dict = model_config_dict self.headless_mode = headless_mode + self.debug = debug self.model = ModelFactory.create( model_platform=self.model_platform, @@ -341,7 +343,9 @@ def stagehand_extract_text_images(self, url: str) -> str: Dict[str, Any]: Extracted text and image URLs in JSON format. """ - print("[DEBUG]: Calling the text and image extraction tool") + if self.debug: + print("[DEBUG]: Calling the web interaction tool") + # JavaScript code to extract text and images using Stagehand js_code = f""" const {{ Stagehand }} = require('@browserbasehq/stagehand'); @@ -374,7 +378,8 @@ def stagehand_extract_text_images(self, url: str) -> str: link: "{url}" }}; - console.log(JSON.stringify(extractedData, null, 2)); + console.log("Final updated_state: ", + JSON.stringify(extractedData, null, 2)); }} catch (error) {{ console.error("Final updated_state: ", JSON.stringify({{ @@ -389,15 +394,21 @@ def stagehand_extract_text_images(self, url: str) -> str: # Run Stagehand script node_process = SubprocessInterpreter( - require_confirm=False, print_stdout=True, print_stderr=True + require_confirm=False, print_stdout=False, print_stderr=False ) exec_result = node_process.run(js_code, "node") # Attempt to parse final JSON from logs: - final_json = self._parse_json_from_output(exec_result) - if final_json is not None: - # Return as a JSON string for the caller to parse - return json.dumps(final_json) + result_str = self._parse_json_from_output(exec_result) + + if self.debug: + print(f"[DEBUG]: Generated code: {js_code}") + + print(f"[DEBUG]: result_str: {result_str}") + + if result_str is not None: + # Return as a JSON string to the caller + return json.dumps(result_str) else: # If no valid JSON found in logs, return an error as JSON return json.dumps( @@ -420,16 +431,21 @@ def stagehand_tool(self, task_prompt: str) -> str: Dict[str, Any]: JSON result from the Stagehand script, or an error. """ - - print("[DEBUG]: Calling the web interaction tool") + if self.debug: + print("[DEBUG]: Calling the web interaction tool") # Generate Stagehand code js_code = self._generate_stagehand_code(task_prompt) - # Run code in Node, capture JSON + # Run code in Node, capture JSON in string format result_str = self._run_stagehand_script_in_node(js_code) - # Attempt to parse JSON + if self.debug: + print(f"[DEBUG]: Generated code: {js_code}") + + print(f"[DEBUG]: result_str: {result_str}") + + # Return JSON in string format try: return result_str except json.JSONDecodeError: @@ -479,33 +495,33 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: # Wrap the user snippet with Stagehand environment wrapper_code = f""" -const {{ Stagehand }} = require('@browserbasehq/stagehand'); -const z = require('zod'); - -(async () => {{ - const stagehand = new Stagehand({{ headless: {"true" if - self.headless_mode else "false"} }}); - await stagehand.init(); - const page = stagehand.page; - console.log("Starting Stagehand automation..."); - try {{ - // Insert the generated snippet - {js_code} - }} catch (error) {{ - console.error("Final updated_state: ", JSON.stringify({{ - status: "failure", - error: error.message - }})); - }} finally {{ - await stagehand.close(); - console.log("Stagehand session closed."); - }} -}})(); -""" + const {{ Stagehand }} = require('@browserbasehq/stagehand'); + const z = require('zod'); + + (async () => {{ + const stagehand = new Stagehand({{ headless: {"true" if + self.headless_mode else "false"} }}); + await stagehand.init(); + const page = stagehand.page; + console.log("Starting Stagehand automation..."); + try {{ + // Insert the generated snippet + {js_code} + }} catch (error) {{ + console.error("Final updated_state: ", JSON.stringify({{ + status: "failure", + error: error.message + }})); + }} finally {{ + await stagehand.close(); + console.log("Stagehand session closed."); + }} + }})(); + """ # Run the script in Node.js node_process = SubprocessInterpreter( - require_confirm=False, print_stdout=True, print_stderr=True + require_confirm=False, print_stdout=False, print_stderr=False ) exec_result = node_process.run(wrapper_code, "node") @@ -536,7 +552,7 @@ def _parse_json_from_output(self, text: str): Returns: str: The extracted JSON snippet or an empty string if not found. """ - start_marker = "updated_state: {" + start_marker = "updated_state:" start_index = text.find(start_marker) if start_index == -1: return "" From d8e3096aff18982fd6db8cefbcf1445b70ae8007 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sat, 8 Feb 2025 17:40:12 +0530 Subject: [PATCH 32/43] fix: pre-commit checks --- camel/toolkits/web_toolkit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index adee029a6a..41d4175187 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -37,7 +37,7 @@ class StagehandPrompts: def __init__(self, high_level_task: str): self.high_level_task = high_level_task self.stagehand_prompt = TextPrompt( - f"""You are an assistant that helps in writing a + f"""You an assistant that helps in writing a JavaScript snippet for a web automation task using Stagehand. that acts as a low level plan for getting the information for the high level task of {high_level_task}The snippet must only contain @@ -234,7 +234,7 @@ def __init__(self, high_level_task: str): }} }} - The calling agent will provide you feedback on what to inlcude + The the calling agent will provide you feedback on what to inlcude in the 'updated_state'. Always define this in the code before ending it. At the end of your snippet, always do the final extraction to fill From 9c0ea48b539ac6e2b520fe48de6c62714c422d33 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sun, 9 Feb 2025 12:58:10 +0530 Subject: [PATCH 33/43] fix: debug statement for stagehand_extract_text_images tool --- camel/toolkits/web_toolkit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 41d4175187..659589ba7b 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -207,6 +207,7 @@ def __init__(self, high_level_task: str): For extractions, use one extraction call for each chunk. Remember: + - Never use relative URLs for links in page.goto(). - Always use absolute URLs for links in page.goto(). - Use observe() to see potential clickable items or possible actions. - Use extract() with a carefully chosen instruction and schema @@ -344,7 +345,7 @@ def stagehand_extract_text_images(self, url: str) -> str: """ if self.debug: - print("[DEBUG]: Calling the web interaction tool") + print("[DEBUG]: Calling the extract text & images tool") # JavaScript code to extract text and images using Stagehand js_code = f""" From dd0666058d588955d3aaa9f27afe80e3e9d1bf58 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sun, 9 Feb 2025 12:59:16 +0530 Subject: [PATCH 34/43] feat: added stagehand_extract_text_images tool --- examples/toolkits/web_toolkit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index 3622dd5f3b..f2021aae04 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -19,9 +19,10 @@ from camel.types import ModelPlatformType, ModelType # Initialize the toolkit -toolkit = WebToolkit(headless_mode=False) +toolkit = WebToolkit(headless_mode=False, debug=True) stagehand_tool = FunctionTool(toolkit.stagehand_tool) +web_text_and_image_tool = FunctionTool(toolkit.stagehand_extract_text_images) model = ModelFactory.create( model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI @@ -37,7 +38,7 @@ tool_agent = ChatAgent( assistant_sys_msg, model=model, - tools=[stagehand_tool], + tools=[stagehand_tool, web_text_and_image_tool], ) # Interact with the agent From 25122d8d60a7254995b66dde367464e47fd2a2cd Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Sun, 9 Feb 2025 13:31:17 +0530 Subject: [PATCH 35/43] feat: updated prompt --- examples/toolkits/web_toolkit.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index f2021aae04..bf5703d5f2 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -28,10 +28,13 @@ model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI ) -assistant_sys_msg = """You are a helpful assistant capable of performing web -interactions and answering questions with real-time data. When appropriate, -use the available -tools to automate web tasks and retrieve information. +assistant_sys_msg = """You are a helpful assistant capable of performing +web interactions and answering questions with +real-time data. Use the available tools to automate web tasks and +retrieve necessary information. +Always include references to the websites you visited and provide the +extracted text as evidence. +Verify the authenticity of the information before responding. """ # Create a ChatAgent with just this single tool, wrapped in a list From 2e487b8a854efb98e3fc9ca63456428173bf203f Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:31:31 +0530 Subject: [PATCH 36/43] fix: remove default tools from worker --- camel/societies/workforce/workforce.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/camel/societies/workforce/workforce.py b/camel/societies/workforce/workforce.py index 5cdffb99ec..4c0f18b658 100644 --- a/camel/societies/workforce/workforce.py +++ b/camel/societies/workforce/workforce.py @@ -41,7 +41,8 @@ ) from camel.societies.workforce.worker import Worker from camel.tasks.task import Task, TaskState -from camel.toolkits import GoogleMapsToolkit, SearchToolkit, WeatherToolkit + +# from camel.toolkits import GoogleMapsToolkit, SearchToolkit, WeatherToolkit from camel.types import ModelPlatformType, ModelType logger = logging.getLogger(__name__) @@ -345,15 +346,7 @@ def _create_new_agent(self, role: str, sys_msg: str) -> ChatAgent: if self.new_worker_agent_kwargs is not None: return ChatAgent(worker_sys_msg, **self.new_worker_agent_kwargs) - # Default tools for a new agent - function_list = [ - *SearchToolkit().get_tools(), - *WeatherToolkit().get_tools(), - *GoogleMapsToolkit().get_tools(), - ] - model_config_dict = ChatGPTConfig( - tools=function_list, temperature=0.0, ).as_dict() @@ -363,7 +356,7 @@ def _create_new_agent(self, role: str, sys_msg: str) -> ChatAgent: model_config_dict=model_config_dict, ) - return ChatAgent(worker_sys_msg, model=model, tools=function_list) # type: ignore[arg-type] + return ChatAgent(worker_sys_msg, model=model) # type: ignore[arg-type] async def _get_returned_task(self) -> Task: r"""Get the task that's published by this node and just get returned From a3d4c36f338b9cdb9f0a877a39c124039b166490 Mon Sep 17 00:00:00 2001 From: Aaron617 <1170813560@qq.com> Date: Mon, 10 Feb 2025 15:18:41 +0800 Subject: [PATCH 37/43] update unit test for web toolkit derived from GAIA --- examples/toolkits/web_toolkit_unit_test.py | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/toolkits/web_toolkit_unit_test.py diff --git a/examples/toolkits/web_toolkit_unit_test.py b/examples/toolkits/web_toolkit_unit_test.py new file mode 100644 index 0000000000..ddbae70930 --- /dev/null +++ b/examples/toolkits/web_toolkit_unit_test.py @@ -0,0 +1,46 @@ +import pytest +from camel.toolkits import WebToolkit + +@pytest.fixture +def web_toolkit(): + return WebToolkit() + + +def test_1(web_toolkit): + + task_prompt = r"According to Girls Who Code, how long did it take in years for the percentage of computer scientists that were women to change by 13% from a starting point of 37%? Here are the reference website: `https://girlswhocode.com/about-us`" + res = web_toolkit.stagehand_tool(task_prompt) + + assert '22' in str(res) + + +def test_2(web_toolkit): + + task_prompt = r"In Audre Lorde’s poem “Father Son and Holy Ghost”, what is the number of the stanza in which some lines are indented? Here are the reference website: `https://www.poetryfoundation.org/poems/46462/father-son-and-holy-ghost`" + res = web_toolkit.stagehand_tool(task_prompt) + + assert '2' in str(res) + + +def test_3(web_toolkit): + + task_prompt = r"On the DeepFruits fruit detection graph on Connected Papers from 2016, what feature caused the largest bubble to be the size it is?" + res = web_toolkit.stagehand_tool(task_prompt) + + assert "citations" in str(res) + + +def test_4(web_toolkit): + + task_prompt = "On Cornell Law School website's legal information institute, under the fifth section of federal rules alphabetically, what word was deleted in the last amendment to the first rule in the article that has \"witnesses\" in the most titles as of 2021?" + res = web_toolkit.stagehand_tool(task_prompt) + + assert "inference" in str(res) + + +def test_5(web_toolkit): + + task_prompt = "Acording to `https://openreview.net/group?id=NeurIPS.cc/2022/Conference`, how many papers by an author named Yuri were accepted with a \"certain\" recommendation?" + res = web_toolkit.stagehand_tool(task_prompt) + + assert "3" in str(res) From 1e0aecc7e8c168a466b68915a4c3133582c9197b Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:58:27 +0530 Subject: [PATCH 38/43] feat: added screenshot tool --- examples/toolkits/web_toolkit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/toolkits/web_toolkit.py b/examples/toolkits/web_toolkit.py index bf5703d5f2..83e3c1a5fc 100644 --- a/examples/toolkits/web_toolkit.py +++ b/examples/toolkits/web_toolkit.py @@ -23,6 +23,9 @@ stagehand_tool = FunctionTool(toolkit.stagehand_tool) web_text_and_image_tool = FunctionTool(toolkit.stagehand_extract_text_images) +screenshot_tool = FunctionTool( + toolkit.stagehand_screenshot_and_analyze_with_gpt4o +) model = ModelFactory.create( model_platform=ModelPlatformType.OPENAI, model_type=ModelType.GPT_4O_MINI @@ -41,7 +44,7 @@ tool_agent = ChatAgent( assistant_sys_msg, model=model, - tools=[stagehand_tool, web_text_and_image_tool], + tools=[stagehand_tool, web_text_and_image_tool, screenshot_tool], ) # Interact with the agent From 0af989d5b3bbf7ba98319d1b7ece911d07f0651d Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:59:01 +0530 Subject: [PATCH 39/43] feat: added screenshot tool --- camel/toolkits/web_toolkit.py | 178 +++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 3 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 659589ba7b..bd262cc8af 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -12,7 +12,8 @@ # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= import json -from typing import List +import os +from typing import Any, Dict, List from camel.agents import ChatAgent from camel.configs import ChatGPTConfig @@ -207,7 +208,6 @@ def __init__(self, high_level_task: str): For extractions, use one extraction call for each chunk. Remember: - - Never use relative URLs for links in page.goto(). - Always use absolute URLs for links in page.goto(). - Use observe() to see potential clickable items or possible actions. - Use extract() with a carefully chosen instruction and schema @@ -345,7 +345,7 @@ def stagehand_extract_text_images(self, url: str) -> str: """ if self.debug: - print("[DEBUG]: Calling the extract text & images tool") + print("[DEBUG]: Calling the web interaction tool") # JavaScript code to extract text and images using Stagehand js_code = f""" @@ -482,6 +482,177 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: else: raise ValueError("Failed to generate Stagehand code.") + def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: + r""" + Captures multiple screenshots while scrolling, extracts page text, + and sends each screenshot along with the extracted text to GPT-4o + for analysis. + + Args: + url (str): The webpage URL to analyze. + + Returns: + Dict[str, Any]: JSON response containing: + - GPT-4o analysis for each screenshot. + - Extracted text from the page. + - Screenshot file paths. + """ + + if self.debug: + print("[DEBUG]: Calling the screenshot and analyze tool") + + screenshot_folder = "screenshots" + os.makedirs(screenshot_folder, exist_ok=True) + screenshot_base = os.path.join( + screenshot_folder, os.path.basename(url).replace("/", "_") + ) + + # JavaScript code for scrolling, taking screenshots, + # and extracting text per screenshot + js_code = f""" + const {{ Stagehand }} = require('@browserbasehq/stagehand'); + const z = require('zod'); + const fs = require('fs'); + + (async () => {{ + const stagehand = new Stagehand({{ headless: true }}); + await stagehand.init(); + const page = stagehand.page; + try {{ + await page.goto("{url}"); + + let screenshots = []; + let totalHeight = 0; + let viewportHeight = await page.evaluate( + () => window.innerHeight); + let scrollHeight = await page.evaluate( + () => document.body.scrollHeight); + let scrollY = 0; + let index = 0; + + // Extract full-page text once + const fullTextData = await page.extract({{ + instruction: "Extract all visible text on the page.", + schema: z.object({{ text: z.string() }}) + }}); + + let extracted_text = fullTextData.text; + + // Scroll and take multiple screenshots + while (scrollY < scrollHeight) {{ + let screenshot_path = "{screenshot_base}_" + + index + ".png"; + await page.screenshot({{ path: screenshot_path }}); + screenshots.push(screenshot_path); + + totalHeight += viewportHeight; + scrollY += viewportHeight; + await page.evaluate((height) => + window.scrollBy(0, height), + viewportHeight); + await page.act({{ action: "Wait a second + for scrolling to complete." }}); + index++; + }} + + // Final JSON object + const extractedData = {{ + status: "success", + text: extracted_text, + screenshots: screenshots, + link: "{url}" + }}; + + console.log("Final updated_state: ", + JSON.stringify(extractedData, null, 2)); + + }} catch (error) {{ + console.error("Final updated_state: ", JSON.stringify({{ + status: "failure", + error: error.message + }})); + }} finally {{ + await stagehand.close(); + }} + }})(); + """ + + # Run Stagehand script + node_process = SubprocessInterpreter( + require_confirm=False, print_stdout=False, print_stderr=False + ) + exec_result = node_process.run(js_code, "node") + + # Parse the JSON output + result_str = self._parse_json_from_output(exec_result) + + if not result_str or "screenshots" not in result_str: + return json.dumps( + { + "status": "error", + "message": "No valid JSON found in node logs.", + } + ) + + screenshots = result_str["screenshots"] + extracted_text = result_str["text"] + + # Analyze each screenshot with GPT-4o + gpt_results = self._analyze_screenshots_with_gpt4o( + screenshots, extracted_text + ) + + # Final response with GPT-4o results + final_response = { + "status": "success", + "link": url, + "text": extracted_text, + "gpt_analysis": gpt_results, + } + + return json.dumps(final_response) + + def _analyze_screenshots_with_gpt4o( + self, screenshots: List[str], text: str + ) -> List[Dict[str, Any]]: + r""" + Sends each screenshot along with extracted text to GPT-4o for analysis. + + Args: + screenshots (List[str]): List of screenshot file paths. + text (str): Extracted text from the webpage. + + Returns: + List[Dict[str, Any]]: List of GPT-4o responses for each screenshot. + """ + results = [] + + for screenshot in screenshots: + gpt_input = { + "prompt": f"""Analyze the following screenshot in the + context of the extracted webpage + text:\n\n{text}\n\n""" + f"""Describe the visual elements and provide insights + based on the webpage's purpose.""", + "image": screenshot, # Pass image file for analysis + } + + # Send to GPT-4o model + response = self.agent.step(input_message=gpt_input) + + # Extract response content + gpt_response = ( + response.msgs[-1].content.strip() + if response and response.msgs + else "No response from model." + ) + + results.append( + {"screenshot": screenshot, "analysis": gpt_response} + ) + + return results + def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" Internal method that executes the Stagehand code under @@ -585,4 +756,5 @@ def get_tools(self) -> List[FunctionTool]: return [ FunctionTool(self.stagehand_tool), FunctionTool(self.stagehand_extract_text_images), + FunctionTool(self.stagehand_screenshot_and_analyze_with_gpt4o), ] From 61c21d1e09e20f6a5e5e845fd8d39751d1ff2e7f Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Tue, 11 Feb 2025 00:52:31 +0530 Subject: [PATCH 40/43] fix: screenshot tool no text --- camel/toolkits/web_toolkit.py | 201 ++++++++++++---------------------- 1 file changed, 67 insertions(+), 134 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index bd262cc8af..7b4fa2e022 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -345,7 +345,7 @@ def stagehand_extract_text_images(self, url: str) -> str: """ if self.debug: - print("[DEBUG]: Calling the web interaction tool") + print("[DEBUG]: Calling the extract_text_images tool") # JavaScript code to extract text and images using Stagehand js_code = f""" @@ -482,11 +482,10 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: else: raise ValueError("Failed to generate Stagehand code.") - def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: - r""" - Captures multiple screenshots while scrolling, extracts page text, - and sends each screenshot along with the extracted text to GPT-4o - for analysis. + + def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> Dict[str, Any]: + """ + Captures multiple screenshots while scrolling and sends each screenshot to GPT-4o for analysis. Args: url (str): The webpage URL to analyze. @@ -494,12 +493,11 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: Returns: Dict[str, Any]: JSON response containing: - GPT-4o analysis for each screenshot. - - Extracted text from the page. - Screenshot file paths. """ if self.debug: - print("[DEBUG]: Calling the screenshot and analyze tool") + print("[DEBUG]: Capturing screenshots for analysis") screenshot_folder = "screenshots" os.makedirs(screenshot_folder, exist_ok=True) @@ -507,15 +505,13 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: screenshot_folder, os.path.basename(url).replace("/", "_") ) - # JavaScript code for scrolling, taking screenshots, - # and extracting text per screenshot + # JavaScript code for scrolling and taking screenshots js_code = f""" const {{ Stagehand }} = require('@browserbasehq/stagehand'); - const z = require('zod'); const fs = require('fs'); (async () => {{ - const stagehand = new Stagehand({{ headless: true }}); + const stagehand = new Stagehand({{ headless: false }}); await stagehand.init(); const page = stagehand.page; try {{ @@ -523,53 +519,37 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: let screenshots = []; let totalHeight = 0; - let viewportHeight = await page.evaluate( - () => window.innerHeight); - let scrollHeight = await page.evaluate( - () => document.body.scrollHeight); + let viewportHeight = await page.evaluate(() => window.innerHeight); + let scrollHeight = await page.evaluate(() => document.body.scrollHeight); let scrollY = 0; let index = 0; - // Extract full-page text once - const fullTextData = await page.extract({{ - instruction: "Extract all visible text on the page.", - schema: z.object({{ text: z.string() }}) - }}); - - let extracted_text = fullTextData.text; - // Scroll and take multiple screenshots while (scrollY < scrollHeight) {{ - let screenshot_path = "{screenshot_base}_" + - index + ".png"; + let screenshot_path = "{screenshot_base}_" + index + ".png"; await page.screenshot({{ path: screenshot_path }}); screenshots.push(screenshot_path); totalHeight += viewportHeight; scrollY += viewportHeight; - await page.evaluate((height) => - window.scrollBy(0, height), - viewportHeight); - await page.act({{ action: "Wait a second - for scrolling to complete." }}); + await page.evaluate((height) => window.scrollBy(0, height), viewportHeight); + await page.act({{ action: "Wait a second for scrolling to complete." }}); index++; }} // Final JSON object const extractedData = {{ - status: "success", - text: extracted_text, - screenshots: screenshots, - link: "{url}" + "status": "success", + "screenshots": screenshots, + "link": "{url}" }}; - console.log("Final updated_state: ", - JSON.stringify(extractedData, null, 2)); + console.log("updated_state: ", JSON.stringify(extractedData, null, 2)); }} catch (error) {{ - console.error("Final updated_state: ", JSON.stringify({{ - status: "failure", - error: error.message + console.error("updated_state: ", JSON.stringify({{ + "status": "failure", + "error": error.message }})); }} finally {{ await stagehand.close(); @@ -577,69 +557,81 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> str: }})(); """ - # Run Stagehand script + print("[DEBUG]: Executing JavaScript in Node.js") + + # Run the script in Node.js node_process = SubprocessInterpreter( - require_confirm=False, print_stdout=False, print_stderr=False + require_confirm=False, print_stdout=True, print_stderr=True ) + exec_result = node_process.run(js_code, "node") - # Parse the JSON output - result_str = self._parse_json_from_output(exec_result) + # Debugging: Print raw output from node + print(f"[DEBUG] Raw Node.js Output:\n{exec_result}") - if not result_str or "screenshots" not in result_str: - return json.dumps( - { - "status": "error", - "message": "No valid JSON found in node logs.", - } - ) + # Parse the JSON output using the unchanged _parse_json_from_output function + raw_json = self._parse_json_from_output(exec_result) - screenshots = result_str["screenshots"] - extracted_text = result_str["text"] + # Convert JSON string to a Python dictionary + try: + final_json = json.loads(raw_json) + except json.JSONDecodeError: + print("[ERROR]: Failed to parse JSON from extracted output.") + return {"status": "error", "message": "Failed to parse extracted JSON."} + + if "screenshots" not in final_json: + print("[ERROR]: No valid screenshots found.") + return {"status": "error", "message": "No screenshots found in output."} + + screenshots = final_json["screenshots"] + + print("[DEBUG]: Screenshots Captured:\n", screenshots) # Analyze each screenshot with GPT-4o - gpt_results = self._analyze_screenshots_with_gpt4o( - screenshots, extracted_text - ) + gpt_results = self._analyze_screenshots_with_gpt4o(screenshots) # Final response with GPT-4o results - final_response = { + return { "status": "success", "link": url, - "text": extracted_text, - "gpt_analysis": gpt_results, + "gpt_analysis": gpt_results } - return json.dumps(final_response) - - def _analyze_screenshots_with_gpt4o( - self, screenshots: List[str], text: str - ) -> List[Dict[str, Any]]: - r""" - Sends each screenshot along with extracted text to GPT-4o for analysis. + def _analyze_screenshots_with_gpt4o(self, screenshots: List[str]) -> List[Dict[str, Any]]: + """ + Sends each screenshot to GPT-4o for analysis. Args: screenshots (List[str]): List of screenshot file paths. - text (str): Extracted text from the webpage. Returns: List[Dict[str, Any]]: List of GPT-4o responses for each screenshot. """ + + if self.debug: + print("[DEBUG]: Calling _analyze_screenshots_with_gpt4o") + results = [] for screenshot in screenshots: - gpt_input = { - "prompt": f"""Analyze the following screenshot in the - context of the extracted webpage - text:\n\n{text}\n\n""" - f"""Describe the visual elements and provide insights - based on the webpage's purpose.""", - "image": screenshot, # Pass image file for analysis - } + gpt_input = BaseMessage( + role_name="GPT-4o Screenshot Analyzer", + role_type=RoleType.USER, + meta_dict=None, + content="Analyze the following screenshot and describe the visual elements. Identify key UI components, any notable content, and overall design layout." + ) + + # Debugging: Check input message + if self.debug: + print(f"[DEBUG] Sending GPT-4o Input for {screenshot}") # Send to GPT-4o model response = self.agent.step(input_message=gpt_input) + # Debugging: Check response + if self.debug: + print(f"[DEBUG] GPT-4o Response: {response}") + # Extract response content gpt_response = ( response.msgs[-1].content.strip() @@ -653,65 +645,6 @@ def _analyze_screenshots_with_gpt4o( return results - def _run_stagehand_script_in_node(self, js_code: str) -> str: - r""" - Internal method that executes the Stagehand code under - Node.js and returns the final JSON line from stdout. - - Args: - js_code (str): The JavaScript code to execute. - - Returns: - str: The final output of the script or an error message. - """ - - # Wrap the user snippet with Stagehand environment - wrapper_code = f""" - const {{ Stagehand }} = require('@browserbasehq/stagehand'); - const z = require('zod'); - - (async () => {{ - const stagehand = new Stagehand({{ headless: {"true" if - self.headless_mode else "false"} }}); - await stagehand.init(); - const page = stagehand.page; - console.log("Starting Stagehand automation..."); - try {{ - // Insert the generated snippet - {js_code} - }} catch (error) {{ - console.error("Final updated_state: ", JSON.stringify({{ - status: "failure", - error: error.message - }})); - }} finally {{ - await stagehand.close(); - console.log("Stagehand session closed."); - }} - }})(); - """ - - # Run the script in Node.js - node_process = SubprocessInterpreter( - require_confirm=False, print_stdout=False, print_stderr=False - ) - - exec_result = node_process.run(wrapper_code, "node") - - # Attempt to parse final JSON from logs: - final_json = self._parse_json_from_output(exec_result) - if final_json is not None: - # Return as a JSON string for the caller to parse - return json.dumps(final_json) - else: - # If no valid JSON found in logs, return an error as JSON - return json.dumps( - { - "status": "error", - "message": "No valid JSON found in node logs.", - } - ) - def _parse_json_from_output(self, text: str): r""" Extracts a substring that starts with the first '{' following From dac6d23d8d6ccd8b4871dab2ba0b23b279d834a7 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Tue, 11 Feb 2025 01:03:33 +0530 Subject: [PATCH 41/43] fix: accidentally deleted _run_stagehand_script_in_node() --- camel/toolkits/web_toolkit.py | 62 ++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 7b4fa2e022..6c49ab3fce 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -486,7 +486,8 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> Dict[str, Any]: """ Captures multiple screenshots while scrolling and sends each screenshot to GPT-4o for analysis. - + Use this tool when you think visual analysis of graphs/images/or the website content would be useful + Args: url (str): The webpage URL to analyze. @@ -645,6 +646,65 @@ def _analyze_screenshots_with_gpt4o(self, screenshots: List[str]) -> List[Dict[s return results + def _run_stagehand_script_in_node(self, js_code: str) -> str: + r""" + Internal method that executes the Stagehand code under + Node.js and returns the final JSON line from stdout. + + Args: + js_code (str): The JavaScript code to execute. + + Returns: + str: The final output of the script or an error message. + """ + + # Wrap the user snippet with Stagehand environment + wrapper_code = f""" + const {{ Stagehand }} = require('@browserbasehq/stagehand'); + const z = require('zod'); + + (async () => {{ + const stagehand = new Stagehand({{ headless: {"true" if + self.headless_mode else "false"} }}); + await stagehand.init(); + const page = stagehand.page; + console.log("Starting Stagehand automation..."); + try {{ + // Insert the generated snippet + {js_code} + }} catch (error) {{ + console.error("Final updated_state: ", JSON.stringify({{ + status: "failure", + error: error.message + }})); + }} finally {{ + await stagehand.close(); + console.log("Stagehand session closed."); + }} + }})(); + """ + + # Run the script in Node.js + node_process = SubprocessInterpreter( + require_confirm=False, print_stdout=False, print_stderr=False + ) + + exec_result = node_process.run(wrapper_code, "node") + + # Attempt to parse final JSON from logs: + final_json = self._parse_json_from_output(exec_result) + if final_json is not None: + # Return as a JSON string for the caller to parse + return json.dumps(final_json) + else: + # If no valid JSON found in logs, return an error as JSON + return json.dumps( + { + "status": "error", + "message": "No valid JSON found in node logs.", + } + ) + def _parse_json_from_output(self, text: str): r""" Extracts a substring that starts with the first '{' following From 12145d5a6409e08890875aeaaf0b4a22f9289e1a Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Tue, 11 Feb 2025 03:35:49 +0530 Subject: [PATCH 42/43] fix: image_list has PIL.Image object --- camel/toolkits/web_toolkit.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 6c49ab3fce..51b8868d29 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -24,6 +24,7 @@ from camel.toolkits.base import BaseToolkit from camel.toolkits.function_tool import FunctionTool from camel.types import ModelPlatformType, ModelType, RoleType +from PIL import Image # Define a module-level constant for the default ChatGPT configuration _DEFAULT_CHATGPT_CONFIG_DICT = ChatGPTConfig(temperature=0.0).as_dict() @@ -483,13 +484,15 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: raise ValueError("Failed to generate Stagehand code.") - def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> Dict[str, Any]: + def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) -> Dict[str, Any]: """ Captures multiple screenshots while scrolling and sends each screenshot to GPT-4o for analysis. Use this tool when you think visual analysis of graphs/images/or the website content would be useful Args: url (str): The webpage URL to analyze. + question (str): The question to be answered. + Returns: Dict[str, Any]: JSON response containing: @@ -589,7 +592,7 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> Dict[str, Any print("[DEBUG]: Screenshots Captured:\n", screenshots) # Analyze each screenshot with GPT-4o - gpt_results = self._analyze_screenshots_with_gpt4o(screenshots) + gpt_results = self._analyze_screenshots_with_gpt4o(question, screenshots) # Final response with GPT-4o results return { @@ -598,11 +601,12 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, url: str) -> Dict[str, Any "gpt_analysis": gpt_results } - def _analyze_screenshots_with_gpt4o(self, screenshots: List[str]) -> List[Dict[str, Any]]: + def _analyze_screenshots_with_gpt4o(self, question: str, screenshots: List[str]) -> List[Dict[str, Any]]: """ Sends each screenshot to GPT-4o for analysis. Args: + question (str): The question to be answered. screenshots (List[str]): List of screenshot file paths. Returns: @@ -614,19 +618,28 @@ def _analyze_screenshots_with_gpt4o(self, screenshots: List[str]) -> List[Dict[s results = [] - for screenshot in screenshots: + for screenshot_path in screenshots: + # Ensure the screenshot file exists before proceeding + if not os.path.exists(screenshot_path): + print(f"[ERROR]: Screenshot {screenshot_path} not found.") + continue + + # Convert the screenshot to a PIL Image object + image = Image.open(screenshot_path) + gpt_input = BaseMessage( role_name="GPT-4o Screenshot Analyzer", role_type=RoleType.USER, meta_dict=None, - content="Analyze the following screenshot and describe the visual elements. Identify key UI components, any notable content, and overall design layout." + image_list=[image], + image_detail="high", + content=f"Analyze this screenshot and describe the visual elements. {question}" ) - # Debugging: Check input message if self.debug: - print(f"[DEBUG] Sending GPT-4o Input for {screenshot}") + print(f"[DEBUG] Sending GPT-4o Input for {screenshot_path}") - # Send to GPT-4o model + # Send to GPT-4o model for **vision processing** response = self.agent.step(input_message=gpt_input) # Debugging: Check response @@ -641,11 +654,12 @@ def _analyze_screenshots_with_gpt4o(self, screenshots: List[str]) -> List[Dict[s ) results.append( - {"screenshot": screenshot, "analysis": gpt_response} + {"screenshot": screenshot_path, "analysis": gpt_response} ) return results + def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" Internal method that executes the Stagehand code under From 84c12ef72a2f0f39c468abe79b41e29e6c7f4b30 Mon Sep 17 00:00:00 2001 From: X-TRON404 <55325140+X-TRON404@users.noreply.github.com> Date: Tue, 11 Feb 2025 09:53:28 +0530 Subject: [PATCH 43/43] fix: link in stagehand_tool & precommit checks --- camel/toolkits/web_toolkit.py | 85 ++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/camel/toolkits/web_toolkit.py b/camel/toolkits/web_toolkit.py index 51b8868d29..540d1931c0 100644 --- a/camel/toolkits/web_toolkit.py +++ b/camel/toolkits/web_toolkit.py @@ -15,6 +15,8 @@ import os from typing import Any, Dict, List +from PIL import Image + from camel.agents import ChatAgent from camel.configs import ChatGPTConfig from camel.interpreters.subprocess_interpreter import SubprocessInterpreter @@ -24,7 +26,6 @@ from camel.toolkits.base import BaseToolkit from camel.toolkits.function_tool import FunctionTool from camel.types import ModelPlatformType, ModelType, RoleType -from PIL import Image # Define a module-level constant for the default ChatGPT configuration _DEFAULT_CHATGPT_CONFIG_DICT = ChatGPTConfig(temperature=0.0).as_dict() @@ -244,9 +245,12 @@ def __init__(self, high_level_task: str): variable called 'updated_state'. For example: - IMPORTANT: - All of the values of the 'updated_state' should always be a string + - All of the values of the + 'updated_state' should always be a string or a number never a Object. - The link should be an absolute url extracted from the url bar. + - The link should be an absolute url extracted from the url bar. + - Always extract the link in the end to + represent the last webpage visited. - Convert the value to a string or array before calling the includes() method on it. @@ -483,16 +487,17 @@ def _generate_stagehand_code(self, high_level_task: str) -> str: else: raise ValueError("Failed to generate Stagehand code.") - - def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) -> Dict[str, Any]: - """ - Captures multiple screenshots while scrolling and sends each screenshot to GPT-4o for analysis. - Use this tool when you think visual analysis of graphs/images/or the website content would be useful - + def stagehand_screenshot_and_analyze_with_gpt4o( + self, question: str, url: str + ) -> str: + r""" + Captures multiple screenshots while scrolling and sends each screenshot + to GPT-4o for analysis. + Args: url (str): The webpage URL to analyze. question (str): The question to be answered. - + Returns: Dict[str, Any]: JSON response containing: @@ -523,21 +528,28 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) - let screenshots = []; let totalHeight = 0; - let viewportHeight = await page.evaluate(() => window.innerHeight); - let scrollHeight = await page.evaluate(() => document.body.scrollHeight); + let viewportHeight = await + page.evaluate(() => window.innerHeight); + let scrollHeight = await page.evaluate(() => + document.body.scrollHeight + ); + let scrollY = 0; let index = 0; // Scroll and take multiple screenshots while (scrollY < scrollHeight) {{ - let screenshot_path = "{screenshot_base}_" + index + ".png"; + let screenshot_path = + "{screenshot_base}_" + index + ".png"; await page.screenshot({{ path: screenshot_path }}); screenshots.push(screenshot_path); totalHeight += viewportHeight; scrollY += viewportHeight; - await page.evaluate((height) => window.scrollBy(0, height), viewportHeight); - await page.act({{ action: "Wait a second for scrolling to complete." }}); + await page.evaluate((height) => + window.scrollBy(0, height), viewportHeight); + await page.act({{ action: "Wait a second for" + + "scrolling to complete." }}); index++; }} @@ -548,7 +560,8 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) - "link": "{url}" }}; - console.log("updated_state: ", JSON.stringify(extractedData, null, 2)); + console.log("updated_state: ", + JSON.stringify(extractedData, null, 2)); }} catch (error) {{ console.error("updated_state: ", JSON.stringify({{ @@ -570,10 +583,8 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) - exec_result = node_process.run(js_code, "node") - # Debugging: Print raw output from node print(f"[DEBUG] Raw Node.js Output:\n{exec_result}") - # Parse the JSON output using the unchanged _parse_json_from_output function raw_json = self._parse_json_from_output(exec_result) # Convert JSON string to a Python dictionary @@ -581,28 +592,40 @@ def stagehand_screenshot_and_analyze_with_gpt4o(self, question: str, url: str) - final_json = json.loads(raw_json) except json.JSONDecodeError: print("[ERROR]: Failed to parse JSON from extracted output.") - return {"status": "error", "message": "Failed to parse extracted JSON."} + return json.dumps( + { + "status": "error", + "message": "Failed to parse extracted JSON.", + } + ) if "screenshots" not in final_json: print("[ERROR]: No valid screenshots found.") - return {"status": "error", "message": "No screenshots found in output."} + return json.dumps( + { + "status": "error", + "message": "No screenshots found in output.", + } + ) screenshots = final_json["screenshots"] print("[DEBUG]: Screenshots Captured:\n", screenshots) # Analyze each screenshot with GPT-4o - gpt_results = self._analyze_screenshots_with_gpt4o(question, screenshots) + gpt_results = self._analyze_screenshots_with_gpt4o( + question, screenshots + ) # Final response with GPT-4o results - return { - "status": "success", - "link": url, - "gpt_analysis": gpt_results - } + return json.dumps( + {"status": "success", "link": url, "gpt_analysis": gpt_results} + ) - def _analyze_screenshots_with_gpt4o(self, question: str, screenshots: List[str]) -> List[Dict[str, Any]]: - """ + def _analyze_screenshots_with_gpt4o( + self, question: str, screenshots: List[str] + ) -> List[Dict[str, Any]]: + r""" Sends each screenshot to GPT-4o for analysis. Args: @@ -633,7 +656,8 @@ def _analyze_screenshots_with_gpt4o(self, question: str, screenshots: List[str]) meta_dict=None, image_list=[image], image_detail="high", - content=f"Analyze this screenshot and describe the visual elements. {question}" + content=f"""Analyze this screenshot and describe the + visual elements. {question}""", ) if self.debug: @@ -659,7 +683,6 @@ def _analyze_screenshots_with_gpt4o(self, question: str, screenshots: List[str]) return results - def _run_stagehand_script_in_node(self, js_code: str) -> str: r""" Internal method that executes the Stagehand code under @@ -718,7 +741,7 @@ def _run_stagehand_script_in_node(self, js_code: str) -> str: "message": "No valid JSON found in node logs.", } ) - + def _parse_json_from_output(self, text: str): r""" Extracts a substring that starts with the first '{' following