featur: Add CalculatorToolComponent (#3772)
* feat: Add CalculatorToolComponent to langflow/components/tools This commit adds the CalculatorToolComponent to the langflow/components/tools directory. The CalculatorToolComponent allows users to perform basic arithmetic operations on a given expression. It includes an input for the expression and returns the result or an error message. Ref: #3757 * lint * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
2652f44d31
commit
92f59ab9e0
5 changed files with 92 additions and 17 deletions
5
poetry.lock
generated
5
poetry.lock
generated
|
|
@ -10605,11 +10605,6 @@ files = [
|
|||
{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"},
|
||||
{file = "triton-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b052da883351fdf6be3d93cedae6db3b8e3988d3b09ed221bccecfa9612230"},
|
||||
{file = "triton-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd34f19a8582af96e6291d4afce25dac08cb2a5d218c599163761e8e0827208e"},
|
||||
{file = "triton-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d5e10de8c011adeb7c878c6ce0dd6073b14367749e34467f1cff2bde1b78253"},
|
||||
{file = "triton-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8903767951bf86ec960b4fe4e21bc970055afc65e9d57e916d79ae3c93665e3"},
|
||||
{file = "triton-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41004fb1ae9a53fcb3e970745feb87f0e3c94c6ce1ba86e95fa3b8537894bef7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
|
|||
82
src/backend/base/langflow/components/tools/Calculator.py
Normal file
82
src/backend/base/langflow/components/tools/Calculator.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import ast
|
||||
import operator
|
||||
from typing import List
|
||||
from pydantic import BaseModel, Field
|
||||
from langflow.base.langchain_utilities.model import LCToolComponent
|
||||
from langflow.inputs import MessageTextInput
|
||||
from langflow.schema import Data
|
||||
from langflow.field_typing import Tool
|
||||
from langchain.tools import StructuredTool
|
||||
|
||||
|
||||
class CalculatorToolComponent(LCToolComponent):
|
||||
display_name = "Calculator"
|
||||
description = "Perform basic arithmetic operations on a given expression."
|
||||
icon = "calculator"
|
||||
name = "CalculatorTool"
|
||||
|
||||
inputs = [
|
||||
MessageTextInput(
|
||||
name="expression",
|
||||
display_name="Expression",
|
||||
info="The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').",
|
||||
),
|
||||
]
|
||||
|
||||
class CalculatorToolSchema(BaseModel):
|
||||
expression: str = Field(..., description="The arithmetic expression to evaluate.")
|
||||
|
||||
def run_model(self) -> List[Data]:
|
||||
return self._evaluate_expression(self.expression)
|
||||
|
||||
def build_tool(self) -> Tool:
|
||||
return StructuredTool.from_function(
|
||||
name="calculator",
|
||||
description="Evaluate basic arithmetic expressions. Input should be a string containing the expression.",
|
||||
func=self._evaluate_expression,
|
||||
args_schema=self.CalculatorToolSchema,
|
||||
)
|
||||
|
||||
def _evaluate_expression(self, expression: str) -> List[Data]:
|
||||
try:
|
||||
# Define the allowed operators
|
||||
operators = {
|
||||
ast.Add: operator.add,
|
||||
ast.Sub: operator.sub,
|
||||
ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv,
|
||||
ast.Pow: operator.pow,
|
||||
}
|
||||
|
||||
def eval_expr(node):
|
||||
if isinstance(node, ast.Num):
|
||||
return node.n
|
||||
elif isinstance(node, ast.BinOp):
|
||||
return operators[type(node.op)](eval_expr(node.left), eval_expr(node.right))
|
||||
elif isinstance(node, ast.UnaryOp):
|
||||
return operators[type(node.op)](eval_expr(node.operand))
|
||||
else:
|
||||
raise TypeError(node)
|
||||
|
||||
# Parse the expression and evaluate it
|
||||
tree = ast.parse(expression, mode="eval")
|
||||
result = eval_expr(tree.body)
|
||||
|
||||
# Format the result to a reasonable number of decimal places
|
||||
formatted_result = f"{result:.6f}".rstrip("0").rstrip(".")
|
||||
|
||||
self.status = formatted_result
|
||||
return [Data(data={"result": formatted_result})]
|
||||
|
||||
except (SyntaxError, TypeError, KeyError) as e:
|
||||
error_message = f"Invalid expression: {str(e)}"
|
||||
self.status = error_message
|
||||
return [Data(data={"error": error_message})]
|
||||
except ZeroDivisionError:
|
||||
error_message = "Error: Division by zero"
|
||||
self.status = error_message
|
||||
return [Data(data={"error": error_message})]
|
||||
except Exception as e:
|
||||
error_message = f"Error: {str(e)}"
|
||||
self.status = error_message
|
||||
return [Data(data={"error": error_message})]
|
||||
|
|
@ -10,6 +10,7 @@ from .SearXNGTool import SearXNGToolComponent
|
|||
from .SerpAPI import SerpAPIComponent
|
||||
from .WikipediaAPI import WikipediaAPIComponent
|
||||
from .WolframAlphaAPI import WolframAlphaAPIComponent
|
||||
from .Calculator import CalculatorToolComponent
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -25,4 +26,5 @@ __all__ = [
|
|||
"SerpAPIComponent",
|
||||
"WikipediaAPIComponent",
|
||||
"WolframAlphaAPIComponent",
|
||||
"CalculatorToolComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1159,7 +1159,7 @@
|
|||
"description": "Perform basic arithmetic operations on a given expression.",
|
||||
"display_name": "Calculator",
|
||||
"documentation": "",
|
||||
"edited": true,
|
||||
"edited": false,
|
||||
"field_order": [
|
||||
"expression"
|
||||
],
|
||||
|
|
@ -1176,8 +1176,7 @@
|
|||
"name": "api_run_model",
|
||||
"selected": "Data",
|
||||
"types": [
|
||||
"Data",
|
||||
"list"
|
||||
"Data"
|
||||
],
|
||||
"value": "__UNDEFINED__"
|
||||
},
|
||||
|
|
@ -1188,8 +1187,7 @@
|
|||
"name": "api_build_tool",
|
||||
"selected": "Tool",
|
||||
"types": [
|
||||
"Tool",
|
||||
"Sequence"
|
||||
"Tool"
|
||||
],
|
||||
"value": "__UNDEFINED__"
|
||||
}
|
||||
|
|
@ -1213,7 +1211,7 @@
|
|||
"show": true,
|
||||
"title_case": false,
|
||||
"type": "code",
|
||||
"value": "import ast\r\nimport operator\r\nfrom typing import List\r\nfrom pydantic import BaseModel, Field\r\nfrom langflow.base.langchain_utilities.model import LCToolComponent\r\nfrom langflow.inputs import MessageTextInput\r\nfrom langflow.schema import Data\r\nfrom langflow.field_typing import Tool\r\nfrom langchain.tools import StructuredTool\r\n\r\nclass CalculatorToolComponent(LCToolComponent):\r\n display_name = \"Calculator\"\r\n description = \"Perform basic arithmetic operations on a given expression.\"\r\n icon = \"calculator\"\r\n name = \"CalculatorTool\"\r\n\r\n inputs = [\r\n MessageTextInput(\r\n name=\"expression\",\r\n display_name=\"Expression\",\r\n info=\"The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').\",\r\n ),\r\n ]\r\n\r\n class CalculatorToolSchema(BaseModel):\r\n expression: str = Field(..., description=\"The arithmetic expression to evaluate.\")\r\n\r\n def run_model(self) -> List[Data]:\r\n return self._evaluate_expression(self.expression)\r\n\r\n def build_tool(self) -> Tool:\r\n return StructuredTool.from_function(\r\n name=\"calculator\",\r\n description=\"Evaluate basic arithmetic expressions. Input should be a string containing the expression.\",\r\n func=self._evaluate_expression,\r\n args_schema=self.CalculatorToolSchema,\r\n )\r\n\r\n def _evaluate_expression(self, expression: str) -> List[Data]:\r\n try:\r\n # Define the allowed operators\r\n operators = {\r\n ast.Add: operator.add,\r\n ast.Sub: operator.sub,\r\n ast.Mult: operator.mul,\r\n ast.Div: operator.truediv,\r\n ast.Pow: operator.pow,\r\n }\r\n\r\n def eval_expr(node):\r\n if isinstance(node, ast.Num):\r\n return node.n\r\n elif isinstance(node, ast.BinOp):\r\n return operators[type(node.op)](eval_expr(node.left), eval_expr(node.right))\r\n elif isinstance(node, ast.UnaryOp):\r\n return operators[type(node.op)](eval_expr(node.operand))\r\n else:\r\n raise TypeError(node)\r\n\r\n # Parse the expression and evaluate it\r\n tree = ast.parse(expression, mode='eval')\r\n result = eval_expr(tree.body)\r\n\r\n # Format the result to a reasonable number of decimal places\r\n formatted_result = f\"{result:.6f}\".rstrip('0').rstrip('.')\r\n\r\n self.status = formatted_result\r\n return [Data(data={\"result\": formatted_result})]\r\n\r\n except (SyntaxError, TypeError, KeyError) as e:\r\n error_message = f\"Invalid expression: {str(e)}\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]\r\n except ZeroDivisionError:\r\n error_message = \"Error: Division by zero\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]\r\n except Exception as e:\r\n error_message = f\"Error: {str(e)}\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]"
|
||||
"value": "import ast\nimport operator\nfrom typing import List\nfrom pydantic import BaseModel, Field\nfrom langflow.base.langchain_utilities.model import LCToolComponent\nfrom langflow.inputs import MessageTextInput\nfrom langflow.schema import Data\nfrom langflow.field_typing import Tool\nfrom langchain.tools import StructuredTool\n\n\nclass CalculatorToolComponent(LCToolComponent):\n display_name = \"Calculator\"\n description = \"Perform basic arithmetic operations on a given expression.\"\n icon = \"calculator\"\n name = \"CalculatorTool\"\n\n inputs = [\n MessageTextInput(\n name=\"expression\",\n display_name=\"Expression\",\n info=\"The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').\",\n ),\n ]\n\n class CalculatorToolSchema(BaseModel):\n expression: str = Field(..., description=\"The arithmetic expression to evaluate.\")\n\n def run_model(self) -> List[Data]:\n return self._evaluate_expression(self.expression)\n\n def build_tool(self) -> Tool:\n return StructuredTool.from_function(\n name=\"calculator\",\n description=\"Evaluate basic arithmetic expressions. Input should be a string containing the expression.\",\n func=self._evaluate_expression,\n args_schema=self.CalculatorToolSchema,\n )\n\n def _evaluate_expression(self, expression: str) -> List[Data]:\n try:\n # Define the allowed operators\n operators = {\n ast.Add: operator.add,\n ast.Sub: operator.sub,\n ast.Mult: operator.mul,\n ast.Div: operator.truediv,\n ast.Pow: operator.pow,\n }\n\n def eval_expr(node):\n if isinstance(node, ast.Num):\n return node.n\n elif isinstance(node, ast.BinOp):\n return operators[type(node.op)](eval_expr(node.left), eval_expr(node.right))\n elif isinstance(node, ast.UnaryOp):\n return operators[type(node.op)](eval_expr(node.operand))\n else:\n raise TypeError(node)\n\n # Parse the expression and evaluate it\n tree = ast.parse(expression, mode=\"eval\")\n result = eval_expr(tree.body)\n\n # Format the result to a reasonable number of decimal places\n formatted_result = f\"{result:.6f}\".rstrip(\"0\").rstrip(\".\")\n\n self.status = formatted_result\n return [Data(data={\"result\": formatted_result})]\n\n except (SyntaxError, TypeError, KeyError) as e:\n error_message = f\"Invalid expression: {str(e)}\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n except ZeroDivisionError:\n error_message = \"Error: Division by zero\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n except Exception as e:\n error_message = f\"Error: {str(e)}\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n"
|
||||
},
|
||||
"expression": {
|
||||
"_input_type": "MessageTextInput",
|
||||
|
|
|
|||
|
|
@ -2258,7 +2258,7 @@
|
|||
"description": "Perform basic arithmetic operations on a given expression.",
|
||||
"display_name": "Calculator",
|
||||
"documentation": "",
|
||||
"edited": true,
|
||||
"edited": false,
|
||||
"field_order": [
|
||||
"expression"
|
||||
],
|
||||
|
|
@ -2275,8 +2275,7 @@
|
|||
"name": "api_run_model",
|
||||
"selected": "Data",
|
||||
"types": [
|
||||
"Data",
|
||||
"list"
|
||||
"Data"
|
||||
],
|
||||
"value": "__UNDEFINED__"
|
||||
},
|
||||
|
|
@ -2287,8 +2286,7 @@
|
|||
"name": "api_build_tool",
|
||||
"selected": "Tool",
|
||||
"types": [
|
||||
"Tool",
|
||||
"Sequence"
|
||||
"Tool"
|
||||
],
|
||||
"value": "__UNDEFINED__"
|
||||
}
|
||||
|
|
@ -2312,7 +2310,7 @@
|
|||
"show": true,
|
||||
"title_case": false,
|
||||
"type": "code",
|
||||
"value": "import ast\r\nimport operator\r\nfrom typing import List\r\nfrom pydantic import BaseModel, Field\r\nfrom langflow.base.langchain_utilities.model import LCToolComponent\r\nfrom langflow.inputs import MessageTextInput\r\nfrom langflow.schema import Data\r\nfrom langflow.field_typing import Tool\r\nfrom langchain.tools import StructuredTool\r\n\r\nclass CalculatorToolComponent(LCToolComponent):\r\n display_name = \"Calculator\"\r\n description = \"Perform basic arithmetic operations on a given expression.\"\r\n icon = \"calculator\"\r\n name = \"CalculatorTool\"\r\n\r\n inputs = [\r\n MessageTextInput(\r\n name=\"expression\",\r\n display_name=\"Expression\",\r\n info=\"The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').\",\r\n ),\r\n ]\r\n\r\n class CalculatorToolSchema(BaseModel):\r\n expression: str = Field(..., description=\"The arithmetic expression to evaluate.\")\r\n\r\n def run_model(self) -> List[Data]:\r\n return self._evaluate_expression(self.expression)\r\n\r\n def build_tool(self) -> Tool:\r\n return StructuredTool.from_function(\r\n name=\"calculator\",\r\n description=\"Evaluate basic arithmetic expressions. Input should be a string containing the expression.\",\r\n func=self._evaluate_expression,\r\n args_schema=self.CalculatorToolSchema,\r\n )\r\n\r\n def _evaluate_expression(self, expression: str) -> List[Data]:\r\n try:\r\n # Define the allowed operators\r\n operators = {\r\n ast.Add: operator.add,\r\n ast.Sub: operator.sub,\r\n ast.Mult: operator.mul,\r\n ast.Div: operator.truediv,\r\n ast.Pow: operator.pow,\r\n }\r\n\r\n def eval_expr(node):\r\n if isinstance(node, ast.Num):\r\n return node.n\r\n elif isinstance(node, ast.BinOp):\r\n return operators[type(node.op)](eval_expr(node.left), eval_expr(node.right))\r\n elif isinstance(node, ast.UnaryOp):\r\n return operators[type(node.op)](eval_expr(node.operand))\r\n else:\r\n raise TypeError(node)\r\n\r\n # Parse the expression and evaluate it\r\n tree = ast.parse(expression, mode='eval')\r\n result = eval_expr(tree.body)\r\n\r\n # Format the result to a reasonable number of decimal places\r\n formatted_result = f\"{result:.6f}\".rstrip('0').rstrip('.')\r\n\r\n self.status = formatted_result\r\n return [Data(data={\"result\": formatted_result})]\r\n\r\n except (SyntaxError, TypeError, KeyError) as e:\r\n error_message = f\"Invalid expression: {str(e)}\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]\r\n except ZeroDivisionError:\r\n error_message = \"Error: Division by zero\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]\r\n except Exception as e:\r\n error_message = f\"Error: {str(e)}\"\r\n self.status = error_message\r\n return [Data(data={\"error\": error_message})]"
|
||||
"value": "import ast\nimport operator\nfrom typing import List\nfrom pydantic import BaseModel, Field\nfrom langflow.base.langchain_utilities.model import LCToolComponent\nfrom langflow.inputs import MessageTextInput\nfrom langflow.schema import Data\nfrom langflow.field_typing import Tool\nfrom langchain.tools import StructuredTool\n\n\nclass CalculatorToolComponent(LCToolComponent):\n display_name = \"Calculator\"\n description = \"Perform basic arithmetic operations on a given expression.\"\n icon = \"calculator\"\n name = \"CalculatorTool\"\n\n inputs = [\n MessageTextInput(\n name=\"expression\",\n display_name=\"Expression\",\n info=\"The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').\",\n ),\n ]\n\n class CalculatorToolSchema(BaseModel):\n expression: str = Field(..., description=\"The arithmetic expression to evaluate.\")\n\n def run_model(self) -> List[Data]:\n return self._evaluate_expression(self.expression)\n\n def build_tool(self) -> Tool:\n return StructuredTool.from_function(\n name=\"calculator\",\n description=\"Evaluate basic arithmetic expressions. Input should be a string containing the expression.\",\n func=self._evaluate_expression,\n args_schema=self.CalculatorToolSchema,\n )\n\n def _evaluate_expression(self, expression: str) -> List[Data]:\n try:\n # Define the allowed operators\n operators = {\n ast.Add: operator.add,\n ast.Sub: operator.sub,\n ast.Mult: operator.mul,\n ast.Div: operator.truediv,\n ast.Pow: operator.pow,\n }\n\n def eval_expr(node):\n if isinstance(node, ast.Num):\n return node.n\n elif isinstance(node, ast.BinOp):\n return operators[type(node.op)](eval_expr(node.left), eval_expr(node.right))\n elif isinstance(node, ast.UnaryOp):\n return operators[type(node.op)](eval_expr(node.operand))\n else:\n raise TypeError(node)\n\n # Parse the expression and evaluate it\n tree = ast.parse(expression, mode=\"eval\")\n result = eval_expr(tree.body)\n\n # Format the result to a reasonable number of decimal places\n formatted_result = f\"{result:.6f}\".rstrip(\"0\").rstrip(\".\")\n\n self.status = formatted_result\n return [Data(data={\"result\": formatted_result})]\n\n except (SyntaxError, TypeError, KeyError) as e:\n error_message = f\"Invalid expression: {str(e)}\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n except ZeroDivisionError:\n error_message = \"Error: Division by zero\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n except Exception as e:\n error_message = f\"Error: {str(e)}\"\n self.status = error_message\n return [Data(data={\"error\": error_message})]\n"
|
||||
},
|
||||
"expression": {
|
||||
"_input_type": "MessageTextInput",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue