diff --git a/api/core/tools/provider/builtin/websearch/_assets/icon.svg b/api/core/tools/provider/builtin/websearch/_assets/icon.svg new file mode 100644 index 0000000000..d6ef5d878f --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/_assets/icon.svg @@ -0,0 +1,23 @@ + + + + \ No newline at end of file diff --git a/api/core/tools/provider/builtin/websearch/tools/get_markdown.py b/api/core/tools/provider/builtin/websearch/tools/get_markdown.py new file mode 100644 index 0000000000..92d7d1addc --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/get_markdown.py @@ -0,0 +1,51 @@ +from typing import Any, Union + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + +BASE_URL = "https://api.serply.io/v1/request" + + +class SerplyApi: + """ + SerplyAPI tool provider. + """ + + def __init__(self, api_key: str) -> None: + """Initialize SerplyAPI tool provider.""" + self.serply_api_key = api_key + + def run(self, url: str, **kwargs: Any) -> str: + """Run query through SerplyAPI and parse result.""" + + location = kwargs.get("location", "US") + + headers = { + "X-API-KEY": self.serply_api_key, + "X-User-Agent": kwargs.get("device", "desktop"), + "X-Proxy-Location": location, + "User-Agent": "Dify", + } + data = {"url": url, "method": "GET", "response_type": "markdown"} + res = requests.post(url, headers=headers, json=data) + return res.text + + +class GetMarkdownTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any], + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + """ + Invoke the SerplyApi tool. + """ + url = tool_parameters["url"] + location = tool_parameters.get("location", None) + + api_key = self.runtime.credentials["serply_api_key"] + result = SerplyApi(api_key).run(url, location=location) + + return self.create_text_message(text=result) diff --git a/api/core/tools/provider/builtin/websearch/tools/get_markdown.yaml b/api/core/tools/provider/builtin/websearch/tools/get_markdown.yaml new file mode 100644 index 0000000000..06a302bd14 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/get_markdown.yaml @@ -0,0 +1,96 @@ +identity: + name: get_markdown + author: Dify + label: + en_US: Get Markdown API + zh_Hans: Get Markdown API +description: + human: + en_US: A tool to perform convert a webpage to markdown to make it easier for LLMs to understand. + zh_Hans: 一个将网页转换为 Markdown 的工具,以便模型更容易理解 + llm: A tool to perform convert a webpage to markdown to make it easier for LLMs to understand. +parameters: + - name: url + type: string + required: true + label: + en_US: URL + zh_Hans: URL + human_description: + en_US: URL that you want to grab the content from + zh_Hans: 您要从中获取内容的 URL + llm_description: Defines the link want to grab content from. + form: llm + - name: location + type: string + required: false + default: US + label: + en_US: Location + zh_Hans: 询问 + human_description: + en_US: Defines from where you want the search to originate. (For example - New York) + zh_Hans: 定义您想要搜索的起始位置。 (例如 - 纽约) + llm_description: Defines from where you want the search to originate. (For example - New York) + form: form + options: + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - 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 + - value: JP + label: + en_US: Japan + zh_Hans: 日本 + pt_BR: Japan + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden diff --git a/api/core/tools/provider/builtin/websearch/tools/job_search.py b/api/core/tools/provider/builtin/websearch/tools/job_search.py new file mode 100644 index 0000000000..347b4eb4c4 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/job_search.py @@ -0,0 +1,86 @@ +from typing import Any, Union +from urllib.parse import urlencode + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + +BASE_URL = "https://api.serply.io/v1/news/" + + +class SerplyApi: + """ + SerplyAPI tool provider. + """ + + def __init__(self, api_key: str) -> None: + """Initialize SerplyAPI tool provider.""" + self.serply_api_key = api_key + + def run(self, query: str, **kwargs: Any) -> str: + """Run query through SerplyAPI and parse result.""" + params = {"q": query, "hl": kwargs.get("hl", "en"), "gl": kwargs.get("gl", "US"), "num": kwargs.get("num", 10)} + location = kwargs.get("location", "US") + + headers = { + "X-API-KEY": self.serply_api_key, + "X-User-Agent": kwargs.get("device", "desktop"), + "X-Proxy-Location": location, + "User-Agent": "Dify", + } + + url = f"{BASE_URL}{urlencode(params)}" + res = requests.get( + url, + headers=headers, + ) + res = res.json() + + return self.parse_results(res) + + @staticmethod + def parse_results(res: dict) -> str: + """Process response from Serply Job Search.""" + jobs = res.get("jobs", []) + if not jobs: + raise ValueError(f"Got error from Serply: {res}") + + string = [] + for job in jobs[:10]: + try: + string.append( + "\n".join([ + f"Position: {job['position']}", + f"Employer: {job['employer']}", + f"Location: {job['location']}", + f"Link: {job['link']}", + f"""Highest: {", ".join([h for h in job["highlights"]])}""", + "---", + ]) + ) + except KeyError: + continue + + content = "\n".join(string) + return f"\nJobs results:\n {content}\n" + + +class JobSearchTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any], + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + """ + Invoke the SerplyApi tool. + """ + query = tool_parameters["query"] + gl = tool_parameters.get("gl", "us") + hl = tool_parameters.get("hl", "en") + location = tool_parameters.get("location", None) + + api_key = self.runtime.credentials["serply_api_key"] + result = SerplyApi(api_key).run(query, gl=gl, hl=hl, location=location) + + return self.create_text_message(text=result) diff --git a/api/core/tools/provider/builtin/websearch/tools/job_search.yaml b/api/core/tools/provider/builtin/websearch/tools/job_search.yaml new file mode 100644 index 0000000000..b5ede3df46 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/job_search.yaml @@ -0,0 +1,41 @@ +identity: + name: job_search + author: Dify + label: + en_US: Job Search API + zh_Hans: Job Search API +description: + human: + en_US: A tool to retrieve job titles, company names and description from Google Jobs engine. + zh_Hans: 一个从 Google 招聘引擎检索职位名称、公司名称和描述的工具。 + llm: A tool to retrieve job titles, company names and description from Google Jobs engine. +parameters: + - name: query + type: string + required: true + label: + en_US: Query + zh_Hans: 询问 + human_description: + en_US: Defines the query you want to search. + zh_Hans: 定义您要搜索的查询。 + llm_description: Defines the search query you want to search. + form: llm + - name: location + type: string + required: false + default: US + label: + en_US: Location + zh_Hans: 询问 + human_description: + en_US: Defines from where you want the search to originate. (For example - New York) + zh_Hans: 定义您想要搜索的起始位置。 (例如 - 纽约) + llm_description: Defines from where you want the search to originate. (For example - New York) + form: form + options: + - value: US + label: + en_US: United States + zh_Hans: 美国 + pt_BR: United States diff --git a/api/core/tools/provider/builtin/websearch/tools/news_search.py b/api/core/tools/provider/builtin/websearch/tools/news_search.py new file mode 100644 index 0000000000..886ea47765 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/news_search.py @@ -0,0 +1,88 @@ +from typing import Any, Union +from urllib.parse import urlencode + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + +BASE_URL = "https://api.serply.io/v1/news/" + + +class SerplyApi: + """ + SerplyApi tool provider. + """ + + def __init__(self, api_key: str) -> None: + """Initialize SerplyApi tool provider.""" + self.serply_api_key = api_key + + def run(self, query: str, **kwargs: Any) -> str: + """Run query through SerplyApi and parse result.""" + params = {"q": query, "hl": kwargs.get("hl", "en"), "gl": kwargs.get("gl", "US"), "num": kwargs.get("num", 10)} + location = kwargs.get("location", "US") + + headers = { + "X-API-KEY": self.serply_api_key, + "X-User-Agent": kwargs.get("device", "desktop"), + "X-Proxy-Location": location, + "User-Agent": "Dify", + } + + url = f"{BASE_URL}{urlencode(params)}" + res = requests.get( + url, + headers=headers, + ) + res = res.json() + + return self.parse_results(res) + + @staticmethod + def parse_results(res: dict) -> str: + """Process response from Serply News Search.""" + news = res.get("entries", []) + if not news: + raise ValueError(f"Got error from Serply: {res}") + + string = [] + for entry in news: + try: + # follow url + r = requests.get(entry["link"]) + final_link = r.history[-1].headers["Location"] + string.append( + "\n".join([ + f"Title: {entry['title']}", + f"Link: {final_link}", + f"Source: {entry['source']['title']}", + f"Published: {entry['published']}", + "---", + ]) + ) + except KeyError: + continue + + content = "\n".join(string) + return f"\nNews:\n {content}\n" + + +class NewsSearchTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any], + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + """ + Invoke the SerplyApi tool. + """ + query = tool_parameters["query"] + gl = tool_parameters.get("gl", "us") + hl = tool_parameters.get("hl", "en") + location = tool_parameters.get("location", None) + + api_key = self.runtime.credentials["serply_api_key"] + result = SerplyApi(api_key).run(query, gl=gl, hl=hl, location=location) + + return self.create_text_message(text=result) diff --git a/api/core/tools/provider/builtin/websearch/tools/news_search.yaml b/api/core/tools/provider/builtin/websearch/tools/news_search.yaml new file mode 100644 index 0000000000..126c610825 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/news_search.yaml @@ -0,0 +1,501 @@ +identity: + name: news_search + author: Dify + label: + en_US: News Search API + zh_Hans: News Search API +description: + human: + en_US: A tool to retrieve organic search results snippets and links from Google News engine. + zh_Hans: 一种从 Google 新闻引擎检索有机搜索结果片段和链接的工具。 + llm: A tool to retrieve organic search results snippets and links from Google News engine. +parameters: + - name: query + type: string + required: true + label: + en_US: Query + zh_Hans: 询问 + human_description: + en_US: Defines the query you want to search. + zh_Hans: 定义您要搜索的查询。 + llm_description: Defines the search query you want to search. + form: llm + - name: location + type: string + required: false + default: US + label: + en_US: Location + zh_Hans: 询问 + human_description: + en_US: Defines from where you want the search to originate. (For example - New York) + zh_Hans: 定义您想要搜索的起始位置。 (例如 - 纽约) + llm_description: Defines from where you want the search to originate. (For example - New York) + form: form + options: + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - 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 + - value: JP + label: + en_US: Japan + zh_Hans: 日本 + pt_BR: Japan + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden + - name: gl + type: select + label: + en_US: Country + zh_Hans: 国家/地区 + required: false + human_description: + en_US: Defines the country of the search. Default is "US". + zh_Hans: 定义搜索的国家/地区。默认为“美国”。 + llm_description: Defines the gl parameter of the Google search. + 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: hl + type: select + label: + en_US: Language + zh_Hans: 语言 + human_description: + en_US: Defines the interface language of the search. Default is "en". + zh_Hans: 定义搜索的界面语言。默认为“en”。 + required: false + default: en + form: form + options: + - value: ar + label: + en_US: Arabic + zh_Hans: 阿拉伯语 + - value: bg + label: + en_US: Bulgarian + zh_Hans: 保加利亚语 + - value: ca + label: + en_US: Catalan + zh_Hans: 加泰罗尼亚语 + - value: zh-cn + label: + en_US: Chinese (Simplified) + zh_Hans: 中文(简体) + - value: zh-tw + label: + en_US: Chinese (Traditional) + zh_Hans: 中文(繁体) + - value: cs + label: + en_US: Czech + zh_Hans: 捷克语 + - value: da + label: + en_US: Danish + zh_Hans: 丹麦语 + - value: nl + label: + en_US: Dutch + zh_Hans: 荷兰语 + - value: en + label: + en_US: English + zh_Hans: 英语 + - value: et + label: + en_US: Estonian + zh_Hans: 爱沙尼亚语 + - value: fi + label: + en_US: Finnish + zh_Hans: 芬兰语 + - value: fr + label: + en_US: French + zh_Hans: 法语 + - value: de + label: + en_US: German + zh_Hans: 德语 + - value: el + label: + en_US: Greek + zh_Hans: 希腊语 + - value: iw + label: + en_US: Hebrew + zh_Hans: 希伯来语 + - value: hi + label: + en_US: Hindi + zh_Hans: 印地语 + - value: hu + label: + en_US: Hungarian + zh_Hans: 匈牙利语 + - value: id + label: + en_US: Indonesian + zh_Hans: 印尼语 + - value: it + label: + en_US: Italian + zh_Hans: 意大利语 + - value: ja + label: + en_US: Japanese + zh_Hans: 日语 + - value: kn + label: + en_US: Kannada + zh_Hans: 卡纳达语 + - value: ko + label: + en_US: Korean + zh_Hans: 韩语 + - value: lv + label: + en_US: Latvian + zh_Hans: 拉脱维亚语 + - value: lt + label: + en_US: Lithuanian + zh_Hans: 立陶宛语 + - value: my + label: + en_US: Malay + zh_Hans: 马来语 + - value: ml + label: + en_US: Malayalam + zh_Hans: 马拉雅拉姆语 + - value: mr + label: + en_US: Marathi + zh_Hans: 马拉地语 + - value: "no" + label: + en_US: Norwegian + zh_Hans: 挪威语 + - value: pl + label: + en_US: Polish + zh_Hans: 波兰语 + - value: pt-br + label: + en_US: Portuguese (Brazil) + zh_Hans: 葡萄牙语(巴西) + - value: pt-pt + label: + en_US: Portuguese (Portugal) + zh_Hans: 葡萄牙语(葡萄牙) + - value: pa + label: + en_US: Punjabi + zh_Hans: 旁遮普语 + - value: ro + label: + en_US: Romanian + zh_Hans: 罗马尼亚语 + - value: ru + label: + en_US: Russian + zh_Hans: 俄语 + - value: sr + label: + en_US: Serbian + zh_Hans: 塞尔维亚语 + - value: sk + label: + en_US: Slovak + zh_Hans: 斯洛伐克语 + - value: sl + label: + en_US: Slovenian + zh_Hans: 斯洛文尼亚语 + - value: es + label: + en_US: Spanish + zh_Hans: 西班牙语 + - value: sv + label: + en_US: Swedish + zh_Hans: 瑞典语 + - value: ta + label: + en_US: Tamil + zh_Hans: 泰米尔语 + - value: te + label: + en_US: Telugu + zh_Hans: 泰卢固语 + - value: th + label: + en_US: Thai + zh_Hans: 泰语 + - value: tr + label: + en_US: Turkish + zh_Hans: 土耳其语 + - value: uk + label: + en_US: Ukrainian + zh_Hans: 乌克兰语 + - value: vi + label: + en_US: Vietnamese + zh_Hans: 越南语 diff --git a/api/core/tools/provider/builtin/websearch/tools/scholar_search.py b/api/core/tools/provider/builtin/websearch/tools/scholar_search.py new file mode 100644 index 0000000000..19df455231 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/scholar_search.py @@ -0,0 +1,91 @@ +from typing import Any, Union +from urllib.parse import urlencode + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + +BASE_URL = "https://api.serply.io/v1/scholar/" + + +class SerplyApi: + """ + SerplyApi tool provider. + """ + + def __init__(self, api_key: str) -> None: + """Initialize SerplyApi tool provider.""" + self.serply_api_key = api_key + + def run(self, query: str, **kwargs: Any) -> str: + """Run query through SerplyApi and parse result.""" + params = {"q": query, "hl": kwargs.get("hl", "en"), "gl": kwargs.get("gl", "US"), "num": kwargs.get("num", 10)} + location = kwargs.get("location", "US") + + headers = { + "X-API-KEY": self.serply_api_key, + "X-User-Agent": kwargs.get("device", "desktop"), + "X-Proxy-Location": location, + "User-Agent": "Dify", + } + + url = f"{BASE_URL}{urlencode(params)}" + res = requests.get( + url, + headers=headers, + ) + res = res.json() + + return self.parse_results(res) + + @staticmethod + def parse_results(res: dict) -> str: + """Process response from Serply News Search.""" + articles = res.get("articles", []) + if not articles: + raise ValueError(f"Got error from Serply: {res}") + + string = [] + for article in articles: + try: + if "doc" in article: + link = article["doc"]["link"] + else: + link = article["link"] + authors = [author["name"] for author in article["author"]["authors"]] + string.append( + "\n".join([ + f"Title: {article['title']}", + f"Link: {link}", + f"Description: {article['description']}", + f"Cite: {article['cite']}", + f"Authors: {', '.join(authors)}", + "---", + ]) + ) + except KeyError: + continue + + content = "\n".join(string) + return f"\nScholar results:\n {content}\n" + + +class ScholarSearchTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any], + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + """ + Invoke the SerplyApi tool. + """ + query = tool_parameters["query"] + gl = tool_parameters.get("gl", "us") + hl = tool_parameters.get("hl", "en") + location = tool_parameters.get("location", None) + + api_key = self.runtime.credentials["serply_api_key"] + result = SerplyApi(api_key).run(query, gl=gl, hl=hl, location=location) + + return self.create_text_message(text=result) diff --git a/api/core/tools/provider/builtin/websearch/tools/scholar_search.yaml b/api/core/tools/provider/builtin/websearch/tools/scholar_search.yaml new file mode 100644 index 0000000000..59f60d6d48 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/scholar_search.yaml @@ -0,0 +1,501 @@ +identity: + name: scholar_search + author: Dify + label: + en_US: Scholar API + zh_Hans: Scholar API +description: + human: + en_US: A tool to retrieve scholarly literature. + zh_Hans: 学术文献检索工具 + llm: A tool to retrieve scholarly literature. +parameters: + - name: query + type: string + required: true + label: + en_US: Query + zh_Hans: 询问 + human_description: + en_US: Defines the query you want to search. + zh_Hans: 定义您要搜索的查询。 + llm_description: Defines the search query you want to search. + form: llm + - name: location + type: string + required: false + default: US + label: + en_US: Location + zh_Hans: 询问 + human_description: + en_US: Defines from where you want the search to originate. (For example - New York) + zh_Hans: 定义您想要搜索的起始位置。 (例如 - 纽约) + llm_description: Defines from where you want the search to originate. (For example - New York) + form: form + options: + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - 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 + - value: JP + label: + en_US: Japan + zh_Hans: 日本 + pt_BR: Japan + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden + - name: gl + type: select + label: + en_US: Country + zh_Hans: 国家/地区 + required: false + human_description: + en_US: Defines the country of the search. Default is "US". + zh_Hans: 定义搜索的国家/地区。默认为“美国”。 + llm_description: Defines the gl parameter of the Google search. + 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: hl + type: select + label: + en_US: Language + zh_Hans: 语言 + human_description: + en_US: Defines the interface language of the search. Default is "en". + zh_Hans: 定义搜索的界面语言。默认为“en”。 + required: false + default: en + form: form + options: + - value: ar + label: + en_US: Arabic + zh_Hans: 阿拉伯语 + - value: bg + label: + en_US: Bulgarian + zh_Hans: 保加利亚语 + - value: ca + label: + en_US: Catalan + zh_Hans: 加泰罗尼亚语 + - value: zh-cn + label: + en_US: Chinese (Simplified) + zh_Hans: 中文(简体) + - value: zh-tw + label: + en_US: Chinese (Traditional) + zh_Hans: 中文(繁体) + - value: cs + label: + en_US: Czech + zh_Hans: 捷克语 + - value: da + label: + en_US: Danish + zh_Hans: 丹麦语 + - value: nl + label: + en_US: Dutch + zh_Hans: 荷兰语 + - value: en + label: + en_US: English + zh_Hans: 英语 + - value: et + label: + en_US: Estonian + zh_Hans: 爱沙尼亚语 + - value: fi + label: + en_US: Finnish + zh_Hans: 芬兰语 + - value: fr + label: + en_US: French + zh_Hans: 法语 + - value: de + label: + en_US: German + zh_Hans: 德语 + - value: el + label: + en_US: Greek + zh_Hans: 希腊语 + - value: iw + label: + en_US: Hebrew + zh_Hans: 希伯来语 + - value: hi + label: + en_US: Hindi + zh_Hans: 印地语 + - value: hu + label: + en_US: Hungarian + zh_Hans: 匈牙利语 + - value: id + label: + en_US: Indonesian + zh_Hans: 印尼语 + - value: it + label: + en_US: Italian + zh_Hans: 意大利语 + - value: ja + label: + en_US: Japanese + zh_Hans: 日语 + - value: kn + label: + en_US: Kannada + zh_Hans: 卡纳达语 + - value: ko + label: + en_US: Korean + zh_Hans: 韩语 + - value: lv + label: + en_US: Latvian + zh_Hans: 拉脱维亚语 + - value: lt + label: + en_US: Lithuanian + zh_Hans: 立陶宛语 + - value: my + label: + en_US: Malay + zh_Hans: 马来语 + - value: ml + label: + en_US: Malayalam + zh_Hans: 马拉雅拉姆语 + - value: mr + label: + en_US: Marathi + zh_Hans: 马拉地语 + - value: "no" + label: + en_US: Norwegian + zh_Hans: 挪威语 + - value: pl + label: + en_US: Polish + zh_Hans: 波兰语 + - value: pt-br + label: + en_US: Portuguese (Brazil) + zh_Hans: 葡萄牙语(巴西) + - value: pt-pt + label: + en_US: Portuguese (Portugal) + zh_Hans: 葡萄牙语(葡萄牙) + - value: pa + label: + en_US: Punjabi + zh_Hans: 旁遮普语 + - value: ro + label: + en_US: Romanian + zh_Hans: 罗马尼亚语 + - value: ru + label: + en_US: Russian + zh_Hans: 俄语 + - value: sr + label: + en_US: Serbian + zh_Hans: 塞尔维亚语 + - value: sk + label: + en_US: Slovak + zh_Hans: 斯洛伐克语 + - value: sl + label: + en_US: Slovenian + zh_Hans: 斯洛文尼亚语 + - value: es + label: + en_US: Spanish + zh_Hans: 西班牙语 + - value: sv + label: + en_US: Swedish + zh_Hans: 瑞典语 + - value: ta + label: + en_US: Tamil + zh_Hans: 泰米尔语 + - value: te + label: + en_US: Telugu + zh_Hans: 泰卢固语 + - value: th + label: + en_US: Thai + zh_Hans: 泰语 + - value: tr + label: + en_US: Turkish + zh_Hans: 土耳其语 + - value: uk + label: + en_US: Ukrainian + zh_Hans: 乌克兰语 + - value: vi + label: + en_US: Vietnamese + zh_Hans: 越南语 diff --git a/api/core/tools/provider/builtin/websearch/tools/web_search.py b/api/core/tools/provider/builtin/websearch/tools/web_search.py new file mode 100644 index 0000000000..4f57c27caf --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/web_search.py @@ -0,0 +1,88 @@ +import typing +from urllib.parse import urlencode + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + + +class SerplyApi: + """ + SerplyApi tool provider. + """ + + def __init__(self, api_key: str) -> None: + """Initialize Serply Web Search Tool provider.""" + self.serply_api_key = api_key + self.base_url = "https://api.serply.io/v1/search/" + + def run(self, query: str, **kwargs: typing.Any) -> str: + """Run query through Serply and parse result.""" + params = {"q": query, "hl": kwargs.get("hl", "en"), "gl": kwargs.get("gl", "US"), "num": kwargs.get("num", 10)} + location = kwargs.get("location", "US") + + headers = { + "X-API-KEY": self.serply_api_key, + "X-User-Agent": kwargs.get("device", "desktop"), + "X-Proxy-Location": location, + "User-Agent": "Dify", + } + + url = f"{self.base_url}{urlencode(params)}" + res = requests.get( + url, + headers=headers, + ) + res = res.json() + + return self.parse_results(res) + + @staticmethod + def parse_results(res: dict) -> str: + """Process response from Serply Web Search.""" + results = res.get("results", []) + if not results: + raise ValueError(f"Got error from Serply: {res}") + + string = [] + for result in results: + try: + string.append( + "\n".join([ + f"Title: {result['title']}", + f"Link: {result['link']}", + f"Description: {result['description'].strip()}", + "---", + ]) + ) + except KeyError: + continue + + if related_questions := res.get("related_questions", []): + string.append("---") + string.append("Related Questions: ") + string.append("\n".join(related_questions)) + + content = "\n".join(string) + return f"\nSearch results:\n {content}\n" + + +class WebSearchTool(BuiltinTool): + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, typing.Any], + ) -> typing.Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + """ + Invoke the SerplyApi tool. + """ + query = tool_parameters["query"] + num = tool_parameters.get("num", 10) + gl = tool_parameters.get("gl", "us") + hl = tool_parameters.get("hl", "en") + location = tool_parameters.get("location", "None") + + api_key = self.runtime.credentials["serply_api_key"] + result = SerplyApi(api_key).run(query=query, num=num, gl=gl, hl=hl, location=location) + return self.create_text_message(text=result) diff --git a/api/core/tools/provider/builtin/websearch/tools/web_search.yaml b/api/core/tools/provider/builtin/websearch/tools/web_search.yaml new file mode 100644 index 0000000000..055029253c --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/tools/web_search.yaml @@ -0,0 +1,376 @@ +identity: + name: web_search + author: Dify + label: + en_US: Web Search API + zh_Hans: Web Search API +description: + human: + en_US: A tool to retrieve answer boxes, knowledge graphs, snippets, and webpages from Google Search engine. + zh_Hans: 一种从 Google 搜索引擎检索答案框、知识图、片段和网页的工具。 + llm: A tool to retrieve answer boxes, knowledge graphs, snippets, and webpages from Google Search engine. +parameters: + - name: query + type: string + required: true + label: + en_US: Query + zh_Hans: 询问 + human_description: + en_US: Defines the query you want to search. + zh_Hans: 定义您要搜索的查询。 + llm_description: Defines the search query you want to search. + form: llm + - name: location + type: string + required: false + default: US + label: + en_US: Location + zh_Hans: 询问 + human_description: + en_US: Defines from where you want the search to originate. (For example - New York) + zh_Hans: 定义您想要搜索的起始位置。 (例如 - 纽约) + llm_description: Defines from where you want the search to originate. (For example - New York) + form: form + options: + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - 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 + - value: JP + label: + en_US: Japan + zh_Hans: 日本 + pt_BR: Japan + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden + - name: device + type: select + label: + en_US: Device Type + zh_Hans: 汉斯先生 + human_description: + en_US: Defines the device to make interface search. Default is "desktop". + zh_Hans: 定义进行接口搜索的设备。默认为“桌面” + required: false + default: desktop + form: form + options: + - value: desktop + label: + en_US: Desktop + zh_Hans: 桌面 + - value: mobile + label: + en_US: Mobile + zh_Hans: 移动的 + - name: gl + type: select + label: + en_US: Country + zh_Hans: 国家/地区 + required: false + human_description: + en_US: Defines the country of the search. Default is "US". + zh_Hans: 定义搜索的国家/地区。默认为“美国”。 + llm_description: Defines the gl parameter of the Google search. + form: form + default: US + options: + - value: AU + label: + en_US: Australia + zh_Hans: 澳大利亚 + pt_BR: Australia + - value: BR + label: + en_US: Brazil + zh_Hans: 巴西 + pt_BR: Brazil + - value: CA + label: + en_US: Canada + zh_Hans: 加拿大 + pt_BR: Canada + - value: DE + label: + en_US: Germany + zh_Hans: 德国 + pt_BR: Germany + - value: FR + label: + en_US: France + zh_Hans: 法国 + pt_BR: France + - value: GB + label: + en_US: United Kingdom + zh_Hans: 英国 + pt_BR: United Kingdom + - value: IN + label: + en_US: India + zh_Hans: 印度 + pt_BR: India + - value: KR + label: + en_US: Korea + zh_Hans: 韩国 + pt_BR: Korea + - value: SE + label: + en_US: Sweden + zh_Hans: 瑞典 + pt_BR: Sweden + - value: SG + label: + en_US: Singapore + zh_Hans: 新加坡 + pt_BR: Singapore + - value: US + label: + en_US: United States + zh_Hans: 美国 + pt_BR: United States + - name: hl + type: select + label: + en_US: Language + zh_Hans: 语言 + human_description: + en_US: Defines the interface language of the search. Default is "en". + zh_Hans: 定义搜索的界面语言。默认为“en”。 + required: false + default: en + form: form + options: + - value: ar + label: + en_US: Arabic + zh_Hans: 阿拉伯语 + - value: bg + label: + en_US: Bulgarian + zh_Hans: 保加利亚语 + - value: ca + label: + en_US: Catalan + zh_Hans: 加泰罗尼亚语 + - value: zh-cn + label: + en_US: Chinese (Simplified) + zh_Hans: 中文(简体) + - value: zh-tw + label: + en_US: Chinese (Traditional) + zh_Hans: 中文(繁体) + - value: cs + label: + en_US: Czech + zh_Hans: 捷克语 + - value: da + label: + en_US: Danish + zh_Hans: 丹麦语 + - value: nl + label: + en_US: Dutch + zh_Hans: 荷兰语 + - value: en + label: + en_US: English + zh_Hans: 英语 + - value: et + label: + en_US: Estonian + zh_Hans: 爱沙尼亚语 + - value: fi + label: + en_US: Finnish + zh_Hans: 芬兰语 + - value: fr + label: + en_US: French + zh_Hans: 法语 + - value: de + label: + en_US: German + zh_Hans: 德语 + - value: el + label: + en_US: Greek + zh_Hans: 希腊语 + - value: iw + label: + en_US: Hebrew + zh_Hans: 希伯来语 + - value: hi + label: + en_US: Hindi + zh_Hans: 印地语 + - value: hu + label: + en_US: Hungarian + zh_Hans: 匈牙利语 + - value: id + label: + en_US: Indonesian + zh_Hans: 印尼语 + - value: it + label: + en_US: Italian + zh_Hans: 意大利语 + - value: ja + label: + en_US: Japanese + zh_Hans: 日语 + - value: kn + label: + en_US: Kannada + zh_Hans: 卡纳达语 + - value: ko + label: + en_US: Korean + zh_Hans: 韩语 + - value: lv + label: + en_US: Latvian + zh_Hans: 拉脱维亚语 + - value: lt + label: + en_US: Lithuanian + zh_Hans: 立陶宛语 + - value: my + label: + en_US: Malay + zh_Hans: 马来语 + - value: ml + label: + en_US: Malayalam + zh_Hans: 马拉雅拉姆语 + - value: mr + label: + en_US: Marathi + zh_Hans: 马拉地语 + - value: "no" + label: + en_US: Norwegian + zh_Hans: 挪威语 + - value: pl + label: + en_US: Polish + zh_Hans: 波兰语 + - value: pt-br + label: + en_US: Portuguese (Brazil) + zh_Hans: 葡萄牙语(巴西) + - value: pt-pt + label: + en_US: Portuguese (Portugal) + zh_Hans: 葡萄牙语(葡萄牙) + - value: pa + label: + en_US: Punjabi + zh_Hans: 旁遮普语 + - value: ro + label: + en_US: Romanian + zh_Hans: 罗马尼亚语 + - value: ru + label: + en_US: Russian + zh_Hans: 俄语 + - value: sr + label: + en_US: Serbian + zh_Hans: 塞尔维亚语 + - value: sk + label: + en_US: Slovak + zh_Hans: 斯洛伐克语 + - value: sl + label: + en_US: Slovenian + zh_Hans: 斯洛文尼亚语 + - value: es + label: + en_US: Spanish + zh_Hans: 西班牙语 + - value: sv + label: + en_US: Swedish + zh_Hans: 瑞典语 + - value: ta + label: + en_US: Tamil + zh_Hans: 泰米尔语 + - value: te + label: + en_US: Telugu + zh_Hans: 泰卢固语 + - value: th + label: + en_US: Thai + zh_Hans: 泰语 + - value: tr + label: + en_US: Turkish + zh_Hans: 土耳其语 + - value: uk + label: + en_US: Ukrainian + zh_Hans: 乌克兰语 + - value: vi + label: + en_US: Vietnamese + zh_Hans: 越南语 diff --git a/api/core/tools/provider/builtin/websearch/websearch.py b/api/core/tools/provider/builtin/websearch/websearch.py new file mode 100644 index 0000000000..90cc0c573a --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/websearch.py @@ -0,0 +1,21 @@ +from typing import Any + +from core.tools.errors import ToolProviderCredentialValidationError +from core.tools.provider.builtin.websearch.tools.web_search import WebSearchTool +from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController + + +class WebSearchAPIProvider(BuiltinToolProviderController): + # validate when saving the api_key + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + try: + WebSearchTool().fork_tool_runtime( + runtime={ + "credentials": credentials, + } + ).invoke( + user_id="", + tool_parameters={"query": "what is llm"}, + ) + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) diff --git a/api/core/tools/provider/builtin/websearch/websearch.yaml b/api/core/tools/provider/builtin/websearch/websearch.yaml new file mode 100644 index 0000000000..c4267e1022 --- /dev/null +++ b/api/core/tools/provider/builtin/websearch/websearch.yaml @@ -0,0 +1,34 @@ +identity: + name: websearch + author: Serply.io + label: + en_US: Serply.io + zh_Hans: Serply.io + pt_BR: Serply.io + description: + en_US: Serply.io is a robust real-time SERP API delivering structured data from a collection of search engines including Web Search, Jobs, News, and many more. + zh_Hans: Serply.io 是一个强大的实时 SERP API,可提供来自 搜索 招聘 新闻等搜索引擎集合的结构化数据。 + pt_BR: Serply.io is a robust real-time SERP API delivering structured data from a collection of search engines including Web Search, Jobs, News, and many more. + icon: icon.svg + tags: + - search + - business + - news + - productivity +credentials_for_provider: + serply_api_key: + type: secret-input + required: true + label: + en_US: Serply.io API key + zh_Hans: Serply.io API key + pt_BR: Serply.io API key + placeholder: + en_US: Please input your Serply.io API key + zh_Hans: 请输入你的 Serply.io API key + pt_BR: Please input your Serply.io API key + help: + en_US: Get your Serply.io API key from https://Serply.io/ + zh_Hans: 从 Serply.io 获取您的 Serply.io API key + pt_BR: Get your Serply.io API key from Serply.io + url: https://Serply.io/