From b814f0b7e312df771f179c65fa44657171ef3507 Mon Sep 17 00:00:00 2001 From: Yeuoly <45712896+Yeuoly@users.noreply.github.com> Date: Sun, 4 Feb 2024 18:46:01 +0800 Subject: [PATCH] feat: bing search (#2375) --- api/core/tools/provider/builtin/_positions.py | 1 + .../provider/builtin/bing/_assets/icon.png | Bin 0 -> 4624 bytes api/core/tools/provider/builtin/bing/bing.py | 23 + .../tools/provider/builtin/bing/bing.yaml | 45 ++ .../builtin/bing/tools/bing_web_search.py | 61 +++ .../builtin/bing/tools/bing_web_search.yaml | 480 ++++++++++++++++++ 6 files changed, 610 insertions(+) create mode 100644 api/core/tools/provider/builtin/bing/_assets/icon.png create mode 100644 api/core/tools/provider/builtin/bing/bing.py create mode 100644 api/core/tools/provider/builtin/bing/bing.yaml create mode 100644 api/core/tools/provider/builtin/bing/tools/bing_web_search.py create mode 100644 api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml diff --git a/api/core/tools/provider/builtin/_positions.py b/api/core/tools/provider/builtin/_positions.py index 232b6684aa..d4e47640ab 100644 --- a/api/core/tools/provider/builtin/_positions.py +++ b/api/core/tools/provider/builtin/_positions.py @@ -4,6 +4,7 @@ from core.tools.entities.user_entities import UserToolProvider position = { 'google': 1, + 'bing': 2, 'wikipedia': 2, 'dalle': 3, 'webscraper': 4, diff --git a/api/core/tools/provider/builtin/bing/_assets/icon.png b/api/core/tools/provider/builtin/bing/_assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7b3225a96d8fcd077fa2bcf3e8d12a3e4068af GIT binary patch literal 4624 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 None: + try: + BingSearchTool().fork_tool_runtime( + meta={ + "credentials": credentials, + } + ).invoke( + user_id='', + tool_parameters={ + "query": "test", + "result_type": "link" + }, + ) + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) diff --git a/api/core/tools/provider/builtin/bing/bing.yaml b/api/core/tools/provider/builtin/bing/bing.yaml new file mode 100644 index 0000000000..ee3aaf1968 --- /dev/null +++ b/api/core/tools/provider/builtin/bing/bing.yaml @@ -0,0 +1,45 @@ +identity: + author: Dify + name: bing + label: + en_US: Bing + zh_Hans: Bing + pt_BR: Bing + description: + en_US: Bing Search + zh_Hans: Bing 搜索 + pt_BR: Bing Search + icon: icon.png +credentials_for_provider: + subscription_key: + type: secret-input + required: true + label: + en_US: Bing subscription key + zh_Hans: Bing subscription key + pt_BR: Bing subscription key + placeholder: + en_US: Please input your Bing subscription key + zh_Hans: 请输入你的 Bing subscription key + pt_BR: Please input your Bing subscription key + help: + en_US: Get your Bing subscription key from Bing + zh_Hans: 从 Bing 获取您的 Bing subscription key + pt_BR: Get your Bing subscription key from Bing + url: https://www.microsoft.com/cognitive-services/en-us/bing-web-search-api + server_url: + type: text-input + required: false + label: + en_US: Bing endpoint + zh_Hans: Bing endpoint + pt_BR: Bing endpoint + placeholder: + en_US: Please input your Bing endpoint + zh_Hans: 请输入你的 Bing 端点 + pt_BR: Please input your Bing endpoint + help: + en_US: An endpoint is like "https://api.bing.microsoft.com/v7.0/search" + zh_Hans: 例如 "https://api.bing.microsoft.com/v7.0/search" + pt_BR: An endpoint is like "https://api.bing.microsoft.com/v7.0/search" + default: https://api.bing.microsoft.com/v7.0/search diff --git a/api/core/tools/provider/builtin/bing/tools/bing_web_search.py b/api/core/tools/provider/builtin/bing/tools/bing_web_search.py new file mode 100644 index 0000000000..e13e538806 --- /dev/null +++ b/api/core/tools/provider/builtin/bing/tools/bing_web_search.py @@ -0,0 +1,61 @@ +from core.tools.tool.builtin_tool import BuiltinTool +from core.tools.entities.tool_entities import ToolInvokeMessage + +from typing import Any, Dict, List, Union +from os import path +from requests import get + +class BingSearchTool(BuiltinTool): + url = 'https://api.bing.microsoft.com/v7.0/search' + + def _invoke(self, + user_id: str, + tool_parameters: Dict[str, Any], + ) -> Union[ToolInvokeMessage, List[ToolInvokeMessage]]: + """ + invoke tools + """ + + key = self.runtime.credentials.get('subscription_key', None) + if not key: + raise Exception('subscription_key is required') + + server_url = self.runtime.credentials.get('server_url', None) + if not server_url: + server_url = self.url + + query = tool_parameters.get('query', None) + if not query: + raise Exception('query is required') + + market = tool_parameters.get('market', 'US') + lang = tool_parameters.get('language', 'en') + + market_code = f'{lang}-{market}' + accept_language = f'{lang},{market_code};q=0.9' + headers = { + 'Ocp-Apim-Subscription-Key': key, + 'Accept-Language': accept_language + } + + params = { + 'q': query, + 'mkt': market_code + } + + response = get(server_url, headers=headers, params=params) + + if response.status_code != 200: + raise Exception(f'Error {response.status_code}: {response.text}') + + response = response.json() + # get the first 5 results + search_results = response['webPages']['value'][:5] + results = [] + for result in search_results: + results.append(self.create_text_message( + text=f'{result["name"]}: {result["url"]}' + )) + + return results + \ No newline at end of file diff --git a/api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml b/api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml new file mode 100644 index 0000000000..ebb67af48d --- /dev/null +++ b/api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml @@ -0,0 +1,480 @@ +identity: + name: bing_web_search + author: Dify + label: + en_US: BingWebSearch + zh_Hans: 必应网页搜索 + pt_BR: BingWebSearch +description: + human: + en_US: A tool for performing a Bing SERP search and extracting snippets and webpages.Input should be a search query. + zh_Hans: 一个用于执行 Bing SERP 搜索并提取片段和网页的工具。输入应该是一个搜索查询。 + pt_BR: A tool for performing a Bing SERP search and extracting snippets and webpages.Input should be a search query. + llm: A tool for performing a Bing SERP search and extracting snippets and webpages.Input should be a search query. +parameters: + - name: query + type: string + required: true + label: + en_US: Query string + zh_Hans: 查询语句 + pt_BR: Query string + human_description: + en_US: used for searching + zh_Hans: 用于搜索网页内容 + pt_BR: used for searching + llm_description: key words for searching + form: llm + - name: market + type: select + label: + en_US: Market + zh_Hans: 市场 + pt_BR: Market + human_description: + en_US: market takes responsibility for the region + zh_Hans: 市场决定了搜索结果的地区 + pt_BR: market takes responsibility for the region + required: false + form: form + default: US + options: + - value: AR + label: + en_US: Argentina + zh_Hans: 阿根廷 + pt_BR: Argentina + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: AT + label: + en_US: Austria + zh_Hans: 奥地利 + pt_BR: Austria + - value: BE + label: + en_US: Belgium + zh_Hans: 比利时 + pt_BR: Belgium + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: CL + label: + en_US: Chile + zh_Hans: 智利 + pt_BR: Chile + - value: CO + label: + en_US: Colombia + zh_Hans: 哥伦比亚 + pt_BR: Colombia + - value: CN + label: + en_US: China + zh_Hans: 中国 + pt_BR: China + - value: CZ + label: + en_US: Czech Republic + zh_Hans: 捷克共和国 + pt_BR: Czech Republic + - value: DK + label: + en_US: Denmark + zh_Hans: 丹麦 + pt_BR: Denmark + - value: FI + label: + en_US: Finland + zh_Hans: 芬兰 + pt_BR: Finland + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: HK + label: + en_US: Hong Kong + zh_Hans: 香港 + pt_BR: Hong Kong + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: ID + label: + en_US: Indonesia + zh_Hans: 印度尼西亚 + pt_BR: Indonesia + - value: IT + label: + en_US: Italy + zh_Hans: 意大利 + pt_BR: Italy + - value: JP + label: + en_US: Japan + zh_Hans: 日本 + pt_BR: Japan + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: MY + label: + en_US: Malaysia + zh_Hans: 马来西亚 + pt_BR: Malaysia + - value: MX + label: + en_US: Mexico + zh_Hans: 墨西哥 + pt_BR: Mexico + - value: NL + label: + en_US: Netherlands + zh_Hans: 荷兰 + pt_BR: Netherlands + - value: NZ + label: + en_US: New Zealand + zh_Hans: 新西兰 + pt_BR: New Zealand + - value: NO + label: + en_US: Norway + zh_Hans: 挪威 + pt_BR: Norway + - value: PH + label: + en_US: Philippines + zh_Hans: 菲律宾 + pt_BR: Philippines + - value: PL + label: + en_US: Poland + zh_Hans: 波兰 + pt_BR: Poland + - value: PT + label: + en_US: Portugal + zh_Hans: 葡萄牙 + pt_BR: Portugal + - value: RU + label: + en_US: Russia + zh_Hans: 俄罗斯 + pt_BR: Russia + - value: SA + label: + en_US: Saudi Arabia + zh_Hans: 沙特阿拉伯 + pt_BR: Saudi Arabia + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: ZA + label: + en_US: South Africa + zh_Hans: 南非 + pt_BR: South Africa + - value: ES + label: + en_US: Spain + zh_Hans: 西班牙 + pt_BR: Spain + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden + - value: CH + label: + en_US: Switzerland + zh_Hans: 瑞士 + pt_BR: Switzerland + - value: TW + label: + en_US: Taiwan + zh_Hans: 台湾 + pt_BR: Taiwan + - value: TH + label: + en_US: Thailand + zh_Hans: 泰国 + pt_BR: Thailand + - value: TR + label: + en_US: Turkey + zh_Hans: 土耳其 + pt_BR: Turkey + - value: GB + label: + en_US: United Kingdom + zh_Hans: 英国 + pt_BR: United Kingdom + - value: US + label: + en_US: United States + zh_Hans: 美国 + pt_BR: United States + - name: language + type: select + label: + en_US: Language + zh_Hans: 语言 + pt_BR: Language + human_description: + en_US: language takes responsibility for the language of the search result + zh_Hans: 语言决定了搜索结果的语言 + pt_BR: language takes responsibility for the language of the search result + required: false + default: en + form: form + options: + - value: ar + label: + en_US: Arabic + zh_Hans: 阿拉伯语 + pt_BR: Arabic + - value: bg + label: + en_US: Bulgarian + zh_Hans: 保加利亚语 + pt_BR: Bulgarian + - value: ca + label: + en_US: Catalan + zh_Hans: 加泰罗尼亚语 + pt_BR: Catalan + - value: zh-hans + label: + en_US: Chinese (Simplified) + zh_Hans: 中文(简体) + pt_BR: Chinese (Simplified) + - value: zh-hant + label: + en_US: Chinese (Traditional) + zh_Hans: 中文(繁体) + pt_BR: Chinese (Traditional) + - value: cs + label: + en_US: Czech + zh_Hans: 捷克语 + pt_BR: Czech + - value: da + label: + en_US: Danish + zh_Hans: 丹麦语 + pt_BR: Danish + - value: nl + label: + en_US: Dutch + zh_Hans: 荷兰语 + pt_BR: Dutch + - value: en + label: + en_US: English + zh_Hans: 英语 + pt_BR: English + - value: et + label: + en_US: Estonian + zh_Hans: 爱沙尼亚语 + pt_BR: Estonian + - value: fi + label: + en_US: Finnish + zh_Hans: 芬兰语 + pt_BR: Finnish + - value: fr + label: + en_US: French + zh_Hans: 法语 + pt_BR: French + - value: de + label: + en_US: German + zh_Hans: 德语 + pt_BR: German + - value: el + label: + en_US: Greek + zh_Hans: 希腊语 + pt_BR: Greek + - value: he + label: + en_US: Hebrew + zh_Hans: 希伯来语 + pt_BR: Hebrew + - value: hi + label: + en_US: Hindi + zh_Hans: 印地语 + pt_BR: Hindi + - value: hu + label: + en_US: Hungarian + zh_Hans: 匈牙利语 + pt_BR: Hungarian + - value: id + label: + en_US: Indonesian + zh_Hans: 印尼语 + pt_BR: Indonesian + - value: it + label: + en_US: Italian + zh_Hans: 意大利语 + pt_BR: Italian + - value: jp + label: + en_US: Japanese + zh_Hans: 日语 + pt_BR: Japanese + - value: kn + label: + en_US: Kannada + zh_Hans: 卡纳达语 + pt_BR: Kannada + - value: ko + label: + en_US: Korean + zh_Hans: 韩语 + pt_BR: Korean + - value: lv + label: + en_US: Latvian + zh_Hans: 拉脱维亚语 + pt_BR: Latvian + - value: lt + label: + en_US: Lithuanian + zh_Hans: 立陶宛语 + pt_BR: Lithuanian + - value: ms + label: + en_US: Malay + zh_Hans: 马来语 + pt_BR: Malay + - value: ml + label: + en_US: Malayalam + zh_Hans: 马拉雅拉姆语 + pt_BR: Malayalam + - value: mr + label: + en_US: Marathi + zh_Hans: 马拉地语 + pt_BR: Marathi + - value: nb + label: + en_US: Norwegian + zh_Hans: 挪威语 + pt_BR: Norwegian + - value: pl + label: + en_US: Polish + zh_Hans: 波兰语 + pt_BR: Polish + - value: pt-br + label: + en_US: Portuguese (Brazil) + zh_Hans: 葡萄牙语(巴西) + pt_BR: Portuguese (Brazil) + - value: pt-pt + label: + en_US: Portuguese (Portugal) + zh_Hans: 葡萄牙语(葡萄牙) + pt_BR: Portuguese (Portugal) + - value: pa + label: + en_US: Punjabi + zh_Hans: 旁遮普语 + pt_BR: Punjabi + - value: ro + label: + en_US: Romanian + zh_Hans: 罗马尼亚语 + pt_BR: Romanian + - value: ru + label: + en_US: Russian + zh_Hans: 俄语 + pt_BR: Russian + - value: sr + label: + en_US: Serbian + zh_Hans: 塞尔维亚语 + pt_BR: Serbian + - value: sk + label: + en_US: Slovak + zh_Hans: 斯洛伐克语 + pt_BR: Slovak + - value: sl + label: + en_US: Slovenian + zh_Hans: 斯洛文尼亚语 + pt_BR: Slovenian + - value: es + label: + en_US: Spanish + zh_Hans: 西班牙语 + pt_BR: Spanish + - value: sv + label: + en_US: Swedish + zh_Hans: 瑞典语 + pt_BR: Swedish + - value: ta + label: + en_US: Tamil + zh_Hans: 泰米尔语 + pt_BR: Tamil + - value: te + label: + en_US: Telugu + zh_Hans: 泰卢固语 + pt_BR: Telugu + - value: th + label: + en_US: Thai + zh_Hans: 泰语 + pt_BR: Thai + - value: tr + label: + en_US: Turkish + zh_Hans: 土耳其语 + pt_BR: Turkish + - value: uk + label: + en_US: Ukrainian + zh_Hans: 乌克兰语 + pt_BR: Ukrainian + - value: vi + label: + en_US: Vietnamese + zh_Hans: 越南语 + pt_BR: Vietnamese