diff --git a/api/core/entities/provider_entities.py b/api/core/entities/provider_entities.py index 23f0b9cb3b..0d5b0a1b2c 100644 --- a/api/core/entities/provider_entities.py +++ b/api/core/entities/provider_entities.py @@ -97,3 +97,6 @@ class ModelSettings(BaseModel): model_type: ModelType enabled: bool = True load_balancing_configs: list[ModelLoadBalancingConfiguration] = [] + + # pydantic configs + model_config = ConfigDict(protected_namespaces=()) diff --git a/api/core/tools/entities/api_entities.py b/api/core/tools/entities/api_entities.py index da12996b2b..2b01b8fd8e 100644 --- a/api/core/tools/entities/api_entities.py +++ b/api/core/tools/entities/api_entities.py @@ -28,8 +28,8 @@ class UserToolProvider(BaseModel): icon: str label: I18nObject # label type: ToolProviderType - masked_credentials: dict = None - original_credentials: dict = None + masked_credentials: Optional[dict] = None + original_credentials: Optional[dict] = None is_team_authorization: bool = False allow_delete: bool = True tools: list[UserTool] = None diff --git a/api/core/tools/provider/builtin/aippt/tools/aippt.py b/api/core/tools/provider/builtin/aippt/tools/aippt.py index 518eb732c2..8d6883a3b1 100644 --- a/api/core/tools/provider/builtin/aippt/tools/aippt.py +++ b/api/core/tools/provider/builtin/aippt/tools/aippt.py @@ -507,9 +507,9 @@ class AIPPTGenerateTool(BuiltinTool): colors, styles = self.get_styles(user_id='__dify_system__') except Exception as e: colors, styles = [ - {'id': -1, 'name': '__default__', 'en_name': '__default__'} + {'id': '-1', 'name': '__default__', 'en_name': '__default__'} ], [ - {'id': -1, 'name': '__default__', 'en_name': '__default__'} + {'id': '-1', 'name': '__default__', 'en_name': '__default__'} ] return [ 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 index 6bf64efb99..a3f60bb09b 100644 --- a/api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml +++ b/api/core/tools/provider/builtin/bing/tools/bing_web_search.yaml @@ -263,7 +263,7 @@ parameters: en_US: New Zealand zh_Hans: 新西兰 pt_BR: New Zealand - - value: NO + - value: 'NO' label: en_US: Norway zh_Hans: 挪威 diff --git a/api/core/tools/provider/builtin/duckduckgo/tools/duckduckgo_search.py b/api/core/tools/provider/builtin/duckduckgo/tools/duckduckgo_search.py deleted file mode 100644 index 5beaa7bf44..0000000000 --- a/api/core/tools/provider/builtin/duckduckgo/tools/duckduckgo_search.py +++ /dev/null @@ -1,174 +0,0 @@ -<<<<<<< HEAD -======= -from typing import Any, Optional - -from pydantic import BaseModel, Field - -from core.tools.entities.tool_entities import ToolInvokeMessage -from core.tools.tool.builtin_tool import BuiltinTool - - -class DuckDuckGoSearchAPIWrapper(BaseModel): - """Wrapper for DuckDuckGo Search API. - - Free and does not require any setup. - """ - - region: Optional[str] = "wt-wt" - safesearch: str = "moderate" - time: Optional[str] = "y" - max_results: int = 5 - - def get_snippets(self, query: str) -> list[str]: - """Run query through DuckDuckGo and return concatenated results.""" - from duckduckgo_search import DDGS - - with DDGS() as ddgs: - results = ddgs.text( - query, - region=self.region, - safesearch=self.safesearch, - timelimit=self.time, - ) - if results is None: - return ["No good DuckDuckGo Search Result was found"] - snippets = [] - for i, res in enumerate(results, 1): - if res is not None: - snippets.append(res["body"]) - if len(snippets) == self.max_results: - break - return snippets - - def run(self, query: str) -> str: - snippets = self.get_snippets(query) - return " ".join(snippets) - - def results( - self, query: str, num_results: int, backend: str = "api" - ) -> list[dict[str, str]]: - """Run query through DuckDuckGo and return metadata. - - Args: - query: The query to search for. - num_results: The number of results to return. - - Returns: - A list of dictionaries with the following keys: - snippet - The description of the result. - title - The title of the result. - link - The link to the result. - """ - from duckduckgo_search import DDGS - - with DDGS() as ddgs: - results = ddgs.text( - query, - region=self.region, - safesearch=self.safesearch, - timelimit=self.time, - backend=backend, - ) - if results is None: - return [{"Result": "No good DuckDuckGo Search Result was found"}] - - def to_metadata(result: dict) -> dict[str, str]: - if backend == "news": - return { - "date": result["date"], - "title": result["title"], - "snippet": result["body"], - "source": result["source"], - "link": result["url"], - } - return { - "snippet": result["body"], - "title": result["title"], - "link": result["href"], - } - - formatted_results = [] - for i, res in enumerate(results, 1): - if res is not None: - formatted_results.append(to_metadata(res)) - if len(formatted_results) == num_results: - break - return formatted_results - - -class DuckDuckGoSearchRun(BaseModel): - """Tool that queries the DuckDuckGo search API.""" - - name: str = "duckduckgo_search" - description: str = ( - "A wrapper around DuckDuckGo Search. " - "Useful for when you need to answer questions about current events. " - "Input should be a search query." - ) - api_wrapper: DuckDuckGoSearchAPIWrapper = Field( - default_factory=DuckDuckGoSearchAPIWrapper - ) - - def _run( - self, - query: str, - ) -> str: - """Use the tool.""" - return self.api_wrapper.run(query) - - -class DuckDuckGoSearchResults(BaseModel): - """Tool that queries the DuckDuckGo search API and gets back json.""" - - name: str = "DuckDuckGo Results JSON" - description: str = ( - "A wrapper around Duck Duck Go Search. " - "Useful for when you need to answer questions about current events. " - "Input should be a search query. Output is a JSON array of the query results" - ) - num_results: int = 4 - api_wrapper: DuckDuckGoSearchAPIWrapper = Field( - default_factory=DuckDuckGoSearchAPIWrapper - ) - backend: str = "api" - - def _run( - self, - query: str, - ) -> str: - """Use the tool.""" - res = self.api_wrapper.results(query, self.num_results, backend=self.backend) - res_strs = [", ".join([f"{k}: {v}" for k, v in d.items()]) for d in res] - return ", ".join([f"[{rs}]" for rs in res_strs]) - -class DuckDuckGoInput(BaseModel): - query: str = Field(..., description="Search query.") - -class DuckDuckGoSearchTool(BuiltinTool): - """ - Tool for performing a search using DuckDuckGo search engine. - """ - - def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]: - """ - Invoke the DuckDuckGo search tool. - - Args: - user_id (str): The ID of the user invoking the tool. - tool_parameters (dict[str, Any]): The parameters for the tool invocation. - - Returns: - ToolInvokeMessage | list[ToolInvokeMessage]: The result of the tool invocation. - """ - query = tool_parameters.get('query', '') - - if not query: - return self.create_text_message('Please input query') - - tool = DuckDuckGoSearchRun(args_schema=DuckDuckGoInput) - - result = tool._run(query) - - return self.create_text_message(self.summary(user_id=user_id, content=result)) - ->>>>>>> 4c2ba442b (missing type in DuckDuckGoSearchAPIWrapper) diff --git a/api/core/tools/provider/builtin/firecrawl/tools/crawl.yaml b/api/core/tools/provider/builtin/firecrawl/tools/crawl.yaml index 5f6ba955b8..3861670140 100644 --- a/api/core/tools/provider/builtin/firecrawl/tools/crawl.yaml +++ b/api/core/tools/provider/builtin/firecrawl/tools/crawl.yaml @@ -67,12 +67,12 @@ parameters: zh_Hans: 如果启用,爬虫将仅返回页面的主要内容,不包括标题、导航、页脚等。 form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 - default: false + default: 'false' diff --git a/api/core/tools/provider/builtin/searchapi/tools/google.yaml b/api/core/tools/provider/builtin/searchapi/tools/google.yaml index eab753e5e8..b69a0e1d3e 100644 --- a/api/core/tools/provider/builtin/searchapi/tools/google.yaml +++ b/api/core/tools/provider/builtin/searchapi/tools/google.yaml @@ -185,7 +185,7 @@ parameters: en_US: New Zealand zh_Hans: 新西兰 pt_BR: New Zealand - - value: NO + - value: 'NO' label: en_US: Norway zh_Hans: 挪威 diff --git a/api/core/tools/provider/builtin/searchapi/tools/google_jobs.yaml b/api/core/tools/provider/builtin/searchapi/tools/google_jobs.yaml index 73026d7c41..9033bc0f87 100644 --- a/api/core/tools/provider/builtin/searchapi/tools/google_jobs.yaml +++ b/api/core/tools/provider/builtin/searchapi/tools/google_jobs.yaml @@ -185,7 +185,7 @@ parameters: en_US: New Zealand zh_Hans: 新西兰 pt_BR: New Zealand - - value: NO + - value: 'NO' label: en_US: Norway zh_Hans: 挪威 @@ -468,11 +468,11 @@ parameters: required: false form: form options: - - value: true + - value: 'true' label: en_US: "true" zh_Hans: "true" - - value: false + - value: 'false' label: en_US: "false" zh_Hans: "false" diff --git a/api/core/tools/provider/builtin/searchapi/tools/google_news.yaml b/api/core/tools/provider/builtin/searchapi/tools/google_news.yaml index 719cf6119b..cbb0edf982 100644 --- a/api/core/tools/provider/builtin/searchapi/tools/google_news.yaml +++ b/api/core/tools/provider/builtin/searchapi/tools/google_news.yaml @@ -185,7 +185,7 @@ parameters: en_US: New Zealand zh_Hans: 新西兰 pt_BR: New Zealand - - value: NO + - value: 'NO' label: en_US: Norway zh_Hans: 挪威 diff --git a/api/core/tools/provider/builtin/stackexchange/stackexchange.yaml b/api/core/tools/provider/builtin/stackexchange/stackexchange.yaml index ad64b9595a..d382a3cca9 100644 --- a/api/core/tools/provider/builtin/stackexchange/stackexchange.yaml +++ b/api/core/tools/provider/builtin/stackexchange/stackexchange.yaml @@ -6,7 +6,7 @@ identity: zh_Hans: Stack Exchange description: en_US: Access questions and answers from the Stack Exchange and its sub-sites. - zh_Hans: 从Stack Exchange和其子论坛获取问题和答案。 + zh_Hans: 从 Stack Exchange 和其子论坛获取问题和答案。 icon: icon.svg tags: - search diff --git a/api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.yaml b/api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.yaml index ec36abd129..bbfbae38b0 100644 --- a/api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.yaml +++ b/api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.yaml @@ -96,15 +96,15 @@ parameters: zh_Hans: 是否限制为只有已接受答案的问题。 form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 - default: true + default: 'true' - name: pagesize type: number required: true diff --git a/api/core/tools/provider/builtin/tavily/tools/tavily_search.yaml b/api/core/tools/provider/builtin/tavily/tools/tavily_search.yaml index bfa578458d..88426056af 100644 --- a/api/core/tools/provider/builtin/tavily/tools/tavily_search.yaml +++ b/api/core/tools/provider/builtin/tavily/tools/tavily_search.yaml @@ -62,17 +62,17 @@ parameters: pt_BR: Include images in the search results form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 pt_BR: 'Yes' - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 pt_BR: 'No' - default: false + default: 'false' - name: include_answer type: boolean required: false @@ -86,17 +86,17 @@ parameters: pt_BR: Include answers in the search results form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 pt_BR: 'Yes' - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 pt_BR: 'No' - default: false + default: 'false' - name: include_raw_content type: boolean required: false @@ -110,17 +110,17 @@ parameters: pt_BR: Include raw content in the search results form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 pt_BR: 'Yes' - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 pt_BR: 'No' - default: false + default: 'false' - name: max_results type: number required: false diff --git a/api/core/tools/provider/builtin/webscraper/tools/webscraper.yaml b/api/core/tools/provider/builtin/webscraper/tools/webscraper.yaml index 0dae3db22f..0bb48a941d 100644 --- a/api/core/tools/provider/builtin/webscraper/tools/webscraper.yaml +++ b/api/core/tools/provider/builtin/webscraper/tools/webscraper.yaml @@ -49,12 +49,12 @@ parameters: zh_Hans: 如果启用,爬虫将仅返回页面摘要内容。 form: form options: - - value: true + - value: 'true' label: en_US: 'Yes' zh_Hans: 是 - - value: false + - value: 'false' label: en_US: 'No' zh_Hans: 否 - default: false + default: 'false' diff --git a/api/core/tools/tool/tool.py b/api/core/tools/tool/tool.py index df5a2a1e66..37432a6116 100644 --- a/api/core/tools/tool/tool.py +++ b/api/core/tools/tool/tool.py @@ -24,9 +24,9 @@ from core.tools.utils.tool_parameter_converter import ToolParameterConverter class Tool(BaseModel, ABC): - identity: ToolIdentity = None + identity: Optional[ToolIdentity] = None parameters: Optional[list[ToolParameter]] = None - description: ToolDescription = None + description: Optional[ToolDescription] = None is_team_authorization: bool = False # pydantic configs @@ -46,15 +46,15 @@ class Tool(BaseModel, ABC): if not self.runtime_parameters: self.runtime_parameters = {} - tenant_id: str = None - tool_id: str = None - invoke_from: InvokeFrom = None - tool_invoke_from: ToolInvokeFrom = None - credentials: dict[str, Any] = None - runtime_parameters: dict[str, Any] = None + tenant_id: Optional[str] = None + tool_id: Optional[str] = None + invoke_from: Optional[InvokeFrom] = None + tool_invoke_from: Optional[ToolInvokeFrom] = None + credentials: Optional[dict[str, Any]] = None + runtime_parameters: Optional[dict[str, Any]] = None - runtime: Runtime = None - variables: ToolRuntimeVariablePool = None + runtime: Optional[Runtime] = None + variables: Optional[ToolRuntimeVariablePool] = None def __init__(self, **data: Any): super().__init__(**data) diff --git a/api/services/tools/builtin_tools_manage_service.py b/api/services/tools/builtin_tools_manage_service.py index 2503191b63..ea6ecf0c69 100644 --- a/api/services/tools/builtin_tools_manage_service.py +++ b/api/services/tools/builtin_tools_manage_service.py @@ -201,26 +201,29 @@ class BuiltinToolManageService: result: list[UserToolProvider] = [] for provider_controller in provider_controllers: - # convert provider controller to user provider - user_builtin_provider = ToolTransformService.builtin_provider_to_user_provider( - provider_controller=provider_controller, - db_provider=find_provider(provider_controller.identity.name), - decrypt_credentials=True - ) + try: + # convert provider controller to user provider + user_builtin_provider = ToolTransformService.builtin_provider_to_user_provider( + provider_controller=provider_controller, + db_provider=find_provider(provider_controller.identity.name), + decrypt_credentials=True + ) - # add icon - ToolTransformService.repack_provider(user_builtin_provider) + # add icon + ToolTransformService.repack_provider(user_builtin_provider) - tools = provider_controller.get_tools() - for tool in tools: - user_builtin_provider.tools.append(ToolTransformService.tool_to_user_tool( - tenant_id=tenant_id, - tool=tool, - credentials=user_builtin_provider.original_credentials, - labels=ToolLabelManager.get_tool_labels(provider_controller) - )) + tools = provider_controller.get_tools() + for tool in tools: + user_builtin_provider.tools.append(ToolTransformService.tool_to_user_tool( + tenant_id=tenant_id, + tool=tool, + credentials=user_builtin_provider.original_credentials, + labels=ToolLabelManager.get_tool_labels(provider_controller) + )) - result.append(user_builtin_provider) + result.append(user_builtin_provider) + except Exception as e: + raise e return BuiltinToolProviderSort.sort(result) \ No newline at end of file diff --git a/api/services/tools/tools_transform_service.py b/api/services/tools/tools_transform_service.py index ba8c20d79b..5c77732468 100644 --- a/api/services/tools/tools_transform_service.py +++ b/api/services/tools/tools_transform_service.py @@ -4,8 +4,8 @@ from typing import Optional, Union from flask import current_app -from core.model_runtime.entities.common_entities import I18nObject from core.tools.entities.api_entities import UserTool, UserToolProvider +from core.tools.entities.common_entities import I18nObject from core.tools.entities.tool_bundle import ApiToolBundle from core.tools.entities.tool_entities import ( ApiProviderAuthType, @@ -81,11 +81,13 @@ class ToolTransformService: description=I18nObject( en_US=provider_controller.identity.description.en_US, zh_Hans=provider_controller.identity.description.zh_Hans, + pt_BR=provider_controller.identity.description.pt_BR, ), icon=provider_controller.identity.icon, label=I18nObject( en_US=provider_controller.identity.label.en_US, zh_Hans=provider_controller.identity.label.zh_Hans, + pt_BR=provider_controller.identity.label.pt_BR, ), type=ToolProviderType.BUILT_IN, masked_credentials={},