diff --git a/searx/engines/tavily.py b/searx/engines/tavily.py index 3913d67e9..e4c77fe83 100644 --- a/searx/engines/tavily.py +++ b/searx/engines/tavily.py @@ -6,18 +6,18 @@ Before reporting an issue with this engine, please consult `API error codes`_. -Tavily_ search API (AI engine). This engine implements the REST API +Tavily_ search API (AI engine). This engine implements the REST API (`POST /search`_) and does not make use of the `Tavily Python Wrapper`_. -From the API response this engine generates *result items* (shown in the main +From the API response, this engine generates *result items* (shown in the main result list) and an *answer result* (shown on top of the main result list). If the *answer* from Tavily contains an image, the *answer result* is turned -into a *infobox result*. +into an *infobox result*. .. attention:: AI queries take considerably longer to process than queries to conventional - search engines. The ``timeout`` should therefore also be set considerably + search engines. The ``timeout`` should therefore also be set considerably higher, but it is not recommended to activate AI queries by default (set ``disabled: true``), as otherwise all user searches will have to wait for the AI. @@ -43,7 +43,9 @@ Optional settings are: - :py:obj:`days` - :py:obj:`search_depth` - :py:obj:`max_results` +- :py:obj:`include_answer` - :py:obj:`include_images` +- :py:obj:`include_image_descriptions` - :py:obj:`include_domains` - :py:obj:`exclude_domains` @@ -102,36 +104,42 @@ api_key: str = "unset" """Tavily API Key (`Getting started`_).""" search_depth: str = "basic" -"""The depth of the search. It can be ``basic`` or ``advanced``. Default is +"""The depth of the search. It can be ``basic`` or ``advanced``. Default is ``basic`` unless specified otherwise in a given method. - have an eye on your `Tavily API Credit Deduction`_! """ topic: str = "" -"""The category of the search. This will determine which of tavily's agents -will be used for the search. Currently: only ``general`` and ``news`` are -supported and ``general`` will implicitly activate ``include_answer`` in the -`POST /search`_ API.""" +"""The category of the search. This will determine which of Tavily's agents +will be used for the search. Currently, only ``general`` and ``news`` are +supported.""" days: int = 3 """The number of days back from the current date to include in the search results. -This specifies the time frame of data to be retrieved. Please note that this +This specifies the time frame of data to be retrieved. Please note that this feature is only available when using the ``news`` search topic. Default is 3.""" max_results: int = 5 -"""The maximum number of search results to return. Default is 5.""" +"""The maximum number of search results to return. Default is 5.""" + +include_answer: bool = True +"""Include a short answer to the original query, generated by an LLM based on Tavily's +search results.""" include_images: bool = False -"""Include a list of query-related images in the response. Turns answer into -infobox with first image (as far there are any images in the response). Will -implicitly activate ``include_image_descriptions`` in the `POST /search`_ API -(adds descriptive text for each image). +"""Include a list of query-related images in the response. Creates an infobox +with the first image (as far as there are any images in the response) and the answer, +if ``include_answer`` is also enabled. """ +include_image_descriptions: bool = False +"""When ``include_images`` is set to True, this option adds descriptive text for +each image.""" + include_domains: list[str] = [] """A list of domains to specifically include in the search results. Default -is ``[]```, which includes all domains.""" +is ``[]``, which includes all domains.""" exclude_domains: list[str] = [] """A list of domains to specifically exclude from the search results. Default @@ -154,13 +162,12 @@ def request(query, params): } if include_images: - data["include_image_descriptions"] = True + data["include_image_descriptions"] = include_image_descriptions if topic == "general": - data["include_answer"] = True + data["include_answer"] = include_answer elif topic == "news": - data["topic"] = "news" data["days"] = days params["url"] = search_url @@ -178,33 +185,32 @@ def response(resp): for result in data.get("results", []): results.append( { - "title": f"[{gettext('ai')}] {result['title']}", + "title": result['title'], "url": result["url"], - "content": result["content"], + "content": f"[{gettext('ai')}] {result['content']}", "publishedDate": _parse_date(result.get("published_date")), } ) img_list = data.get("images") if img_list: - content = data.get("answer") - img_src = img_list[0] - if isinstance(img_list[0], dict): - img_src = img_list[0]["url"] - img_caption = gettext("Image caption") + ": " + img_list[0]["description"] - if not content: - gettext("Image caption") - content = img_caption - else: - content += "//" + img_caption + result = { + "infobox": f"Tavily [{gettext('ai')}]", + "img_src": img_list[0], + } - results.append( - { - "infobox": f"Tavily [{gettext('ai')}]", - "img_src": img_src, - "content": content, - } - ) + content = data.get("answer") + if isinstance(img_list[0], dict): + result["img_src"] = img_list[0]["url"] + img_caption = f"{gettext('Image caption')}: {img_list[0]['description']}" + if not content: + result["content"] = img_caption + else: + result["content"] = f"{content}
{img_caption}" + elif content: + result["content"] = content + + results.append(result) elif data["answer"]: results.append({"answer": data["answer"]})