langchain/libs/community/langchain_community/tools/yahoo_finance_news.py
Julian Castro Pulgarin b7e3e337b1
community: Fix YahooFinanceNewsTool to handle updated yfinance data structure (#29498)
*Description:**
Updates the YahooFinanceNewsTool to handle the current yfinance news
data structure. The tool was failing with a KeyError due to changes in
the yfinance API's response format. This PR updates the code to
correctly extract news URLs from the new structure.

**Issue:** #29495

**Dependencies:** 
No new dependencies required. Works with existing yfinance package.

The changes maintain backwards compatibility while fixing the KeyError
that users were experiencing.

The modified code properly handles the new data structure where:
- News type is now at `content.contentType`
- News URL is now at `content.canonicalUrl.url`

---------

Co-authored-by: Chester Curme <chester.curme@gmail.com>
2025-01-31 02:31:44 +00:00

91 lines
3.1 KiB
Python

from typing import Iterable, Optional, Type
from langchain_core.callbacks import CallbackManagerForToolRun
from langchain_core.documents import Document
from langchain_core.tools import BaseTool
from pydantic import BaseModel, Field
from requests.exceptions import HTTPError, ReadTimeout
from urllib3.exceptions import ConnectionError
from langchain_community.document_loaders.web_base import WebBaseLoader
class YahooFinanceNewsInput(BaseModel):
"""Input for the YahooFinanceNews tool."""
query: str = Field(description="company ticker query to look up")
class YahooFinanceNewsTool(BaseTool): # type: ignore[override, override]
"""Tool that searches financial news on Yahoo Finance."""
name: str = "yahoo_finance_news"
description: str = (
"Useful for when you need to find financial news "
"about a public company. "
"Input should be a company ticker. "
"For example, AAPL for Apple, MSFT for Microsoft."
)
top_k: int = 10
"""The number of results to return."""
args_schema: Type[BaseModel] = YahooFinanceNewsInput
def _run(
self,
query: str,
run_manager: Optional[CallbackManagerForToolRun] = None,
) -> str:
"""
Use the Yahoo Finance News tool.
Args:
query: Company ticker symbol (e.g., 'AAPL' for Apple).
run_manager: Optional callback manager.
Returns:
str: Formatted news results or error message.
"""
try:
import yfinance
except ImportError:
raise ImportError(
"Could not import yfinance python package. "
"Please install it with `pip install yfinance`."
)
company = yfinance.Ticker(query)
try:
if company.isin is None:
return f"Company ticker {query} not found."
except (HTTPError, ReadTimeout, ConnectionError):
return f"Company ticker {query} not found."
links = []
try:
links = [
n["content"]["canonicalUrl"]["url"]
for n in company.news
if n["content"]["contentType"] == "STORY"
]
except (HTTPError, ReadTimeout, ConnectionError):
if not links:
return f"No news found for company that searched with {query} ticker."
if not links:
return f"No news found for company that searched with {query} ticker."
loader = WebBaseLoader(web_paths=links)
docs = loader.load()
result = self._format_results(docs, query)
if not result:
return f"No news found for company that searched with {query} ticker."
return result
@staticmethod
def _format_results(docs: Iterable[Document], query: str) -> str:
doc_strings = [
"\n".join([doc.metadata["title"], doc.metadata.get("description", "")])
for doc in docs
if query in doc.metadata.get("description", "")
or query in doc.metadata["title"]
]
return "\n\n".join(doc_strings)