Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Update Serp API component to standard output pattern #5437

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 41 additions & 44 deletions src/backend/base/langflow/components/tools/serp_api.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from typing import Any

from langchain.tools import StructuredTool
from langchain_community.utilities.serpapi import SerpAPIWrapper
from langchain_core.tools import ToolException
from loguru import logger
from pydantic import BaseModel, Field

from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.field_typing import Tool
from langflow.custom import Component
from langflow.inputs import DictInput, IntInput, MultilineInput, SecretStrInput
from langflow.io import Output
from langflow.schema import Data
from langflow.schema.message import Message


class SerpAPISchema(BaseModel):
Expand All @@ -29,7 +29,7 @@ class SerpAPISchema(BaseModel):
max_snippet_length: int = Field(100, description="Maximum length of each result snippet")


class SerpAPIComponent(LCToolComponent):
class SerpAPIComponent(Component):
display_name = "Serp Search API"
description = "Call Serp Search API with result limiting"
name = "SerpAPI"
Expand All @@ -40,12 +40,18 @@ class SerpAPIComponent(LCToolComponent):
MultilineInput(
name="input_value",
display_name="Input",
tool_mode=True,
),
DictInput(name="search_params", display_name="Parameters", advanced=True, is_list=True),
IntInput(name="max_results", display_name="Max Results", value=5, advanced=True),
IntInput(name="max_snippet_length", display_name="Max Snippet Length", value=100, advanced=True),
]

outputs = [
Output(display_name="Data", name="data", method="fetch_content"),
Output(display_name="Text", name="text", method="fetch_content_text"),
]

def _build_wrapper(self, params: dict[str, Any] | None = None) -> SerpAPIWrapper:
"""Build a SerpAPIWrapper with the provided parameters."""
params = params or {}
Expand All @@ -56,12 +62,15 @@ def _build_wrapper(self, params: dict[str, Any] | None = None) -> SerpAPIWrapper
)
return SerpAPIWrapper(serpapi_api_key=self.serpapi_api_key)

def build_tool(self) -> Tool:
def run_model(self) -> list[Data]:
return self.fetch_content()

def fetch_content(self) -> list[Data]:
wrapper = self._build_wrapper(self.search_params)

def search_func(
query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100
) -> list[dict[str, Any]]:
) -> list[Data]:
try:
local_wrapper = wrapper
if params:
Expand All @@ -70,49 +79,37 @@ def search_func(
full_results = local_wrapper.results(query)
organic_results = full_results.get("organic_results", [])[:max_results]

limited_results = []
for result in organic_results:
limited_result = {
"title": result.get("title", "")[:max_snippet_length],
"link": result.get("link", ""),
"snippet": result.get("snippet", "")[:max_snippet_length],
}
limited_results.append(limited_result)
limited_results = [
Data(
text=result.get("snippet", ""),
data={
"title": result.get("title", "")[:max_snippet_length],
"link": result.get("link", ""),
"snippet": result.get("snippet", "")[:max_snippet_length],
},
)
for result in organic_results
]

except Exception as e:
error_message = f"Error in SerpAPI search: {e!s}"
logger.debug(error_message)
raise ToolException(error_message) from e
return limited_results

tool = StructuredTool.from_function(
name="serp_search_api",
description="Search for recent results using SerpAPI with result limiting",
func=search_func,
args_schema=SerpAPISchema,
results = search_func(
self.input_value,
params=self.search_params,
max_results=self.max_results,
max_snippet_length=self.max_snippet_length,
)

self.status = "SerpAPI Tool created"
return tool

def run_model(self) -> list[Data]:
tool = self.build_tool()
try:
results = tool.run(
{
"query": self.input_value,
"params": self.search_params or {},
"max_results": self.max_results,
"max_snippet_length": self.max_snippet_length,
}
)

data_list = [Data(data=result, text=result.get("snippet", "")) for result in results]

except Exception as e: # noqa: BLE001
logger.opt(exception=True).debug("Error running SerpAPI")
self.status = f"Error: {e}"
return [Data(data={"error": str(e)}, text=str(e))]

self.status = data_list # type: ignore[assignment]
return data_list
self.status = results
return results

def fetch_content_text(self) -> Message:
data = self.fetch_content()
result_string = ""
for item in data:
result_string += item.text + "\n"
self.status = result_string
return Message(text=result_string)
Loading