crewAI-examples icon indicating copy to clipboard operation
crewAI-examples copied to clipboard

Key error: "description"

Open cranyy opened this issue 1 year ago • 3 comments

On my first run after successfully installing everything i got this, and it kept coming no matter what company i asked for -

Thought: Do I need to use a tool? Yes Action: yahoo_finance_news Action Input: TSLATraceback (most recent call last): File "E:\Project\crewAI-examples\stock_analysis\main.py", line 54, in result = financial_crew.run() ^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\main.py", line 42, in run result = crew.kickoff() ^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\crewai\crew.py", line 63, in kickoff return self.__sequential_loop() ^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\crewai\crew.py", line 81, in __sequential_loop task_outcome = task.execute(task_outcome) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\crewai\task.py", line 36, in execute return self.agent.execute_task( ^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\crewai\agent.py", line 102, in execute_task return self.agent_executor.invoke({ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\chains\base.py", line 87, in invoke return self( ^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\chains\base.py", line 310, in call raise e File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\chains\base.py", line 304, in call self._call(inputs, run_manager=run_manager) File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\agents\agent.py", line 1167, in _call next_step_output = self._take_next_step( ^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\agents\agent.py", line 1017, in _take_next_step observation = tool.run( ^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\tools\base.py", line 365, in run raise e File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\tools\base.py", line 337, in run self._run(*tool_args, run_manager=run_manager, **tool_kwargs) File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\tools\yahoo_finance_news.py", line 55, in _run result = self._format_results(docs, query) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\tools\yahoo_finance_news.py", line 62, in _format_results doc_strings = [ ^ File "E:\Project\crewAI-examples\stock_analysis\env\Lib\site-packages\langchain\tools\yahoo_finance_news.py", line 65, in if query in doc.metadata["description"] or query in doc.metadata["title"] ~~~~~~~~~~~~^^^^^^^^^^^^^^^ KeyError: 'description'

To fix it i changed the yahoo_finance_news.py as follows:

From this : doc_strings = [ "\n".join([doc.metadata["title"], doc.metadata["description"]]) for doc in docs if query in doc.metadata["description"] or query in doc.metadata["title"] ]

to this : def _format_results(docs: Iterable[Document], query: str) -> str: doc_strings = [] for doc in docs: title = doc.metadata.get("title", "") description = doc.metadata.get("description", "") if query in description or query in title: doc_strings.append("\n".join([title, description]))

cranyy avatar Jan 08 '24 11:01 cranyy

i have the same problem

inozz avatar Jan 08 '24 13:01 inozz

same error here

fxtoofaan avatar Jan 08 '24 16:01 fxtoofaan

So... is this an issue upstream with yahoo_finance_news?

Anyway, thanks for the code, it works :) I'll paste it here more formattet to make it more accessible for others:

In yahoo_finance_news.py (find the full path in your error message), replace the method on line 60 with:

    @staticmethod
    def _format_results(docs: Iterable[Document], query: str) -> str:
        doc_strings = []
        for doc in docs:
            title = doc.metadata.get("title", "")
            description = doc.metadata.get("description", "")
            if query in description or query in title:
                doc_strings.append("\n".join([title, description]))
        return "\n\n".join(doc_strings)

engelfrost avatar Jan 17 '24 20:01 engelfrost

Do you all still need help with this issue?

Biancamazzi avatar Jan 22 '24 21:01 Biancamazzi

Sorry about that, messing around, didnt see what i was clicking - so as i mentioned, the issue is in the description field not existing in yahoo finance api. The above is more of a workaround - Heres a working fix that actually gets the links, and tries to get the description should they ever decide to add it:

from typing import Iterable, Optional

from requests.exceptions import HTTPError, ReadTimeout
from urllib3.exceptions import ConnectionError

from langchain.callbacks.manager import CallbackManagerForToolRun
from langchain.document_loaders.web_base import WebBaseLoader
from langchain.schema import Document
from langchain.tools.base import BaseTool
import yfinance as yf

class YahooFinanceNewsTool(BaseTool):
    """Tool that searches financial news on Yahoo Finance."""

    name = "yahoo_finance_news"
    description = (
        "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."""

    def _run(
        self,
        query: str,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the Yahoo Finance News tool."""
        company = yf.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."

        try:
            news = company.news
            if not news:
                return f"No news found for company with ticker {query}."
            
            formatted_news = [self._format_news_item(item) for item in news]
            return "\n\n".join(formatted_news)
        except (HTTPError, ReadTimeout, ConnectionError) as e:
            return f"Error fetching news for ticker {query}: {e}"

    @staticmethod
    def _format_news_item(news_item):
        """Format a single news item."""
        title = news_item.get('title')
        link = news_item.get('link')
        description = news_item.get('summary') if 'summary' in news_item else 'No description available'
        return f"Title: {title}\nLink: {link}\nDescription: {description}\n"

On a side note - you can do away with a lot of langchain stuff if you want. I just set it up as a tool and import from there, and create a yahoo_news_agent who only uses this and the browser_Tools to analyze the articles and it works great.

cranyy avatar Jan 23 '24 18:01 cranyy

@cranyy feel free to open a PR with your solution! I'm happy to approve it!

Biancamazzi avatar Jan 23 '24 18:01 Biancamazzi