From b281a7d25e7a1d6ea50c673f8867cc04abfcd77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Wed, 17 Jul 2024 19:41:03 +0200 Subject: [PATCH] feat: migrate Search APIs to Component syntax (#2637) * feat: migrate bingsearch to Component syntax * all * fix style * [autofix.ci] apply automated fixes * feat: Update BingSearchAPI and WikipediaAPI components Refactor the BingSearchAPI and WikipediaAPI components to improve code organization and readability. Migrate BingSearchAPI to Component syntax and make initialization separate from the constructor. Update the condition to run end_all_traces in the BingSearchAPIComponent. Also, update the WikipediaAPIComponent to use the WikipediaAPIWrapper with the specified parameters. * update lock --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida --- poetry.lock | 156 +++++++++++++++--- pyproject.toml | 2 + .../base/langflow/base/agents/agent.py | 2 +- .../base/langchain_utilities/__init__.py | 0 .../base/langchain_utilities/model.py | 39 +++++ .../BingSearchAPIWrapper.py | 32 ---- .../GoogleSearchAPIWrapper.py | 24 --- .../GoogleSerperAPIWrapper.py | 51 ------ .../langchain_utilities/SearchApi.py | 55 ------ .../langchain_utilities/SearxSearchWrapper.py | 36 ---- .../langchain_utilities/SerpAPIWrapper.py | 33 ---- .../WikipediaAPIWrapper.py | 32 ---- .../WolframAlphaAPIWrapper.py | 20 --- .../components/tools/BingSearchAPI.py | 46 ++++++ .../components/tools/GoogleSearchAPI.py | 45 +++++ .../components/tools/GoogleSerperAPI.py | 42 +++++ .../langflow/components/tools/SearchAPI.py | 44 +++++ .../components/tools/SearchAPITool.py | 38 ----- .../langflow/components/tools/SearchApi.py | 55 ------ .../base/langflow/components/tools/SerpAPI.py | 43 +++++ .../langflow/components/tools/WikipediaAPI.py | 44 +++++ .../components/tools/WolframAlphaAPI.py | 34 ++++ .../langflow/components/tools/__init__.py | 23 ++- .../base/langflow/field_typing/constants.py | 3 +- src/backend/base/poetry.lock | 8 +- 25 files changed, 499 insertions(+), 408 deletions(-) create mode 100644 src/backend/base/langflow/base/langchain_utilities/__init__.py create mode 100644 src/backend/base/langflow/base/langchain_utilities/model.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/SearchApi.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py delete mode 100644 src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py create mode 100644 src/backend/base/langflow/components/tools/BingSearchAPI.py create mode 100644 src/backend/base/langflow/components/tools/GoogleSearchAPI.py create mode 100644 src/backend/base/langflow/components/tools/GoogleSerperAPI.py create mode 100644 src/backend/base/langflow/components/tools/SearchAPI.py delete mode 100644 src/backend/base/langflow/components/tools/SearchAPITool.py delete mode 100644 src/backend/base/langflow/components/tools/SearchApi.py create mode 100644 src/backend/base/langflow/components/tools/SerpAPI.py create mode 100644 src/backend/base/langflow/components/tools/WikipediaAPI.py create mode 100644 src/backend/base/langflow/components/tools/WolframAlphaAPI.py diff --git a/poetry.lock b/poetry.lock index 1f0c75e5c..53fdc1c9c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -178,13 +178,13 @@ files = [ [[package]] name = "anthropic" -version = "0.31.1" +version = "0.31.2" description = "The official Python library for the anthropic API" optional = false python-versions = ">=3.7" files = [ - {file = "anthropic-0.31.1-py3-none-any.whl", hash = "sha256:d18809cbdecee2296f418e30beb2d0a8ecc225c065a1494cb02348af48794ff8"}, - {file = "anthropic-0.31.1.tar.gz", hash = "sha256:d2248dfc15f7fc7823ac0bb9d48e73429e9b1ed8327ac66839d00cdb2f29d3cb"}, + {file = "anthropic-0.31.2-py3-none-any.whl", hash = "sha256:28d176b98c72615bfae30f0a9eee6297cc33bf52535d38156fc2805556e2f09b"}, + {file = "anthropic-0.31.2.tar.gz", hash = "sha256:0134b73df8d1f142fc68675fbadb75e920054e9e3437b99df63f10f0fc6ac26f"}, ] [package.dependencies] @@ -388,6 +388,21 @@ files = [ {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, ] +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + [[package]] name = "bce-python-sdk" version = "0.9.17" @@ -2726,8 +2741,8 @@ files = [ [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} greenlet = [ - {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, + {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, ] "zope.event" = "*" "zope.interface" = "*" @@ -2886,12 +2901,12 @@ files = [ google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = [ - {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] grpcio-status = [ - {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" @@ -4162,6 +4177,24 @@ files = [ {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] +[[package]] +name = "jaraco-context" +version = "5.3.0" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jaraco.context-5.3.0-py3-none-any.whl", hash = "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266"}, + {file = "jaraco.context-5.3.0.tar.gz", hash = "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["portend", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + [[package]] name = "jedi" version = "0.19.1" @@ -4600,19 +4633,19 @@ tests = ["aiohttp", "duckdb", "pandas (>=1.4)", "polars (>=0.19)", "pytest", "py [[package]] name = "langchain" -version = "0.2.8" +version = "0.2.9" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.8-py3-none-any.whl", hash = "sha256:53e7dfe50294a14200f33bec22b4e14cb63857ccf0a5500b0d18b0fd51285d58"}, - {file = "langchain-0.2.8.tar.gz", hash = "sha256:7fecb309e3558cde4e5cf7e9ffb7c1ab3f07121c40a7ff3b0c27135f8120c296"}, + {file = "langchain-0.2.9-py3-none-any.whl", hash = "sha256:be23fcb29adbd5059944f1fed08fa575f0739d420b1c4127531e0fbf5663fcca"}, + {file = "langchain-0.2.9.tar.gz", hash = "sha256:cc326a7f6347787a19882928c324433b1a79df629bba45604b2d26495ee5d69c"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.2.19,<0.3.0" +langchain-core = ">=0.2.20,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = [ @@ -4795,6 +4828,39 @@ langchain = ">=0.0.335" protobuf = ">=4.25.0" pytz = ">=2023.3.post1" +[[package]] +name = "langchain-google-community" +version = "1.0.6" +description = "An integration package connecting miscellaneous Google's products and LangChain" +optional = false +python-versions = "<4.0,>=3.8.1" +files = [ + {file = "langchain_google_community-1.0.6-py3-none-any.whl", hash = "sha256:5c2f18aebfb60b51f68dc1608d09ac3e8231743d75c545f409230f7bee641faf"}, + {file = "langchain_google_community-1.0.6.tar.gz", hash = "sha256:081ed78702426a62187c86984c169508c432fc13cd2b08dbf5b553b40bb160b3"}, +] + +[package.dependencies] +google-api-core = ">=2.17.1,<3.0.0" +google-api-python-client = ">=2.122.0,<3.0.0" +grpcio = ">=1.62.0,<2.0.0" +langchain-community = ">=0.2.1,<0.3.0" +langchain-core = ">=0.2.9,<0.3" +tenacity = ">=8.3.0,<8.4.0" + +[package.extras] +bigquery = ["google-cloud-bigquery (>=3.21.0,<4.0.0)"] +docai = ["gapic-google-longrunning (>=0.11.2,<0.12.0)", "google-cloud-contentwarehouse (>=0.7.7,<0.8.0)", "google-cloud-documentai (>=2.26.0,<3.0.0)", "google-cloud-documentai-toolbox (>=0.13.3a0,<0.14.0)"] +drive = ["google-auth-httplib2 (>=0.2.0,<0.3.0)", "google-auth-oauthlib (>=1.2.0,<2.0.0)"] +featurestore = ["db-dtypes (>=1.2.0,<2.0.0)", "google-cloud-aiplatform (>=1.56.0,<2.0.0)", "google-cloud-bigquery-storage (>=2.6.0,<3)", "pandas (>=1.0.0)", "pandas (>=2.0.0,<3.0)", "pyarrow (>=6.0.1)", "pydantic (>=2.7.4,<3.0.0)"] +gcs = ["google-cloud-storage (>=2.16.0,<3.0.0)"] +gmail = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "google-auth-httplib2 (>=0.2.0,<0.3.0)", "google-auth-oauthlib (>=1.2.0,<2.0.0)"] +places = ["googlemaps (>=4.10.0,<5.0.0)"] +speech = ["google-cloud-speech (>=2.26.0,<3.0.0)"] +texttospeech = ["google-cloud-texttospeech (>=2.16.3,<3.0.0)"] +translate = ["google-cloud-translate (>=3.15.3,<4.0.0)"] +vertexaisearch = ["google-cloud-discoveryengine (>=0.11.13,<0.12.0)"] +vision = ["google-cloud-vision (>=3.7.2,<4.0.0)"] + [[package]] name = "langchain-google-genai" version = "1.0.7" @@ -5100,13 +5166,13 @@ requests = ">=2,<3" [[package]] name = "langwatch" -version = "0.1.9" +version = "0.1.10" description = "Python SDK for LangWatch for monitoring your LLMs" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langwatch-0.1.9-py3-none-any.whl", hash = "sha256:d082f70bb7f6aa67623281e3e624065932bc6e5729322637d8957cc63942a007"}, - {file = "langwatch-0.1.9.tar.gz", hash = "sha256:3f044b668239b0e4cc244635f8ceeb7e10948c736f6b60bcda7c26852308b2f8"}, + {file = "langwatch-0.1.10-py3-none-any.whl", hash = "sha256:271902080b6e0e5ee5aca7e244995b7737bbc54ead956bc16da50445c53d4dce"}, + {file = "langwatch-0.1.10.tar.gz", hash = "sha256:4350aefbbe4ba5ff5f614f10bbf73ca36ccab4f010f66fd66fc826a1a14ade4b"}, ] [package.dependencies] @@ -5199,8 +5265,8 @@ psutil = ">=5.9.1" pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" requests = [ - {version = ">=2.32.2", markers = "python_version > \"3.11\""}, {version = ">=2.26.0", markers = "python_version <= \"3.11\""}, + {version = ">=2.32.2", markers = "python_version > \"3.11\""}, ] tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.11\""} @@ -5752,6 +5818,17 @@ files = [ {file = "monotonic-1.6.tar.gz", hash = "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7"}, ] +[[package]] +name = "more-itertools" +version = "10.3.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.8" +files = [ + {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, + {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, +] + [[package]] name = "mpmath" version = "1.3.0" @@ -6790,9 +6867,9 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -9883,18 +9960,18 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "structlog" -version = "24.3.0" +version = "24.4.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.3.0-py3-none-any.whl", hash = "sha256:ee4c2c7ef7971201f89f85893a4470ecd03bbd97bb54d75581225fdb894689a4"}, - {file = "structlog-24.3.0.tar.gz", hash = "sha256:bcf6b890cf8b48c35fa127ea79c155c79b9e6a4a826f4ce9dfc3bebd72f07fa8"}, + {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, + {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, ] [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -9977,13 +10054,13 @@ files = [ [[package]] name = "tenacity" -version = "8.5.0" +version = "8.3.0" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687"}, - {file = "tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78"}, + {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, + {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, ] [package.extras] @@ -11383,6 +11460,28 @@ files = [ [package.extras] dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] +[[package]] +name = "wolframalpha" +version = "5.1.3" +description = "Wolfram|Alpha 2.0 API client" +optional = false +python-versions = ">=3.8" +files = [ + {file = "wolframalpha-5.1.3-py3-none-any.whl", hash = "sha256:549b44e64595c5845be4c94f2b306a84832157bef422b20937cbca44b48ee117"}, + {file = "wolframalpha-5.1.3.tar.gz", hash = "sha256:56226efeca0f55acec5e17dd2f6537a178d0bf4feec4df0615165e2968bb49b8"}, +] + +[package.dependencies] +httpx = "*" +"jaraco.context" = "*" +more-itertools = "*" +multidict = "*" +xmltodict = "*" + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["keyring", "pmxbot", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + [[package]] name = "wrapt" version = "1.16.0" @@ -11487,6 +11586,17 @@ files = [ {file = "XlsxWriter-3.2.0.tar.gz", hash = "sha256:9977d0c661a72866a61f9f7a809e25ebbb0fb7036baa3b9fe74afcfca6b3cb8c"}, ] +[[package]] +name = "xmltodict" +version = "0.13.0" +description = "Makes working with XML feel like you are working with JSON" +optional = false +python-versions = ">=3.4" +files = [ + {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, + {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, +] + [[package]] name = "xxhash" version = "3.4.1" @@ -11859,4 +11969,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "180a20c1cc6b75974734c6d7f2e623c48528669622e1acb3ff22fee39eb6f24a" +content-hash = "56dbd5894cb81a0c9b0ae7bae0f2664b276a25b3f936ac33e44367ecbfdc8b73" diff --git a/pyproject.toml b/pyproject.toml index 7df516955..2c2876ad4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,6 +102,8 @@ crewai = {extras = ["tools"], version = "^0.36.0"} langwatch = "^0.1.9" langsmith = "^0.1.86" yfinance = "^0.2.40" +langchain-google-community = "^1.0.6" +wolframalpha = "^5.1.3" [tool.poetry.group.dev.dependencies] diff --git a/src/backend/base/langflow/base/agents/agent.py b/src/backend/base/langflow/base/agents/agent.py index 5475e77e8..e4e9a47bf 100644 --- a/src/backend/base/langflow/base/agents/agent.py +++ b/src/backend/base/langflow/base/agents/agent.py @@ -71,7 +71,7 @@ class LCToolsAgentComponent(LCAgentComponent): HandleInput( name="tools", display_name="Tools", - input_types=["Tool"], + input_types=["Tool", "BaseTool"], is_list=True, ), HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True), diff --git a/src/backend/base/langflow/base/langchain_utilities/__init__.py b/src/backend/base/langflow/base/langchain_utilities/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/base/langflow/base/langchain_utilities/model.py b/src/backend/base/langflow/base/langchain_utilities/model.py new file mode 100644 index 000000000..9a32c3c68 --- /dev/null +++ b/src/backend/base/langflow/base/langchain_utilities/model.py @@ -0,0 +1,39 @@ +from abc import abstractmethod +from typing import Union + + +from langflow.custom import Component +from langflow.io import Output +from langflow.schema import Data +from langchain_core.tools import BaseTool + + +class LCToolComponent(Component): + trace_type = "tool" + outputs = [ + Output(name="api_run_model", display_name="Data", method="run_model"), + Output(name="api_build_tool", display_name="Tool", method="build_tool"), + ] + + def _validate_outputs(self): + required_output_methods = ["run_model", "build_tool"] + output_names = [output.name for output in self.outputs] + for method_name in required_output_methods: + if method_name not in output_names: + raise ValueError(f"Output with name '{method_name}' must be defined.") + elif not hasattr(self, method_name): + raise ValueError(f"Method '{method_name}' must be defined.") + + @abstractmethod + def run_model(self) -> Union[Data, list[Data]]: + """ + Run model and return the output. + """ + pass + + @abstractmethod + def build_tool(self) -> BaseTool: + """ + Build the tool. + """ + pass diff --git a/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py deleted file mode 100644 index 04520dd33..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py +++ /dev/null @@ -1,32 +0,0 @@ -# Assuming `BingSearchAPIWrapper` is a class that exists in the context -# and has the appropriate methods and attributes. -# We need to make sure this class is importable from the context where this code will be running. -from langchain_community.utilities.bing_search import BingSearchAPIWrapper - -from langflow.custom import CustomComponent - - -class BingSearchAPIWrapperComponent(CustomComponent): - display_name = "BingSearchAPIWrapper" - description = "Wrapper for Bing Search API." - name = "BingSearchAPIWrapper" - - def build_config(self): - return { - "bing_search_url": {"display_name": "Bing Search URL"}, - "bing_subscription_key": { - "display_name": "Bing Subscription Key", - "password": True, - }, - "k": {"display_name": "Number of results", "advanced": True}, - # 'k' is not included as it is not shown (show=False) - } - - def build( - self, - bing_search_url: str, - bing_subscription_key: str, - k: int = 10, - ) -> BingSearchAPIWrapper: - # 'k' has a default value and is not shown (show=False), so it is hardcoded here - return BingSearchAPIWrapper(bing_search_url=bing_search_url, bing_subscription_key=bing_subscription_key, k=k) diff --git a/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py deleted file mode 100644 index fe804961e..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Callable, Union - -from langchain_community.utilities.google_search import GoogleSearchAPIWrapper - -from langflow.custom import CustomComponent - - -class GoogleSearchAPIWrapperComponent(CustomComponent): - display_name = "GoogleSearchAPIWrapper" - description = "Wrapper for Google Search API." - name = "GoogleSearchAPIWrapper" - - def build_config(self): - return { - "google_api_key": {"display_name": "Google API Key", "password": True}, - "google_cse_id": {"display_name": "Google CSE ID", "password": True}, - } - - def build( - self, - google_api_key: str, - google_cse_id: str, - ) -> Union[GoogleSearchAPIWrapper, Callable]: - return GoogleSearchAPIWrapper(google_api_key=google_api_key, google_cse_id=google_cse_id) # type: ignore diff --git a/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py deleted file mode 100644 index 2f5261411..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Dict - -# Assuming the existence of GoogleSerperAPIWrapper class in the serper module -# If this class does not exist, you would need to create it or import the appropriate class from another module -from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper - -from langflow.custom import CustomComponent - - -class GoogleSerperAPIWrapperComponent(CustomComponent): - display_name = "GoogleSerperAPIWrapper" - description = "Wrapper around the Serper.dev Google Search API." - name = "GoogleSerperAPIWrapper" - - def build_config(self) -> Dict[str, Dict]: - return { - "result_key_for_type": { - "display_name": "Result Key for Type", - "show": True, - "multiline": False, - "password": False, - "advanced": False, - "dynamic": False, - "info": "", - "field_type": "dict", - "list": False, - "value": { - "news": "news", - "places": "places", - "images": "images", - "search": "organic", - }, - }, - "serper_api_key": { - "display_name": "Serper API Key", - "show": True, - "multiline": False, - "password": True, - "advanced": False, - "dynamic": False, - "info": "", - "type": "str", - "list": False, - }, - } - - def build( - self, - serper_api_key: str, - ) -> GoogleSerperAPIWrapper: - return GoogleSerperAPIWrapper(serper_api_key=serper_api_key) diff --git a/src/backend/base/langflow/components/langchain_utilities/SearchApi.py b/src/backend/base/langflow/components/langchain_utilities/SearchApi.py deleted file mode 100644 index 2b6f54de7..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/SearchApi.py +++ /dev/null @@ -1,55 +0,0 @@ -from typing import Optional - -from langchain_community.utilities.searchapi import SearchApiAPIWrapper - -from langflow.custom import CustomComponent -from langflow.schema import Data -from langflow.services.database.models.base import orjson_dumps - - -class SearchApi(CustomComponent): - display_name: str = "SearchApi" - description: str = "Real-time search engine results API." - name = "SearchApi" - - output_types: list[str] = ["Document"] - documentation: str = "https://www.searchapi.io/docs/google" - field_config = { - "engine": { - "display_name": "Engine", - "field_type": "str", - "info": "The search engine to use.", - }, - "params": { - "display_name": "Parameters", - "info": "The parameters to send with the request.", - }, - "code": {"show": False}, - "api_key": { - "display_name": "API Key", - "field_type": "str", - "required": True, - "password": True, - "info": "The API key to use SearchApi.", - }, - } - - def build( - self, - engine: str, - api_key: str, - params: Optional[dict] = None, - ) -> Data: - if params is None: - params = {} - - search_api_wrapper = SearchApiAPIWrapper(engine=engine, searchapi_api_key=api_key) - - q = params.pop("q", "SearchApi Langflow") - results = search_api_wrapper.results(q, **params) - - result = orjson_dumps(results, indent_2=False) - - record = Data(data=result) - self.status = record - return record diff --git a/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py b/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py deleted file mode 100644 index 90c1f6b55..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py +++ /dev/null @@ -1,36 +0,0 @@ -from typing import Dict, Optional - -from langchain_community.utilities.searx_search import SearxSearchWrapper - -from langflow.custom import CustomComponent - - -class SearxSearchWrapperComponent(CustomComponent): - display_name = "SearxSearchWrapper" - description = "Wrapper for Searx API." - name = "SearxSearchWrapper" - - def build_config(self): - return { - "headers": { - "field_type": "dict", - "display_name": "Headers", - "multiline": True, - "value": '{"Authorization": "Bearer "}', - }, - "k": {"display_name": "k", "advanced": True, "field_type": "int", "value": 10}, - "searx_host": { - "display_name": "Searx Host", - "field_type": "str", - "value": "https://searx.example.com", - "advanced": True, - }, - } - - def build( - self, - k: int = 10, - headers: Optional[Dict[str, str]] = None, - searx_host: str = "https://searx.example.com", - ) -> SearxSearchWrapper: - return SearxSearchWrapper(headers=headers, k=k, searx_host=searx_host) diff --git a/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py deleted file mode 100644 index 7bd8d911b..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Callable, Union - -from langchain_community.utilities.serpapi import SerpAPIWrapper - -from langflow.custom import CustomComponent - - -class SerpAPIWrapperComponent(CustomComponent): - display_name = "SerpAPIWrapper" - description = "Wrapper around SerpAPI" - name = "SerpAPIWrapper" - - def build_config(self): - return { - "serpapi_api_key": {"display_name": "SerpAPI API Key", "type": "str", "password": True}, - "params": { - "display_name": "Parameters", - "type": "dict", - "advanced": True, - "multiline": True, - "value": '{"engine": "google","google_domain": "google.com","gl": "us","hl": "en"}', - }, - } - - def build( - self, - serpapi_api_key: str, - params: dict, - ) -> Union[SerpAPIWrapper, Callable]: # Removed quotes around SerpAPIWrapper - return SerpAPIWrapper( # type: ignore - serpapi_api_key=serpapi_api_key, - params=params, - ) diff --git a/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py deleted file mode 100644 index ef1485532..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Callable, Union - -from langchain_community.utilities.wikipedia import WikipediaAPIWrapper - -from langflow.custom import CustomComponent - -# Assuming WikipediaAPIWrapper is a class that needs to be imported. -# The import statement is not included as it is not provided in the JSON -# and the actual implementation details are unknown. - - -class WikipediaAPIWrapperComponent(CustomComponent): - display_name = "WikipediaAPIWrapper" - description = "Wrapper around WikipediaAPI." - name = "WikipediaAPIWrapper" - - def build_config(self): - return {} - - def build( - self, - top_k_results: int = 3, - lang: str = "en", - load_all_available_meta: bool = False, - doc_content_chars_max: int = 4000, - ) -> Union[WikipediaAPIWrapper, Callable]: - return WikipediaAPIWrapper( # type: ignore - top_k_results=top_k_results, - lang=lang, - load_all_available_meta=load_all_available_meta, - doc_content_chars_max=doc_content_chars_max, - ) diff --git a/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py deleted file mode 100644 index f8771d0ce..000000000 --- a/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Callable, Union - -from langchain_community.utilities.wolfram_alpha import WolframAlphaAPIWrapper - -from langflow.custom import CustomComponent - -# Since all the fields in the JSON have show=False, we will only create a basic component -# without any configurable fields. - - -class WolframAlphaAPIWrapperComponent(CustomComponent): - display_name = "WolframAlphaAPIWrapper" - description = "Wrapper for Wolfram Alpha." - name = "WolframAlphaAPIWrapper" - - def build_config(self): - return {"appid": {"display_name": "App ID", "type": "str", "password": True}} - - def build(self, appid: str) -> Union[Callable, WolframAlphaAPIWrapper]: - return WolframAlphaAPIWrapper(wolfram_alpha_appid=appid) # type: ignore diff --git a/src/backend/base/langflow/components/tools/BingSearchAPI.py b/src/backend/base/langflow/components/tools/BingSearchAPI.py new file mode 100644 index 000000000..7d9c0c453 --- /dev/null +++ b/src/backend/base/langflow/components/tools/BingSearchAPI.py @@ -0,0 +1,46 @@ +from typing import List + +from langchain_community.tools.bing_search import BingSearchResults +from langchain_community.utilities import BingSearchAPIWrapper +from langchain_core.tools import BaseTool + +from langflow.base.langchain_utilities.model import LCToolComponent +from langflow.inputs import IntInput, MessageTextInput, MultilineInput, SecretStrInput +from langflow.schema import Data + + +class BingSearchAPIComponent(LCToolComponent): + display_name = "Bing Search API" + description = "Call the Bing Search API." + name = "BingSearchAPI" + + inputs = [ + SecretStrInput(name="bing_subscription_key", display_name="Bing Subscription Key"), + MultilineInput( + name="input_value", + display_name="Input", + ), + MessageTextInput(name="bing_search_url", display_name="Bing Search URL", advanced=True), + IntInput(name="k", display_name="Number of results", value=4, required=True), + ] + + def run_model(self) -> List[Data]: + if self.bing_search_url: + wrapper = BingSearchAPIWrapper( + bing_search_url=self.bing_search_url, bing_subscription_key=self.bing_subscription_key + ) + else: + wrapper = BingSearchAPIWrapper(bing_subscription_key=self.bing_subscription_key) # type: ignore + results = wrapper.results(query=self.input_value, num_results=self.k) + data = [Data(data=result, text=result["snippet"]) for result in results] + self.status = data + return data + + def build_tool(self) -> BaseTool: + if self.bing_search_url: + wrapper = BingSearchAPIWrapper( + bing_search_url=self.bing_search_url, bing_subscription_key=self.bing_subscription_key + ) + else: + wrapper = BingSearchAPIWrapper(bing_subscription_key=self.bing_subscription_key) # type: ignore + return BingSearchResults(api_wrapper=wrapper, num_results=self.k) diff --git a/src/backend/base/langflow/components/tools/GoogleSearchAPI.py b/src/backend/base/langflow/components/tools/GoogleSearchAPI.py new file mode 100644 index 000000000..25d79f775 --- /dev/null +++ b/src/backend/base/langflow/components/tools/GoogleSearchAPI.py @@ -0,0 +1,45 @@ +from typing import Union + +from langchain_core.tools import BaseTool, Tool + +from langflow.base.langchain_utilities.model import LCToolComponent +from langflow.inputs import SecretStrInput, MultilineInput, IntInput +from langflow.schema import Data + + +class GoogleSearchAPIComponent(LCToolComponent): + display_name = "Google Search API" + description = "Call Google Search API." + name = "GoogleSearchAPI" + + inputs = [ + SecretStrInput(name="google_api_key", display_name="Google API Key", required=True), + SecretStrInput(name="google_cse_id", display_name="Google CSE ID", required=True), + MultilineInput( + name="input_value", + display_name="Input", + ), + IntInput(name="k", display_name="Number of results", value=4, required=True), + ] + + def run_model(self) -> Union[Data, list[Data]]: + wrapper = self._build_wrapper() + results = wrapper.results(query=self.input_value, num_results=self.k) + data = [Data(data=result, text=result["snippet"]) for result in results] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return Tool( + name="google_search", + description="Search Google for recent results.", + func=wrapper.run, + ) + + def _build_wrapper(self): + try: + from langchain_google_community import GoogleSearchAPIWrapper # type: ignore + except ImportError: + raise ImportError("Please install langchain-google-community to use GoogleSearchAPIWrapper.") + return GoogleSearchAPIWrapper(google_api_key=self.google_api_key, google_cse_id=self.google_cse_id, k=self.k) diff --git a/src/backend/base/langflow/components/tools/GoogleSerperAPI.py b/src/backend/base/langflow/components/tools/GoogleSerperAPI.py new file mode 100644 index 000000000..66b4cebd3 --- /dev/null +++ b/src/backend/base/langflow/components/tools/GoogleSerperAPI.py @@ -0,0 +1,42 @@ +from typing import Union + +from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper + +from langchain_core.tools import BaseTool, Tool +from langflow.base.langchain_utilities.model import LCToolComponent +from langflow.inputs import SecretStrInput, MultilineInput, IntInput +from langflow.schema import Data + + +class GoogleSerperAPIComponent(LCToolComponent): + display_name = "Google Serper API" + description = "Call the Serper.dev Google Search API." + name = "GoogleSerperAPI" + + inputs = [ + SecretStrInput(name="serper_api_key", display_name="Serper API Key", required=True), + MultilineInput( + name="input_value", + display_name="Input", + ), + IntInput(name="k", display_name="Number of results", value=4, required=True), + ] + + def run_model(self) -> Union[Data, list[Data]]: + wrapper = self._build_wrapper() + results = wrapper.results(query=self.input_value) + list_results = results.get("organic", []) + data = [Data(data=result, text=result["snippet"]) for result in list_results] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return Tool( + name="google_search", + description="Search Google for recent results.", + func=wrapper.run, + ) + + def _build_wrapper(self): + return GoogleSerperAPIWrapper(serper_api_key=self.serper_api_key, k=self.k) diff --git a/src/backend/base/langflow/components/tools/SearchAPI.py b/src/backend/base/langflow/components/tools/SearchAPI.py new file mode 100644 index 000000000..42c940589 --- /dev/null +++ b/src/backend/base/langflow/components/tools/SearchAPI.py @@ -0,0 +1,44 @@ +from typing import Union + +from langchain_community.utilities.searchapi import SearchApiAPIWrapper + +from langflow.base.langchain_utilities.model import LCToolComponent +from langchain_core.tools import BaseTool, Tool +from langflow.inputs import SecretStrInput, MultilineInput, DictInput, MessageTextInput +from langflow.schema import Data + + +class SearchAPIComponent(LCToolComponent): + display_name: str = "Search API" + description: str = "Call the searchapi.io API" + name = "SearchAPI" + documentation: str = "https://www.searchapi.io/docs/google" + + inputs = [ + MessageTextInput(name="engine", display_name="Engine", value="google"), + SecretStrInput(name="api_key", display_name="SearchAPI API Key", required=True), + MultilineInput( + name="input_value", + display_name="Input", + ), + DictInput(name="search_params", display_name="Search parameters", advanced=True, is_list=True), + ] + + def run_model(self) -> Union[Data, list[Data]]: + wrapper = self._build_wrapper() + results = wrapper.results(query=self.input_value, **(self.search_params or {})) + list_results = results.get("organic_results", []) + data = [Data(data=result, text=result["snippet"]) for result in list_results] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return Tool( + name="search_api", + description="Search for recent results.", + func=lambda x: wrapper.run(query=x, **(self.search_params or {})), + ) + + def _build_wrapper(self): + return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key) diff --git a/src/backend/base/langflow/components/tools/SearchAPITool.py b/src/backend/base/langflow/components/tools/SearchAPITool.py deleted file mode 100644 index 3c8058ee9..000000000 --- a/src/backend/base/langflow/components/tools/SearchAPITool.py +++ /dev/null @@ -1,38 +0,0 @@ -from langchain_community.tools.searchapi import SearchAPIRun -from langchain_community.utilities.searchapi import SearchApiAPIWrapper - -from langflow.custom import CustomComponent -from langflow.field_typing import Tool - - -class SearchApiToolComponent(CustomComponent): - display_name: str = "SearchApi Tool" - description: str = "Real-time search engine results API." - name = "SearchAPITool" - documentation: str = "https://www.searchapi.io/docs/google" - field_config = { - "engine": { - "display_name": "Engine", - "field_type": "str", - "info": "The search engine to use.", - }, - "api_key": { - "display_name": "API Key", - "field_type": "str", - "required": True, - "password": True, - "info": "The API key to use SearchApi.", - }, - } - - def build( - self, - engine: str, - api_key: str, - ) -> Tool: - search_api_wrapper = SearchApiAPIWrapper(engine=engine, searchapi_api_key=api_key) - - tool = SearchAPIRun(api_wrapper=search_api_wrapper) - - self.status = tool - return tool # type: ignore diff --git a/src/backend/base/langflow/components/tools/SearchApi.py b/src/backend/base/langflow/components/tools/SearchApi.py deleted file mode 100644 index 2b6f54de7..000000000 --- a/src/backend/base/langflow/components/tools/SearchApi.py +++ /dev/null @@ -1,55 +0,0 @@ -from typing import Optional - -from langchain_community.utilities.searchapi import SearchApiAPIWrapper - -from langflow.custom import CustomComponent -from langflow.schema import Data -from langflow.services.database.models.base import orjson_dumps - - -class SearchApi(CustomComponent): - display_name: str = "SearchApi" - description: str = "Real-time search engine results API." - name = "SearchApi" - - output_types: list[str] = ["Document"] - documentation: str = "https://www.searchapi.io/docs/google" - field_config = { - "engine": { - "display_name": "Engine", - "field_type": "str", - "info": "The search engine to use.", - }, - "params": { - "display_name": "Parameters", - "info": "The parameters to send with the request.", - }, - "code": {"show": False}, - "api_key": { - "display_name": "API Key", - "field_type": "str", - "required": True, - "password": True, - "info": "The API key to use SearchApi.", - }, - } - - def build( - self, - engine: str, - api_key: str, - params: Optional[dict] = None, - ) -> Data: - if params is None: - params = {} - - search_api_wrapper = SearchApiAPIWrapper(engine=engine, searchapi_api_key=api_key) - - q = params.pop("q", "SearchApi Langflow") - results = search_api_wrapper.results(q, **params) - - result = orjson_dumps(results, indent_2=False) - - record = Data(data=result) - self.status = record - return record diff --git a/src/backend/base/langflow/components/tools/SerpAPI.py b/src/backend/base/langflow/components/tools/SerpAPI.py new file mode 100644 index 000000000..302ecf831 --- /dev/null +++ b/src/backend/base/langflow/components/tools/SerpAPI.py @@ -0,0 +1,43 @@ +from langchain_community.utilities.serpapi import SerpAPIWrapper + +from langflow.base.langchain_utilities.model import LCToolComponent +from langchain_core.tools import BaseTool, Tool +from langflow.inputs import SecretStrInput, DictInput, MultilineInput +from langflow.schema import Data + + +class SerpAPIComponent(LCToolComponent): + display_name = "Serp Search API" + description = "Call Serp Search API" + name = "SerpAPI" + + inputs = [ + SecretStrInput(name="serpapi_api_key", display_name="SerpAPI API Key", required=True), + MultilineInput( + name="input_value", + display_name="Input", + ), + DictInput(name="search_params", display_name="Parameters", advanced=True, is_list=True), + ] + + def run_model(self) -> list[Data]: + wrapper = self._build_wrapper() + results = wrapper.results(self.input_value) + list_results = results.get("organic_results", []) + data = [Data(data=result, text=result["snippet"]) for result in list_results] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return Tool(name="search_api", description="Search for recent results.", func=wrapper.run) + + def _build_wrapper(self) -> SerpAPIWrapper: + if self.search_params: + return SerpAPIWrapper( # type: ignore + serpapi_api_key=self.serpapi_api_key, + params=self.search_params, + ) + return SerpAPIWrapper( # type: ignore + serpapi_api_key=self.serpapi_api_key + ) diff --git a/src/backend/base/langflow/components/tools/WikipediaAPI.py b/src/backend/base/langflow/components/tools/WikipediaAPI.py new file mode 100644 index 000000000..914dee8c8 --- /dev/null +++ b/src/backend/base/langflow/components/tools/WikipediaAPI.py @@ -0,0 +1,44 @@ +from langchain_community.utilities.wikipedia import WikipediaAPIWrapper + +from langflow.base.langchain_utilities.model import LCToolComponent +from langchain.tools import WikipediaQueryRun, BaseTool +from langflow.inputs import IntInput, MessageTextInput, BoolInput, MultilineInput +from langflow.schema import Data + + +class WikipediaAPIComponent(LCToolComponent): + display_name = "Wikipedia API" + description = "Call Wikipedia API." + name = "WikipediaAPI" + + inputs = [ + MultilineInput( + name="input_value", + display_name="Input", + ), + MessageTextInput(name="lang", display_name="Language", value="en"), + IntInput(name="k", display_name="Number of results", value=4, required=True), + BoolInput(name="load_all_available_meta", display_name="Load all available meta", value=False, advanced=True), + IntInput( + name="doc_content_chars_max", display_name="Document content characters max", value=4000, advanced=True + ), + ] + + def run_model(self) -> list[Data]: + wrapper = self._build_wrapper() + docs = wrapper.load(self.input_value) + data = [Data.from_document(doc) for doc in docs] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return WikipediaQueryRun(api_wrapper=wrapper) + + def _build_wrapper(self) -> WikipediaAPIWrapper: + return WikipediaAPIWrapper( # type: ignore + top_k_results=self.k, + lang=self.lang, + load_all_available_meta=self.load_all_available_meta, + doc_content_chars_max=self.doc_content_chars_max, + ) diff --git a/src/backend/base/langflow/components/tools/WolframAlphaAPI.py b/src/backend/base/langflow/components/tools/WolframAlphaAPI.py new file mode 100644 index 000000000..faaa1fc7e --- /dev/null +++ b/src/backend/base/langflow/components/tools/WolframAlphaAPI.py @@ -0,0 +1,34 @@ +from langchain_community.utilities.wolfram_alpha import WolframAlphaAPIWrapper + +from langflow.base.langchain_utilities.model import LCToolComponent +from langchain.tools import BaseTool, Tool +from langflow.inputs import MultilineInput, SecretStrInput +from langflow.schema import Data + + +class WolframAlphaAPIComponent(LCToolComponent): + display_name = "WolframAlphaAPI" + description = "Call Wolfram Alpha API." + name = "WolframAlphaAPI" + + inputs = [ + MultilineInput( + name="input_value", + display_name="Input", + ), + SecretStrInput(name="app_id", display_name="App ID", required=True), + ] + + def run_model(self) -> list[Data]: + wrapper = self._build_wrapper() + result_str = wrapper.run(self.input_value) + data = [Data(text=result_str)] + self.status = data + return data + + def build_tool(self) -> BaseTool: + wrapper = self._build_wrapper() + return Tool(name="wolfram_alpha_api", description="Answers mathematical questions.", func=wrapper.run) + + def _build_wrapper(self) -> WolframAlphaAPIWrapper: + return WolframAlphaAPIWrapper(wolfram_alpha_appid=self.app_id) # type: ignore diff --git a/src/backend/base/langflow/components/tools/__init__.py b/src/backend/base/langflow/components/tools/__init__.py index 3d64a723c..3ebec76ee 100644 --- a/src/backend/base/langflow/components/tools/__init__.py +++ b/src/backend/base/langflow/components/tools/__init__.py @@ -1,7 +1,24 @@ from .PythonREPLTool import PythonREPLToolComponent from .RetrieverTool import RetrieverToolComponent -from .SearchApi import SearchApi -from .SearchAPITool import SearchApiToolComponent +from .BingSearchAPI import BingSearchAPIComponent +from .GoogleSearchAPI import GoogleSearchAPIComponent +from .GoogleSerperAPI import GoogleSerperAPIComponent +from .PythonCodeStructuredTool import PythonCodeStructuredTool +from .SearchAPI import SearchAPIComponent +from .SerpAPI import SerpAPIComponent +from .WikipediaAPI import WikipediaAPIComponent +from .WolframAlphaAPI import WolframAlphaAPIComponent -__all__ = ["RetrieverToolComponent", "SearchApiToolComponent", "SearchApi", "PythonREPLToolComponent"] +__all__ = [ + "RetrieverToolComponent", + "BingSearchAPIComponent", + "GoogleSearchAPIComponent", + "GoogleSerperAPIComponent", + "PythonCodeStructuredTool", + "PythonREPLToolComponent", + "SearchAPIComponent", + "SerpAPIComponent", + "WikipediaAPIComponent", + "WolframAlphaAPIComponent", +] diff --git a/src/backend/base/langflow/field_typing/constants.py b/src/backend/base/langflow/field_typing/constants.py index 9ac0a1a3f..cff143fc5 100644 --- a/src/backend/base/langflow/field_typing/constants.py +++ b/src/backend/base/langflow/field_typing/constants.py @@ -13,7 +13,7 @@ from langchain_core.memory import BaseMemory from langchain_core.output_parsers import BaseOutputParser from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate, PromptTemplate from langchain_core.retrievers import BaseRetriever -from langchain_core.tools import Tool +from langchain_core.tools import Tool, BaseTool from langchain_core.vectorstores import VectorStore, VectorStoreRetriever from langchain_text_splitters import TextSplitter @@ -43,6 +43,7 @@ class Code: LANGCHAIN_BASE_TYPES = { "Chain": Chain, "AgentExecutor": AgentExecutor, + "BaseTool": BaseTool, "Tool": Tool, "BaseLLM": BaseLLM, "BaseLanguageModel": BaseLanguageModel, diff --git a/src/backend/base/poetry.lock b/src/backend/base/poetry.lock index 26c2287fb..a2666a105 100644 --- a/src/backend/base/poetry.lock +++ b/src/backend/base/poetry.lock @@ -1245,19 +1245,19 @@ files = [ [[package]] name = "langchain" -version = "0.2.8" +version = "0.2.9" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.8-py3-none-any.whl", hash = "sha256:53e7dfe50294a14200f33bec22b4e14cb63857ccf0a5500b0d18b0fd51285d58"}, - {file = "langchain-0.2.8.tar.gz", hash = "sha256:7fecb309e3558cde4e5cf7e9ffb7c1ab3f07121c40a7ff3b0c27135f8120c296"}, + {file = "langchain-0.2.9-py3-none-any.whl", hash = "sha256:be23fcb29adbd5059944f1fed08fa575f0739d420b1c4127531e0fbf5663fcca"}, + {file = "langchain-0.2.9.tar.gz", hash = "sha256:cc326a7f6347787a19882928c324433b1a79df629bba45604b2d26495ee5d69c"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.2.19,<0.3.0" +langchain-core = ">=0.2.20,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = [