From 7a2f9cf1bbe421d00c649915ef1258e4378cabd6 Mon Sep 17 00:00:00 2001 From: halo Date: Mon, 2 Feb 2026 23:04:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20DuckDuckGo=20?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DuckDuckGo\346\220\234\347\264\242.tool" | Bin 0 -> 2766 bytes tools/tool_duckduckgo_search/README.md | 122 ++++++++++++++++++ tools/tool_duckduckgo_search/data.yaml | 5 + .../duckduckgo_search.py | 53 ++++++++ tools/tool_duckduckgo_search/logo.png | Bin 0 -> 22954 bytes 5 files changed, 180 insertions(+) create mode 100644 "tools/tool_duckduckgo_search/1.0.0/DuckDuckGo\346\220\234\347\264\242.tool" create mode 100644 tools/tool_duckduckgo_search/README.md create mode 100644 tools/tool_duckduckgo_search/data.yaml create mode 100644 tools/tool_duckduckgo_search/duckduckgo_search.py create mode 100644 tools/tool_duckduckgo_search/logo.png diff --git "a/tools/tool_duckduckgo_search/1.0.0/DuckDuckGo\346\220\234\347\264\242.tool" "b/tools/tool_duckduckgo_search/1.0.0/DuckDuckGo\346\220\234\347\264\242.tool" new file mode 100644 index 0000000000000000000000000000000000000000..f503a22910d28946252409e70273e696d8b15d14 GIT binary patch literal 2766 zcmdT`-A@!(6h{G(#m4G`jcJ)aXq ziV3zwpk9R5i!=pMRFt$9G!jujdFV_35bl0F**~G@&MdQwXq)t{lil38bI&>VoZtEE ztr-2oQ)WMOm#OPX(nzqO%1QM+Hb|rR!sxaxSUNOf%9?`NHCBI#U1UC5;hb*mw$!Al zYJ|~>sH&JiAWk={QAR(I0&PkF%aXsjyEW!-QMx66TU%?3f3G6p76~^u<9+*pPm@!a z(YMs*n)s~gZ9oQ&tGX8UDw_X%!doBmAb7l9ue~}-p`u|Zw=$laqK-i?mj|*- zH&>tb^1f+4e24cx&x}5Nxjg8xdHL|Suyy1KnYK$Ut`Fa*lq-$LIOwKG&`iSWpNJ0&n8`7zL$&VhlvS&h8VZMz*Y<~Zy#|E<2DOtaF@3I3VU~D=@J5@FY&;YMcHo7bl-R&6 z2uctQm%KN;mbj2F&hmN^BFC^}S=g(`V&08ZMG(aO#T`x({2#0r@%_KG-9@>!koHI< z7jm=9$t#!2z@}wrNR+?EsFg|+Um-vm5Y~ug;D}5VRSkbC1C|YtF;T3U;b6U!$M~#* z(o-261umfYMz=1yHuN-!s9H=1HE5+_B{5m^L{%Y(7~SREf>xg{@|8Y5^&5XQ znd!aH5=}Nxv>db-dY6OV?C_>UnASQR`Oy`=cn=y13P6E=2=!b7A-_W7%RacrXcf3G z9>)eav^!}T%)*4e1v7*UGeV?CPFmo_N_!Mwbf-Wevi@+ul4&JTbP)^HUmiVvxbxWl z0|((9JTEJz+Jo63t+HTTi-=LH!m{k;#EFjfwHeKE{tr9K%XU8aWb^owzjo~Ty65EN zY8mOKH6~7_ld_2g_Yt}cTyTn{WyRjps)8@Rlj~xeudtgR|%EIX8o*=Wj8~+Bg=L}W= literal 0 HcmV?d00001 diff --git a/tools/tool_duckduckgo_search/README.md b/tools/tool_duckduckgo_search/README.md new file mode 100644 index 0000000..ca0c069 --- /dev/null +++ b/tools/tool_duckduckgo_search/README.md @@ -0,0 +1,122 @@ +# DuckDuckGo 搜索工具 + +基于 `duckduckgo_search` 库实现的搜索工具,支持文字搜索和图片搜索。无需API密钥,开箱即用,可集成到MaxKB知识库系统中。 + +## 一、功能说明 + +- **文字搜索**:获取最新的网络信息和数据 +- **图片搜索**:搜索并获取图片资源 +- **隐私保护**:DuckDuckGo不跟踪用户搜索记录 +- **免费使用**:无需API密钥,完全免费 + +## 二、参数说明 + +### 2.1 输入参数 + +| 参数名 | 数据类型 | 必填 | 默认值 | 说明 | +| :--- | :--- | :--- | :--- | :--- | +| `query` | string | 是 | - | 搜索关键词 | +| `max_results` | int | 否 | `10` | 返回的最大结果数量 | +| `search_type` | string | 否 | `text` | 搜索类型:`text`(文字搜索) 或 `image`(图片搜索) | + +--- + +## 三、工具内容(Python) + +```python +from ddgs import DDGS +import json + + +def duckduckgo_search(query, max_results=10, search_type='text'): + """ + 使用 DuckDuckGo 进行搜索(统一入口函数) + + 参数: + query: 搜索关键词 + max_results: 返回的最大结果数量,默认10条 + search_type: 搜索类型,'text'(文字搜索) 或 'image'(图片搜索),默认'text' + + 返回: + JSON格式的搜索结果列表 + """ + try: + # 确保 max_results 在合理范围内 + max_results = int(max_results) + if max_results < 1: + max_results = 1 + if max_results > 20: + max_results = 20 + # 创建 DDGS 实例并执行搜索 + with DDGS() as ddgs: + if search_type == 'image': + results = list(ddgs.images( + keywords=query, + max_results=max_results + )) + else: + results = list(ddgs.text( + keywords=query, + max_results=max_results + )) + + # 返回 JSON 格式的结果 + return json.dumps(results, ensure_ascii=False, indent=2) + + except Exception as e: + error_result = { + "error": str(e), + "message": f"{search_type}搜索失败,请检查网络连接或稍后重试" + } + return json.dumps(error_result, ensure_ascii=False, indent=2) +``` + +--- + +## 四、使用示例 + +### 文字搜索 + +```python +# 基本搜索 +result = duckduckgo_search(query='Python编程') + +# 指定返回结果数量 +result = duckduckgo_search(query='AI新闻', max_results=5) + +# 明确指定文字搜索 +result = duckduckgo_search(query='Python编程', max_results=10, search_type='text') +``` + +### 图片搜索 + +```python +# 基本图片搜索 +images = duckduckgo_search(query='风景', search_type='image') + +# 指定返回结果数量 +images = duckduckgo_search(query='猫', max_results=20, search_type='image') +``` + +--- + +## 五、依赖库 + +| 依赖库 | 版本要求 | 用途说明 | +| :--- | :--- | :--- | +| `ddgs` | ≥ 9.10.0 | DuckDuckGo搜索核心库 | + +安装命令: + +```bash +pip install ddgs +``` + +--- + +## 六、注意事项 + +- 确保网络连接正常 +- 遵守DuckDuckGo使用条款 +- 建议合理控制搜索频率,避免被限流 +- 搜索结果的准确性需要人工验证 diff --git a/tools/tool_duckduckgo_search/data.yaml b/tools/tool_duckduckgo_search/data.yaml new file mode 100644 index 0000000..894719b --- /dev/null +++ b/tools/tool_duckduckgo_search/data.yaml @@ -0,0 +1,5 @@ +name: DuckDuckGo搜索 +tags: + - 联网搜索 +title: 基于DuckDuckGo的免费联网搜索工具,无需API密钥即可使用 +description: 基于DuckDuckGo的免费联网搜索工具,无需API密钥即可使用 diff --git a/tools/tool_duckduckgo_search/duckduckgo_search.py b/tools/tool_duckduckgo_search/duckduckgo_search.py new file mode 100644 index 0000000..10129ca --- /dev/null +++ b/tools/tool_duckduckgo_search/duckduckgo_search.py @@ -0,0 +1,53 @@ +from ddgs import DDGS +import json + + +def duckduckgo_search(query, max_results=10, search_type="text", region="cn-zh"): + """ + 使用 DuckDuckGo 进行搜索(统一入口函数) + + 参数: + query: 搜索关键词 + max_results: 返回的最大结果数量,默认10条 + search_type: 搜索类型,'text'(文字搜索) 或 'image'(图片搜索),默认'text' + + 返回: + JSON格式的搜索结果列表 + """ + try: + # 确保 max_results 在合理范围内 + max_results = int(max_results) + if max_results < 1: + max_results = 1 + if max_results > 20: + max_results = 20 + # 创建 DDGS 实例并执行搜索 + ddgs = DDGS() + if search_type == "image": + results = list( + ddgs.images( + query=query, + max_results=max_results, + region=region, + safesearch="off", + ) + ) + else: + results = list( + ddgs.text( + query=query, + max_results=max_results, + region=region, + safesearch="off", + ) + ) + + # 返回 JSON 格式的结果 + return json.dumps(results, ensure_ascii=False, indent=2) + + except Exception as e: + error_result = { + "error": str(e), + "message": f"{search_type}搜索失败,请检查网络连接或稍后重试", + } + return json.dumps(error_result, ensure_ascii=False, indent=2) diff --git a/tools/tool_duckduckgo_search/logo.png b/tools/tool_duckduckgo_search/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fbd689b423f34d8d941258ad131b46630b1bb198 GIT binary patch literal 22954 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 literal 0 HcmV?d00001 From a67ec81fb82208482f23fac52abf567b1410343f Mon Sep 17 00:00:00 2001 From: halo Date: Tue, 3 Feb 2026 10:02:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20DuckDuckGo=20?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=B7=A5=E5=85=B7=E7=9A=84=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E5=8C=85=E6=8B=AC=20region=E3=80=81?= =?UTF-8?q?timeout=20=E5=92=8C=20proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DuckDuckGo\346\220\234\347\264\242.tool" | Bin 2766 -> 3151 bytes tools/tool_duckduckgo_search/README.md | 46 ++++++++++++------ .../duckduckgo_search.py | 26 ++++++---- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git "a/tools/tool_duckduckgo_search/1.0.0/DuckDuckGo\346\220\234\347\264\242.tool" "b/tools/tool_duckduckgo_search/1.0.0/DuckDuckGo\346\220\234\347\264\242.tool" index f503a22910d28946252409e70273e696d8b15d14..bc64ada70d78071c1a64004272249d3f80c9e8bb 100644 GIT binary patch delta 612 zcmYjO&ui2`6lOG`Zs?&s2odE60>jmy6so0fb0rtc54`>BWc7SLO zTGfDRAVkst=S&?QnK$)*c%G$FF;2XYH>$S$=8OVBBfoWG9c*u94XPKR+4)9|4xr|) zpjN7uhsvlusi!kMihSKKM#BynPwu~jl~gV-m{eiS&iwcO4&7_|?@R?^vSrE0OswkWjf}v QV_MDjg^Om(mLIjn|6%CX(f|Me delta 142 zcmX>vaZZ%Afo1Apu8FMw8GRJ=NC!b}}oV<)hU7$EI zEwwl`u_!siRw+L%O=p>UCWZ!vW@eKOdE@|lUM&6q diff --git a/tools/tool_duckduckgo_search/README.md b/tools/tool_duckduckgo_search/README.md index ca0c069..2551c4f 100644 --- a/tools/tool_duckduckgo_search/README.md +++ b/tools/tool_duckduckgo_search/README.md @@ -16,8 +16,11 @@ | 参数名 | 数据类型 | 必填 | 默认值 | 说明 | | :--- | :--- | :--- | :--- | :--- | | `query` | string | 是 | - | 搜索关键词 | -| `max_results` | int | 否 | `10` | 返回的最大结果数量 | +| `max_results` | int | 否 | `10` | 返回的最大结果数量(1-20) | | `search_type` | string | 否 | `text` | 搜索类型:`text`(文字搜索) 或 `image`(图片搜索) | +| `region` | string | 否 | `cn-zh` | 搜索区域,如 `cn-zh`(中国)、`us-en`(美国)、`uk-en`(英国) 等 | +| `timeout` | int | 否 | `15` | 请求超时时间(秒) | +| `proxy` | string | 否 | `None` | 代理服务器地址,格式如 `http://proxy.example.com:8080` | --- @@ -28,7 +31,9 @@ from ddgs import DDGS import json -def duckduckgo_search(query, max_results=10, search_type='text'): +def duckduckgo_search( + query, max_results=10, search_type="text", region="cn-zh", timeout=15, proxy=None +): """ 使用 DuckDuckGo 进行搜索(统一入口函数) @@ -48,17 +53,19 @@ def duckduckgo_search(query, max_results=10, search_type='text'): if max_results > 20: max_results = 20 # 创建 DDGS 实例并执行搜索 - with DDGS() as ddgs: - if search_type == 'image': - results = list(ddgs.images( - keywords=query, - max_results=max_results - )) - else: - results = list(ddgs.text( - keywords=query, - max_results=max_results - )) + ddgs = DDGS(timeout=timeout, proxy=proxy) + if search_type == "image": + results = list( + ddgs.images( + query=query, + region=region, + max_results=max_results, + ) + ) + else: + results = list( + ddgs.text(query=query, region=region, max_results=max_results) + ) # 返回 JSON 格式的结果 return json.dumps(results, ensure_ascii=False, indent=2) @@ -66,9 +73,20 @@ def duckduckgo_search(query, max_results=10, search_type='text'): except Exception as e: error_result = { "error": str(e), - "message": f"{search_type}搜索失败,请检查网络连接或稍后重试" + "message": f"{search_type}搜索失败,请检查网络连接或稍后重试", } return json.dumps(error_result, ensure_ascii=False, indent=2) + + +if __name__ == "__main__": + query = "猫" + max_results = 5 + search_type = "image" + region = "cn-zh" + timeout = 15 + result = duckduckgo_search(query, max_results, search_type, region, timeout) + print(result) + ``` --- diff --git a/tools/tool_duckduckgo_search/duckduckgo_search.py b/tools/tool_duckduckgo_search/duckduckgo_search.py index 10129ca..cf80aa7 100644 --- a/tools/tool_duckduckgo_search/duckduckgo_search.py +++ b/tools/tool_duckduckgo_search/duckduckgo_search.py @@ -2,7 +2,9 @@ import json -def duckduckgo_search(query, max_results=10, search_type="text", region="cn-zh"): +def duckduckgo_search( + query, max_results=10, search_type="text", region="cn-zh", timeout=15, proxy=None +): """ 使用 DuckDuckGo 进行搜索(统一入口函数) @@ -22,24 +24,18 @@ def duckduckgo_search(query, max_results=10, search_type="text", region="cn-zh") if max_results > 20: max_results = 20 # 创建 DDGS 实例并执行搜索 - ddgs = DDGS() + ddgs = DDGS(timeout=timeout, proxy=proxy) if search_type == "image": results = list( ddgs.images( query=query, - max_results=max_results, region=region, - safesearch="off", + max_results=max_results, ) ) else: results = list( - ddgs.text( - query=query, - max_results=max_results, - region=region, - safesearch="off", - ) + ddgs.text(query=query, region=region, max_results=max_results) ) # 返回 JSON 格式的结果 @@ -51,3 +47,13 @@ def duckduckgo_search(query, max_results=10, search_type="text", region="cn-zh") "message": f"{search_type}搜索失败,请检查网络连接或稍后重试", } return json.dumps(error_result, ensure_ascii=False, indent=2) + + +if __name__ == "__main__": + query = "猫" + max_results = 5 + search_type = "image" + region = "cn-zh" + timeout = 15 + result = duckduckgo_search(query, max_results, search_type, region, timeout) + print(result)