From 93593893fb11899bf3bc078e72fc37d4b19403d2 Mon Sep 17 00:00:00 2001 From: Felipe Rosa Date: Mon, 9 Sep 2024 17:30:59 -0300 Subject: [PATCH 1/6] feat(YahooFinanceTool): enhance tool with new inputs for data retrieval methods --- .../langflow/components/tools/YfinanceTool.py | 110 ++++++++++++++---- 1 file changed, 88 insertions(+), 22 deletions(-) diff --git a/src/backend/base/langflow/components/tools/YfinanceTool.py b/src/backend/base/langflow/components/tools/YfinanceTool.py index 3ffd2062820..407efd38726 100644 --- a/src/backend/base/langflow/components/tools/YfinanceTool.py +++ b/src/backend/base/langflow/components/tools/YfinanceTool.py @@ -1,35 +1,101 @@ -from typing import cast +import ast +import pprint -from langchain_community.tools.yahoo_finance_news import YahooFinanceNewsTool +import yfinance as yf +from langchain.tools import StructuredTool +from pydantic import BaseModel, Field from langflow.base.langchain_utilities.model import LCToolComponent -from langflow.field_typing import Data, Tool -from langflow.inputs.inputs import MessageTextInput -from langflow.template.field.base import Output +from langflow.field_typing import Tool +from langflow.inputs import DropdownInput, IntInput, MessageTextInput +from langflow.schema import Data -class YfinanceToolComponent(LCToolComponent): - display_name = "Yahoo Finance News Tool" - description = "Tool for interacting with Yahoo Finance News." - name = "YFinanceTool" +class YahooFinanceToolComponent(LCToolComponent): + display_name = "Yahoo Finance Tool" + description = "Access financial data and market information using Yahoo Finance." + icon = "trending-up" + name = "YahooFinanceTool" inputs = [ MessageTextInput( - name="input_value", - display_name="Query", - info="Input should be a company ticker. For example, AAPL for Apple, MSFT for Microsoft.", - ) + name="symbol", + display_name="Stock Symbol", + info="The stock symbol to retrieve data for (e.g., AAPL, GOOG).", + required=True, + ), + DropdownInput( + name="method", + display_name="Data Method", + info="The type of data to retrieve.", + options=[ + "get_actions", + "get_analysis", + "get_balance_sheet", + "get_calendar", + "get_cashflow", + "get_info", + "get_institutional_holders", + "get_news", + "get_recommendations", + "get_sustainability", + ], + value="get_news", + ), + IntInput( + name="num_news", + display_name="Number of News", + info="The number of news articles to retrieve (only applicable for get_news).", + value=5, + ), ] - outputs = [ - Output(name="api_run_model", display_name="Data", method="run_model"), - # Keep this for backwards compatibility - Output(name="tool", display_name="Tool", method="build_tool"), - ] + class YahooFinanceSchema(BaseModel): + symbol: str = Field(..., description="The stock symbol to retrieve data for.") + method: str = Field("get_info", description="The type of data to retrieve.") + num_news: int | None = Field(5, description="The number of news articles to retrieve.") + + def run_model(self) -> list[Data]: + return self._yahoo_finance_tool( + self.symbol, + self.method, + self.num_news, + ) def build_tool(self) -> Tool: - return cast(Tool, YahooFinanceNewsTool()) + return StructuredTool.from_function( + name="yahoo_finance", + description="Access financial data and market information from Yahoo Finance.", + func=self._yahoo_finance_tool, + args_schema=self.YahooFinanceSchema, + ) + + def _yahoo_finance_tool( + self, + symbol: str, + method: str, + num_news: int | None = 5, + ) -> list[Data]: + ticker = yf.Ticker(symbol) + + try: + if method == "get_info": + result = ticker.info + elif method == "get_news": + result = ticker.news[:num_news] + else: + result = getattr(ticker, method)() + + result = pprint.pformat(result) + + if method == "get_news": + data_list = [Data(data=article) for article in ast.literal_eval(result)] + else: + data_list = [Data(data={"result": result})] + + return data_list - def run_model(self) -> Data: - tool = self.build_tool() - return tool.run(self.input_value) + except Exception as e: + error_message = f"Error retrieving data: {str(e)}" + self.status = error_message + return [Data(data={"error": error_message})] From 75ad23620b7369cea05543bc9910a58c16dd08e9 Mon Sep 17 00:00:00 2001 From: italojohnny Date: Mon, 9 Sep 2024 19:31:20 -0300 Subject: [PATCH 2/6] test: fix test --- .../langflow/initial_setup/starter_projects/complex_agent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py index f94c04dfefc..bf9a0932f32 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py +++ b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py @@ -6,7 +6,7 @@ from langflow.components.outputs.ChatOutput import ChatOutput from langflow.components.prompts.Prompt import PromptComponent from langflow.components.tools.SearchAPI import SearchAPIComponent -from langflow.components.tools.YfinanceTool import YfinanceToolComponent +from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent from langflow.graph.graph.base import Graph @@ -14,7 +14,7 @@ def complex_agent_graph(): llm = OpenAIModelComponent(model_name="gpt-4o-mini") manager_llm = OpenAIModelComponent(model_name="gpt-4o") search_api_tool = SearchAPIComponent() - yahoo_search_tool = YfinanceToolComponent() + yahoo_search_tool = YahooFinanceToolComponent dynamic_agent = CrewAIAgentComponent() chat_input = ChatInput() role_prompt = PromptComponent(_display_name="Role Prompt") From caf739fad040cbabf61268f8694666e204571040 Mon Sep 17 00:00:00 2001 From: italojohnny Date: Mon, 9 Sep 2024 19:52:05 -0300 Subject: [PATCH 3/6] test: fix test units --- .../tests/unit/components/tools/test_yfinance_tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/tests/unit/components/tools/test_yfinance_tool.py b/src/backend/tests/unit/components/tools/test_yfinance_tool.py index 7b19b72da1f..f023fa9fc42 100644 --- a/src/backend/tests/unit/components/tools/test_yfinance_tool.py +++ b/src/backend/tests/unit/components/tools/test_yfinance_tool.py @@ -1,6 +1,6 @@ import pytest -from langflow.components.tools.YfinanceTool import YfinanceToolComponent +from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent from langflow.custom.custom_component.component import Component from langflow.custom.utils import build_custom_component_template @@ -11,11 +11,11 @@ def client(): def test_yfinance_tool_template(): - yf_tool = YfinanceToolComponent() + yf_tool = YahooFinanceToolComponent() component = Component(_code=yf_tool._code) frontend_node, _ = build_custom_component_template(component) assert "outputs" in frontend_node output_names = [output["name"] for output in frontend_node["outputs"]] assert "api_run_model" in output_names - assert "tool" in output_names + assert "api_build_tool" in output_names assert all(output["types"] != [] for output in frontend_node["outputs"]) From 8a48aa05a1aaae588ad95e816934c824b28e455f Mon Sep 17 00:00:00 2001 From: italojohnny Date: Mon, 9 Sep 2024 20:06:21 -0300 Subject: [PATCH 4/6] test: fix import --- src/backend/tests/unit/graph/graph/test_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/tests/unit/graph/graph/test_base.py b/src/backend/tests/unit/graph/graph/test_base.py index 8a7e328149e..564bc76ac73 100644 --- a/src/backend/tests/unit/graph/graph/test_base.py +++ b/src/backend/tests/unit/graph/graph/test_base.py @@ -8,7 +8,7 @@ from langflow.components.inputs.ChatInput import ChatInput from langflow.components.outputs.ChatOutput import ChatOutput from langflow.components.outputs.TextOutput import TextOutputComponent -from langflow.components.tools.YfinanceTool import YfinanceToolComponent +from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent from langflow.graph.graph.base import Graph from langflow.graph.graph.constants import Finish @@ -151,6 +151,6 @@ def test_graph_functional_start_end(): @pytest.mark.skip(reason="Temporarily disabled") def test_graph_set_with_valid_component(): - tool = YfinanceToolComponent() + tool = YahooFinanceToolComponent() tool_calling_agent = ToolCallingAgentComponent() tool_calling_agent.set(tools=[tool]) From e16e09ee7726847c473f16fa2e6151f39356f8eb Mon Sep 17 00:00:00 2001 From: italojohnny Date: Tue, 10 Sep 2024 05:54:37 -0300 Subject: [PATCH 5/6] fix: rename component --- src/backend/base/langflow/components/tools/YfinanceTool.py | 2 +- .../langflow/initial_setup/starter_projects/complex_agent.py | 4 ++-- src/backend/tests/unit/components/tools/test_yfinance_tool.py | 4 ++-- src/backend/tests/unit/graph/graph/test_base.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backend/base/langflow/components/tools/YfinanceTool.py b/src/backend/base/langflow/components/tools/YfinanceTool.py index 407efd38726..b32850e9862 100644 --- a/src/backend/base/langflow/components/tools/YfinanceTool.py +++ b/src/backend/base/langflow/components/tools/YfinanceTool.py @@ -11,7 +11,7 @@ from langflow.schema import Data -class YahooFinanceToolComponent(LCToolComponent): +class YfinanceToolComponent(LCToolComponent): display_name = "Yahoo Finance Tool" description = "Access financial data and market information using Yahoo Finance." icon = "trending-up" diff --git a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py index bf9a0932f32..4f20554ddbd 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py +++ b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py @@ -6,7 +6,7 @@ from langflow.components.outputs.ChatOutput import ChatOutput from langflow.components.prompts.Prompt import PromptComponent from langflow.components.tools.SearchAPI import SearchAPIComponent -from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent +from langflow.components.tools.YfinanceTool import YfinanceToolComponent from langflow.graph.graph.base import Graph @@ -14,7 +14,7 @@ def complex_agent_graph(): llm = OpenAIModelComponent(model_name="gpt-4o-mini") manager_llm = OpenAIModelComponent(model_name="gpt-4o") search_api_tool = SearchAPIComponent() - yahoo_search_tool = YahooFinanceToolComponent + yahoo_search_tool = YfinanceToolComponent dynamic_agent = CrewAIAgentComponent() chat_input = ChatInput() role_prompt = PromptComponent(_display_name="Role Prompt") diff --git a/src/backend/tests/unit/components/tools/test_yfinance_tool.py b/src/backend/tests/unit/components/tools/test_yfinance_tool.py index f023fa9fc42..75630a42dae 100644 --- a/src/backend/tests/unit/components/tools/test_yfinance_tool.py +++ b/src/backend/tests/unit/components/tools/test_yfinance_tool.py @@ -1,6 +1,6 @@ import pytest -from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent +from langflow.components.tools.YfinanceTool import YfinanceToolComponent from langflow.custom.custom_component.component import Component from langflow.custom.utils import build_custom_component_template @@ -11,7 +11,7 @@ def client(): def test_yfinance_tool_template(): - yf_tool = YahooFinanceToolComponent() + yf_tool = YfinanceToolComponent() component = Component(_code=yf_tool._code) frontend_node, _ = build_custom_component_template(component) assert "outputs" in frontend_node diff --git a/src/backend/tests/unit/graph/graph/test_base.py b/src/backend/tests/unit/graph/graph/test_base.py index 564bc76ac73..8a7e328149e 100644 --- a/src/backend/tests/unit/graph/graph/test_base.py +++ b/src/backend/tests/unit/graph/graph/test_base.py @@ -8,7 +8,7 @@ from langflow.components.inputs.ChatInput import ChatInput from langflow.components.outputs.ChatOutput import ChatOutput from langflow.components.outputs.TextOutput import TextOutputComponent -from langflow.components.tools.YfinanceTool import YahooFinanceToolComponent +from langflow.components.tools.YfinanceTool import YfinanceToolComponent from langflow.graph.graph.base import Graph from langflow.graph.graph.constants import Finish @@ -151,6 +151,6 @@ def test_graph_functional_start_end(): @pytest.mark.skip(reason="Temporarily disabled") def test_graph_set_with_valid_component(): - tool = YahooFinanceToolComponent() + tool = YfinanceToolComponent() tool_calling_agent = ToolCallingAgentComponent() tool_calling_agent.set(tools=[tool]) From 4e238de29bbce5332c927cb28c49b0f306423da5 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Wed, 2 Oct 2024 17:24:07 -0300 Subject: [PATCH 6/6] Fix instantiation of YfinanceToolComponent in complex_agent.py --- .../langflow/initial_setup/starter_projects/complex_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py index 4f20554ddbd..f94c04dfefc 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py +++ b/src/backend/base/langflow/initial_setup/starter_projects/complex_agent.py @@ -14,7 +14,7 @@ def complex_agent_graph(): llm = OpenAIModelComponent(model_name="gpt-4o-mini") manager_llm = OpenAIModelComponent(model_name="gpt-4o") search_api_tool = SearchAPIComponent() - yahoo_search_tool = YfinanceToolComponent + yahoo_search_tool = YfinanceToolComponent() dynamic_agent = CrewAIAgentComponent() chat_input = ChatInput() role_prompt = PromptComponent(_display_name="Role Prompt")