Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DuckDuckGo Video Search and News Search #10770

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions api/core/tools/provider/builtin/duckduckgo/tools/ddgo_news.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from typing import Any

from duckduckgo_search import DDGS

from core.model_runtime.entities.message_entities import SystemPromptMessage
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool

SUMMARY_PROMPT = """
User's query:
{query}

Here are the news results:
{content}

Please summarize the news in a few sentences.
"""


class DuckDuckGoNewsSearchTool(BuiltinTool):
"""
Tool for performing a news search using DuckDuckGo search engine.
"""

def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
query_dict = {
"keywords": tool_parameters.get("query"),
"timelimit": tool_parameters.get("timelimit"),
"max_results": tool_parameters.get("max_results"),
"safesearch": "moderate",
"region": "wt-wt",
}
try:
response = list(DDGS().news(**query_dict))
if not response:
return [self.create_text_message("No news found matching your criteria.")]
except Exception as e:
return [self.create_text_message(f"Error searching news: {str(e)}")]

require_summary = tool_parameters.get("require_summary", False)

if require_summary:
results = "\n".join([f"{res.get('title')}: {res.get('body')}" for res in response])
results = self.summary_results(user_id=user_id, content=results, query=query_dict["keywords"])
return self.create_text_message(text=results)

# Create rich markdown content for each news item
markdown_result = "\n\n"
json_result = []

for res in response:
markdown_result += f"### {res.get('title', 'Untitled')}\n\n"
if res.get("date"):
markdown_result += f"**Date:** {res.get('date')}\n\n"
if res.get("body"):
markdown_result += f"{res.get('body')}\n\n"
if res.get("source"):
markdown_result += f"*Source: {res.get('source')}*\n\n"
if res.get("image"):
markdown_result += f"![{res.get('title', '')}]({res.get('image')})\n\n"
markdown_result += f"[Read more]({res.get('url', '')})\n\n---\n\n"

json_result.append(
self.create_json_message(
{
"title": res.get("title", ""),
"date": res.get("date", ""),
"body": res.get("body", ""),
"url": res.get("url", ""),
"image": res.get("image", ""),
"source": res.get("source", ""),
}
)
)

return [self.create_text_message(markdown_result)] + json_result

def summary_results(self, user_id: str, content: str, query: str) -> str:
prompt = SUMMARY_PROMPT.format(query=query, content=content)
summary = self.invoke_model(
user_id=user_id,
prompt_messages=[
SystemPromptMessage(content=prompt),
],
stop=[],
)
return summary.message.content
71 changes: 71 additions & 0 deletions api/core/tools/provider/builtin/duckduckgo/tools/ddgo_news.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
identity:
name: ddgo_news
author: Assistant
label:
en_US: DuckDuckGo News Search
zh_Hans: DuckDuckGo 新闻搜索
description:
human:
en_US: Perform news searches on DuckDuckGo and get results.
zh_Hans: 在 DuckDuckGo 上进行新闻搜索并获取结果。
llm: Perform news searches on DuckDuckGo and get results.
parameters:
- name: query
type: string
required: true
label:
en_US: Query String
zh_Hans: 查询语句
human_description:
en_US: Search Query.
zh_Hans: 搜索查询语句。
llm_description: Key words for searching
form: llm
- name: max_results
type: number
required: true
default: 5
label:
en_US: Max Results
zh_Hans: 最大结果数量
human_description:
en_US: The Max Results
zh_Hans: 最大结果数量
form: form
- name: timelimit
type: select
required: false
options:
- value: Day
label:
en_US: Current Day
zh_Hans: 当天
- value: Week
label:
en_US: Current Week
zh_Hans: 本周
- value: Month
label:
en_US: Current Month
zh_Hans: 当月
- value: Year
label:
en_US: Current Year
zh_Hans: 今年
label:
en_US: Result Time Limit
zh_Hans: 结果时间限制
human_description:
en_US: Use when querying results within a specific time range only.
zh_Hans: 只查询一定时间范围内的结果时使用
form: form
- name: require_summary
type: boolean
default: false
label:
en_US: Require Summary
zh_Hans: 是否总结
human_description:
en_US: Whether to pass the news results to llm for summarization.
zh_Hans: 是否需要将新闻结果传给大模型总结
form: form
59 changes: 59 additions & 0 deletions api/core/tools/provider/builtin/duckduckgo/tools/ddgo_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import Any

from duckduckgo_search import DDGS

from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool


class DuckDuckGoVideoSearchTool(BuiltinTool):
"""
Tool for performing a video search using DuckDuckGo search engine.
"""

def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> list[ToolInvokeMessage]:
query_dict = {
"keywords": tool_parameters.get("query"),
"region": tool_parameters.get("region", "wt-wt"),
"safesearch": tool_parameters.get("safesearch", "moderate"),
"timelimit": tool_parameters.get("timelimit"),
"resolution": tool_parameters.get("resolution"),
"duration": tool_parameters.get("duration"),
"license_videos": tool_parameters.get("license_videos"),
"max_results": tool_parameters.get("max_results"),
}

# Remove None values to use API defaults
query_dict = {k: v for k, v in query_dict.items() if v is not None}

response = DDGS().videos(**query_dict)

# Create HTML result with embedded iframes
markdown_result = "\n\n"
json_result = []

for res in response:
title = res.get("title", "")
embed_html = res.get("embed_html", "")
description = res.get("description", "")

# Modify iframe to be responsive
if embed_html:
# Replace fixed dimensions with responsive wrapper and iframe
embed_html = """
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; border-radius: 8px;">
<iframe
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
src="{src}"
frameborder="0"
allowfullscreen>
</iframe>
</div>""".format(src=res.get("embed_url", ""))

markdown_result += f"{title}\n\n"
markdown_result += f"{embed_html}\n\n"
markdown_result += "---\n\n"

json_result.append(self.create_json_message(res))

return [self.create_text_message(markdown_result)] + json_result
86 changes: 86 additions & 0 deletions api/core/tools/provider/builtin/duckduckgo/tools/ddgo_video.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
identity:
name: ddgo_video
author: Assistant
label:
en_US: DuckDuckGo Video Search
zh_Hans: DuckDuckGo 视频搜索
description:
human:
en_US: Perform video searches on DuckDuckGo and get results with embedded videos.
zh_Hans: 在 DuckDuckGo 上进行视频搜索并获取可嵌入的视频结果。
llm: Perform video searches on DuckDuckGo and get results with embedded videos.
parameters:
- name: query
type: string
required: true
label:
en_US: Query String
zh_Hans: 查询语句
human_description:
en_US: Search Query
zh_Hans: 搜索查询语句。
llm_description: Key words for searching
form: llm
- name: max_results
type: number
required: true
default: 3
minimum: 1
maximum: 10
label:
en_US: Max Results
zh_Hans: 最大结果数量
human_description:
en_US: The max results (1-10).
zh_Hans: 最大结果数量(1-10)。
form: form
- name: timelimit
type: select
required: false
options:
- value: Day
label:
en_US: Current Day
zh_Hans: 当天
- value: Week
label:
en_US: Current Week
zh_Hans: 本周
- value: Month
label:
en_US: Current Month
zh_Hans: 当月
- value: Year
label:
en_US: Current Year
zh_Hans: 今年
label:
en_US: Result Time Limit
zh_Hans: 结果时间限制
human_description:
en_US: Use when querying results within a specific time range only.
zh_Hans: 只查询一定时间范围内的结果时使用
form: form
- name: duration
type: select
required: false
options:
- value: short
label:
en_US: Short (<4 minutes)
zh_Hans: 短视频(<4分钟)
- value: medium
label:
en_US: Medium (4-20 minutes)
zh_Hans: 中等(4-20分钟)
- value: long
label:
en_US: Long (>20 minutes)
zh_Hans: 长视频(>20分钟)
label:
en_US: Video Duration
zh_Hans: 视频时长
human_description:
en_US: Filter videos by duration
zh_Hans: 按时长筛选视频
form: form
Loading