diff --git a/src/backend/base/langflow/components/tools/serp_api.py b/src/backend/base/langflow/components/tools/serp_api.py index faf5ad038546..52c09119f87e 100644 --- a/src/backend/base/langflow/components/tools/serp_api.py +++ b/src/backend/base/langflow/components/tools/serp_api.py @@ -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): @@ -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" @@ -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 {} @@ -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: @@ -70,14 +79,17 @@ 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}" @@ -85,34 +97,19 @@ def search_func( 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)