diff --git a/src/backend/base/langflow/components/search/arxiv.py b/src/backend/base/langflow/components/search/arxiv.py index 84a36c9f4..41524edf6 100644 --- a/src/backend/base/langflow/components/search/arxiv.py +++ b/src/backend/base/langflow/components/search/arxiv.py @@ -5,7 +5,6 @@ from xml.etree.ElementTree import Element from defusedxml.ElementTree import fromstring from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.io import DropdownInput, IntInput, MessageTextInput, Output from langflow.schema import Data, DataFrame @@ -160,4 +159,4 @@ class ArXivComponent(Component): DataFrame: A DataFrame containing the search results. """ data = self.search_papers() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/bing_search_api.py b/src/backend/base/langflow/components/search/bing_search_api.py index 54f993425..0b85cf5f8 100644 --- a/src/backend/base/langflow/components/search/bing_search_api.py +++ b/src/backend/base/langflow/components/search/bing_search_api.py @@ -5,7 +5,6 @@ from langchain_community.utilities import BingSearchAPIWrapper from langflow.base.langchain_utilities.model import LCToolComponent from langflow.field_typing import Tool -from langflow.helpers.data import data_to_dataframe from langflow.inputs import IntInput, MessageTextInput, MultilineInput, SecretStrInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -49,7 +48,7 @@ class BingSearchAPIComponent(LCToolComponent): def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) def build_tool(self) -> Tool: if self.bing_search_url: diff --git a/src/backend/base/langflow/components/search/duck_duck_go_search_run.py b/src/backend/base/langflow/components/search/duck_duck_go_search_run.py index f51d7f604..bfd7f14e3 100644 --- a/src/backend/base/langflow/components/search/duck_duck_go_search_run.py +++ b/src/backend/base/langflow/components/search/duck_duck_go_search_run.py @@ -1,7 +1,6 @@ from langchain_community.tools import DuckDuckGoSearchRun from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.inputs import IntInput, MessageTextInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -89,4 +88,4 @@ class DuckDuckGoSearchComponent(Component): DataFrame: A DataFrame containing the search results. """ data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/glean_search_api.py b/src/backend/base/langflow/components/search/glean_search_api.py index c303cddd9..39f27dec2 100644 --- a/src/backend/base/langflow/components/search/glean_search_api.py +++ b/src/backend/base/langflow/components/search/glean_search_api.py @@ -9,7 +9,6 @@ from pydantic.v1 import Field from langflow.base.langchain_utilities.model import LCToolComponent from langflow.field_typing import Tool -from langflow.helpers.data import data_to_dataframe from langflow.inputs import IntInput, MultilineInput, NestedDictInput, SecretStrInput, StrInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -170,4 +169,4 @@ class GleanSearchAPIComponent(LCToolComponent): DataFrame: A DataFrame containing the search results. """ data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/search.py b/src/backend/base/langflow/components/search/search.py index a7c60318e..5c634455e 100644 --- a/src/backend/base/langflow/components/search/search.py +++ b/src/backend/base/langflow/components/search/search.py @@ -3,7 +3,6 @@ from typing import Any from langchain_community.utilities.searchapi import SearchApiAPIWrapper from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -76,4 +75,4 @@ class SearchComponent(Component): DataFrame: A DataFrame containing the search results. """ data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/wikidata.py b/src/backend/base/langflow/components/search/wikidata.py index 3ec83a0d4..3cfed8636 100644 --- a/src/backend/base/langflow/components/search/wikidata.py +++ b/src/backend/base/langflow/components/search/wikidata.py @@ -3,7 +3,6 @@ from httpx import HTTPError from langchain_core.tools import ToolException from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.io import MultilineInput, Output from langflow.schema import Data, DataFrame @@ -82,4 +81,4 @@ class WikidataComponent(Component): def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/wikipedia.py b/src/backend/base/langflow/components/search/wikipedia.py index 6e204a7b8..db2032393 100644 --- a/src/backend/base/langflow/components/search/wikipedia.py +++ b/src/backend/base/langflow/components/search/wikipedia.py @@ -1,7 +1,6 @@ from langchain_community.utilities.wikipedia import WikipediaAPIWrapper from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.inputs import BoolInput, IntInput, MessageTextInput, MultilineInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -50,4 +49,4 @@ class WikipediaComponent(Component): def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/wolfram_alpha_api.py b/src/backend/base/langflow/components/search/wolfram_alpha_api.py index d1592e565..a0b1cc7bc 100644 --- a/src/backend/base/langflow/components/search/wolfram_alpha_api.py +++ b/src/backend/base/langflow/components/search/wolfram_alpha_api.py @@ -2,7 +2,6 @@ from langchain_community.utilities.wolfram_alpha import WolframAlphaAPIWrapper from langflow.base.langchain_utilities.model import LCToolComponent from langflow.field_typing import Tool -from langflow.helpers.data import data_to_dataframe from langflow.inputs import MultilineInput, SecretStrInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -51,4 +50,4 @@ topics, delivering structured responses.""" DataFrame: A DataFrame containing the query results. """ data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/search/yahoo.py b/src/backend/base/langflow/components/search/yahoo.py index 3b28c7603..d391b13b6 100644 --- a/src/backend/base/langflow/components/search/yahoo.py +++ b/src/backend/base/langflow/components/search/yahoo.py @@ -8,7 +8,6 @@ from loguru import logger from pydantic import BaseModel, Field from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.inputs import DropdownInput, IntInput, MessageTextInput from langflow.io import Output from langflow.schema import Data, DataFrame @@ -134,4 +133,4 @@ to access financial data and market information from Yahoo Finance.""" def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/tavily/tavily_extract.py b/src/backend/base/langflow/components/tavily/tavily_extract.py index db027d05b..34717b5d2 100644 --- a/src/backend/base/langflow/components/tavily/tavily_extract.py +++ b/src/backend/base/langflow/components/tavily/tavily_extract.py @@ -2,7 +2,6 @@ import httpx from loguru import logger from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.io import BoolInput, DropdownInput, MessageTextInput, Output, SecretStrInput from langflow.schema import Data from langflow.schema.dataframe import DataFrame @@ -115,4 +114,4 @@ class TavilyExtractComponent(Component): def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/components/tavily/tavily_search.py b/src/backend/base/langflow/components/tavily/tavily_search.py index 598d82779..a20c61b1e 100644 --- a/src/backend/base/langflow/components/tavily/tavily_search.py +++ b/src/backend/base/langflow/components/tavily/tavily_search.py @@ -2,7 +2,6 @@ import httpx from loguru import logger from langflow.custom import Component -from langflow.helpers.data import data_to_dataframe from langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput from langflow.schema import Data from langflow.schema.dataframe import DataFrame @@ -209,4 +208,4 @@ class TavilySearchComponent(Component): def fetch_content_dataframe(self) -> DataFrame: data = self.fetch_content() - return data_to_dataframe(data) + return DataFrame(data) diff --git a/src/backend/base/langflow/helpers/data.py b/src/backend/base/langflow/helpers/data.py index b043eb334..6482ebb87 100644 --- a/src/backend/base/langflow/helpers/data.py +++ b/src/backend/base/langflow/helpers/data.py @@ -2,7 +2,7 @@ from collections import defaultdict from langchain_core.documents import Document -from langflow.schema import Data, DataFrame +from langflow.schema import Data from langflow.schema.message import Message @@ -139,17 +139,3 @@ def messages_to_text(template: str, messages: Message | list[Message]) -> str: formated_messages = [template.format(data=message.model_dump(), **message.model_dump()) for message in messages_] return "\n".join(formated_messages) - - -def data_to_dataframe(data: Data | list[Data]) -> DataFrame: - """Converts a Data object or a list of Data objects to a DataFrame. - - Args: - data (Data | list[Data]): The Data object or list of Data objects to convert. - - Returns: - DataFrame: The converted DataFrame. - """ - if isinstance(data, Data): - return DataFrame([data.data]) - return DataFrame(data=[d.data for d in data]) diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json index 4f79f8819..1cbde6b18 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json @@ -724,7 +724,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", @@ -1153,7 +1153,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceComponent(Component):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def _fetch_yfinance_data(self, ticker: yf.Ticker, method: YahooFinanceMethod, num_news: int | None) -> str:\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n return pprint.pformat(result)\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def fetch_content(self) -> list[Data]:\n try:\n return self._yahoo_finance_tool(\n self.symbol,\n YahooFinanceMethod(self.method),\n self.num_news,\n )\n except ToolException:\n raise\n except Exception as e:\n error_message = f\"Unexpected error: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n result = self._fetch_yfinance_data(ticker, method, num_news)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [\n Data(text=f\"{article['title']}: {article['link']}\", data=article)\n for article in ast.literal_eval(result)\n ]\n else:\n data_list = [Data(text=result, data={\"result\": result})]\n\n return data_list\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.custom import Component\nfrom langflow.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceComponent(Component):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def _fetch_yfinance_data(self, ticker: yf.Ticker, method: YahooFinanceMethod, num_news: int | None) -> str:\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n return pprint.pformat(result)\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def fetch_content(self) -> list[Data]:\n try:\n return self._yahoo_finance_tool(\n self.symbol,\n YahooFinanceMethod(self.method),\n self.num_news,\n )\n except ToolException:\n raise\n except Exception as e:\n error_message = f\"Unexpected error: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n result = self._fetch_yfinance_data(ticker, method, num_news)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [\n Data(text=f\"{article['title']}: {article['link']}\", data=article)\n for article in ast.literal_eval(result)\n ]\n else:\n data_list = [Data(text=result, data={\"result\": result})]\n\n return data_list\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "method": { "_input_type": "DropdownInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json index 4c9247066..864c7570f 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json @@ -2384,7 +2384,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json index 028e98c9f..b92d8606a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json @@ -1892,7 +1892,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json index d753ceff9..47bdd300c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json @@ -843,7 +843,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json index 3dd34981b..75227db6e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json @@ -1960,7 +1960,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json index 93d198374..1896998ae 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json @@ -263,7 +263,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import urllib.request\nfrom urllib.parse import urlparse\nfrom xml.etree.ElementTree import Element\n\nfrom defusedxml.ElementTree import fromstring\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass ArXivComponent(Component):\n display_name = \"arXiv\"\n description = \"Search and retrieve papers from arXiv.org\"\n icon = \"arXiv\"\n\n inputs = [\n MessageTextInput(\n name=\"search_query\",\n display_name=\"Search Query\",\n info=\"The search query for arXiv papers (e.g., 'quantum computing')\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Field\",\n info=\"The field to search in\",\n options=[\"all\", \"title\", \"abstract\", \"author\", \"cat\"], # cat is for category\n value=\"all\",\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"Maximum number of results to return\",\n value=10,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"search_papers_dataframe\"),\n ]\n\n def build_query_url(self) -> str:\n \"\"\"Build the arXiv API query URL.\"\"\"\n base_url = \"http://export.arxiv.org/api/query?\"\n\n # Build the search query\n search_query = f\"{self.search_type}:{self.search_query}\"\n\n # URL parameters\n params = {\n \"search_query\": search_query,\n \"max_results\": str(self.max_results),\n }\n\n # Convert params to URL query string\n query_string = \"&\".join([f\"{k}={urllib.parse.quote(str(v))}\" for k, v in params.items()])\n\n return base_url + query_string\n\n def parse_atom_response(self, response_text: str) -> list[dict]:\n \"\"\"Parse the Atom XML response from arXiv.\"\"\"\n # Parse XML safely using defusedxml\n root = fromstring(response_text)\n\n # Define namespace dictionary for XML parsing\n ns = {\"atom\": \"http://www.w3.org/2005/Atom\", \"arxiv\": \"http://arxiv.org/schemas/atom\"}\n\n papers = []\n # Process each entry (paper)\n for entry in root.findall(\"atom:entry\", ns):\n paper = {\n \"id\": self._get_text(entry, \"atom:id\", ns),\n \"title\": self._get_text(entry, \"atom:title\", ns),\n \"summary\": self._get_text(entry, \"atom:summary\", ns),\n \"published\": self._get_text(entry, \"atom:published\", ns),\n \"updated\": self._get_text(entry, \"atom:updated\", ns),\n \"authors\": [author.find(\"atom:name\", ns).text for author in entry.findall(\"atom:author\", ns)],\n \"arxiv_url\": self._get_link(entry, \"alternate\", ns),\n \"pdf_url\": self._get_link(entry, \"related\", ns),\n \"comment\": self._get_text(entry, \"arxiv:comment\", ns),\n \"journal_ref\": self._get_text(entry, \"arxiv:journal_ref\", ns),\n \"primary_category\": self._get_category(entry, ns),\n \"categories\": [cat.get(\"term\") for cat in entry.findall(\"atom:category\", ns)],\n }\n papers.append(paper)\n\n return papers\n\n def _get_text(self, element: Element, path: str, ns: dict) -> str | None:\n \"\"\"Safely extract text from an XML element.\"\"\"\n el = element.find(path, ns)\n return el.text.strip() if el is not None and el.text else None\n\n def _get_link(self, element: Element, rel: str, ns: dict) -> str | None:\n \"\"\"Get link URL based on relation type.\"\"\"\n for link in element.findall(\"atom:link\", ns):\n if link.get(\"rel\") == rel:\n return link.get(\"href\")\n return None\n\n def _get_category(self, element: Element, ns: dict) -> str | None:\n \"\"\"Get primary category.\"\"\"\n cat = element.find(\"arxiv:primary_category\", ns)\n return cat.get(\"term\") if cat is not None else None\n\n def run_model(self) -> DataFrame:\n return self.search_papers_dataframe()\n\n def search_papers(self) -> list[Data]:\n \"\"\"Search arXiv and return results.\"\"\"\n try:\n # Build the query URL\n url = self.build_query_url()\n\n # Validate URL scheme and host\n parsed_url = urlparse(url)\n if parsed_url.scheme not in {\"http\", \"https\"}:\n error_msg = f\"Invalid URL scheme: {parsed_url.scheme}\"\n raise ValueError(error_msg)\n if parsed_url.hostname != \"export.arxiv.org\":\n error_msg = f\"Invalid host: {parsed_url.hostname}\"\n raise ValueError(error_msg)\n\n # Create a custom opener that only allows http/https schemes\n class RestrictedHTTPHandler(urllib.request.HTTPHandler):\n def http_open(self, req):\n return super().http_open(req)\n\n class RestrictedHTTPSHandler(urllib.request.HTTPSHandler):\n def https_open(self, req):\n return super().https_open(req)\n\n # Build opener with restricted handlers\n opener = urllib.request.build_opener(RestrictedHTTPHandler, RestrictedHTTPSHandler)\n urllib.request.install_opener(opener)\n\n # Make the request with validated URL using restricted opener\n response = opener.open(url)\n response_text = response.read().decode(\"utf-8\")\n\n # Parse the response\n papers = self.parse_atom_response(response_text)\n\n # Convert to Data objects\n results = [Data(data=paper) for paper in papers]\n self.status = results\n except (urllib.error.URLError, ValueError) as e:\n error_data = Data(data={\"error\": f\"Request error: {e!s}\"})\n self.status = error_data\n return [error_data]\n else:\n return results\n\n def search_papers_dataframe(self) -> DataFrame:\n \"\"\"Convert the Arxiv search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.search_papers()\n return data_to_dataframe(data)\n" + "value": "import urllib.request\nfrom urllib.parse import urlparse\nfrom xml.etree.ElementTree import Element\n\nfrom defusedxml.ElementTree import fromstring\n\nfrom langflow.custom import Component\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass ArXivComponent(Component):\n display_name = \"arXiv\"\n description = \"Search and retrieve papers from arXiv.org\"\n icon = \"arXiv\"\n\n inputs = [\n MessageTextInput(\n name=\"search_query\",\n display_name=\"Search Query\",\n info=\"The search query for arXiv papers (e.g., 'quantum computing')\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Field\",\n info=\"The field to search in\",\n options=[\"all\", \"title\", \"abstract\", \"author\", \"cat\"], # cat is for category\n value=\"all\",\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"Maximum number of results to return\",\n value=10,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"search_papers_dataframe\"),\n ]\n\n def build_query_url(self) -> str:\n \"\"\"Build the arXiv API query URL.\"\"\"\n base_url = \"http://export.arxiv.org/api/query?\"\n\n # Build the search query\n search_query = f\"{self.search_type}:{self.search_query}\"\n\n # URL parameters\n params = {\n \"search_query\": search_query,\n \"max_results\": str(self.max_results),\n }\n\n # Convert params to URL query string\n query_string = \"&\".join([f\"{k}={urllib.parse.quote(str(v))}\" for k, v in params.items()])\n\n return base_url + query_string\n\n def parse_atom_response(self, response_text: str) -> list[dict]:\n \"\"\"Parse the Atom XML response from arXiv.\"\"\"\n # Parse XML safely using defusedxml\n root = fromstring(response_text)\n\n # Define namespace dictionary for XML parsing\n ns = {\"atom\": \"http://www.w3.org/2005/Atom\", \"arxiv\": \"http://arxiv.org/schemas/atom\"}\n\n papers = []\n # Process each entry (paper)\n for entry in root.findall(\"atom:entry\", ns):\n paper = {\n \"id\": self._get_text(entry, \"atom:id\", ns),\n \"title\": self._get_text(entry, \"atom:title\", ns),\n \"summary\": self._get_text(entry, \"atom:summary\", ns),\n \"published\": self._get_text(entry, \"atom:published\", ns),\n \"updated\": self._get_text(entry, \"atom:updated\", ns),\n \"authors\": [author.find(\"atom:name\", ns).text for author in entry.findall(\"atom:author\", ns)],\n \"arxiv_url\": self._get_link(entry, \"alternate\", ns),\n \"pdf_url\": self._get_link(entry, \"related\", ns),\n \"comment\": self._get_text(entry, \"arxiv:comment\", ns),\n \"journal_ref\": self._get_text(entry, \"arxiv:journal_ref\", ns),\n \"primary_category\": self._get_category(entry, ns),\n \"categories\": [cat.get(\"term\") for cat in entry.findall(\"atom:category\", ns)],\n }\n papers.append(paper)\n\n return papers\n\n def _get_text(self, element: Element, path: str, ns: dict) -> str | None:\n \"\"\"Safely extract text from an XML element.\"\"\"\n el = element.find(path, ns)\n return el.text.strip() if el is not None and el.text else None\n\n def _get_link(self, element: Element, rel: str, ns: dict) -> str | None:\n \"\"\"Get link URL based on relation type.\"\"\"\n for link in element.findall(\"atom:link\", ns):\n if link.get(\"rel\") == rel:\n return link.get(\"href\")\n return None\n\n def _get_category(self, element: Element, ns: dict) -> str | None:\n \"\"\"Get primary category.\"\"\"\n cat = element.find(\"arxiv:primary_category\", ns)\n return cat.get(\"term\") if cat is not None else None\n\n def run_model(self) -> DataFrame:\n return self.search_papers_dataframe()\n\n def search_papers(self) -> list[Data]:\n \"\"\"Search arXiv and return results.\"\"\"\n try:\n # Build the query URL\n url = self.build_query_url()\n\n # Validate URL scheme and host\n parsed_url = urlparse(url)\n if parsed_url.scheme not in {\"http\", \"https\"}:\n error_msg = f\"Invalid URL scheme: {parsed_url.scheme}\"\n raise ValueError(error_msg)\n if parsed_url.hostname != \"export.arxiv.org\":\n error_msg = f\"Invalid host: {parsed_url.hostname}\"\n raise ValueError(error_msg)\n\n # Create a custom opener that only allows http/https schemes\n class RestrictedHTTPHandler(urllib.request.HTTPHandler):\n def http_open(self, req):\n return super().http_open(req)\n\n class RestrictedHTTPSHandler(urllib.request.HTTPSHandler):\n def https_open(self, req):\n return super().https_open(req)\n\n # Build opener with restricted handlers\n opener = urllib.request.build_opener(RestrictedHTTPHandler, RestrictedHTTPSHandler)\n urllib.request.install_opener(opener)\n\n # Make the request with validated URL using restricted opener\n response = opener.open(url)\n response_text = response.read().decode(\"utf-8\")\n\n # Parse the response\n papers = self.parse_atom_response(response_text)\n\n # Convert to Data objects\n results = [Data(data=paper) for paper in papers]\n self.status = results\n except (urllib.error.URLError, ValueError) as e:\n error_data = Data(data={\"error\": f\"Request error: {e!s}\"})\n self.status = error_data\n return [error_data]\n else:\n return results\n\n def search_papers_dataframe(self) -> DataFrame:\n \"\"\"Convert the Arxiv search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.search_papers()\n return DataFrame(data)\n" }, "max_results": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json index bd3456a2e..ff0fa3173 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json @@ -3143,7 +3143,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceComponent(Component):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def _fetch_yfinance_data(self, ticker: yf.Ticker, method: YahooFinanceMethod, num_news: int | None) -> str:\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n return pprint.pformat(result)\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def fetch_content(self) -> list[Data]:\n try:\n return self._yahoo_finance_tool(\n self.symbol,\n YahooFinanceMethod(self.method),\n self.num_news,\n )\n except ToolException:\n raise\n except Exception as e:\n error_message = f\"Unexpected error: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n result = self._fetch_yfinance_data(ticker, method, num_news)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [\n Data(text=f\"{article['title']}: {article['link']}\", data=article)\n for article in ast.literal_eval(result)\n ]\n else:\n data_list = [Data(text=result, data={\"result\": result})]\n\n return data_list\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.custom import Component\nfrom langflow.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceComponent(Component):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def _fetch_yfinance_data(self, ticker: yf.Ticker, method: YahooFinanceMethod, num_news: int | None) -> str:\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n return pprint.pformat(result)\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def fetch_content(self) -> list[Data]:\n try:\n return self._yahoo_finance_tool(\n self.symbol,\n YahooFinanceMethod(self.method),\n self.num_news,\n )\n except ToolException:\n raise\n except Exception as e:\n error_message = f\"Unexpected error: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n result = self._fetch_yfinance_data(ticker, method, num_news)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [\n Data(text=f\"{article['title']}: {article['link']}\", data=article)\n for article in ast.literal_eval(result)\n ]\n else:\n data_list = [Data(text=result, data={\"result\": result})]\n\n return data_list\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "method": { "_input_type": "DropdownInput", @@ -3664,7 +3664,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" }, "days": { "_input_type": "IntInput", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json index 86f8825f1..9c3173bd7 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json @@ -1462,7 +1462,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return data_to_dataframe(data)\n" + "value": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom import Component\nfrom langflow.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return DataFrame(data)\n" }, "engine": { "_input_type": "DropdownInput",