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 <gabriel@langflow.org>
This commit is contained in:
Nicolò Boschi 2024-07-17 19:41:03 +02:00 committed by GitHub
commit b281a7d25e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 499 additions and 408 deletions

156
poetry.lock generated
View file

@ -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"

View file

@ -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]

View file

@ -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),

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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 <token>"}',
},
"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)

View file

@ -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,
)

View file

@ -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,
)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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
)

View file

@ -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,
)

View file

@ -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

View file

@ -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",
]

View file

@ -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,

View file

@ -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 = [