tools_transform_service.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import json
  2. import logging
  3. from typing import Optional, Union, cast
  4. from configs import dify_config
  5. from core.tools.entities.api_entities import UserTool, UserToolProvider
  6. from core.tools.entities.common_entities import I18nObject
  7. from core.tools.entities.tool_bundle import ApiToolBundle
  8. from core.tools.entities.tool_entities import (
  9. ApiProviderAuthType,
  10. ToolParameter,
  11. ToolProviderCredentials,
  12. ToolProviderType,
  13. )
  14. from core.tools.provider.api_tool_provider import ApiToolProviderController
  15. from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
  16. from core.tools.provider.workflow_tool_provider import WorkflowToolProviderController
  17. from core.tools.tool.tool import Tool
  18. from core.tools.tool.workflow_tool import WorkflowTool
  19. from core.tools.utils.configuration import ToolConfigurationManager
  20. from models.tools import ApiToolProvider, BuiltinToolProvider, WorkflowToolProvider
  21. logger = logging.getLogger(__name__)
  22. class ToolTransformService:
  23. @staticmethod
  24. def get_tool_provider_icon_url(provider_type: str, provider_name: str, icon: str) -> Union[str, dict]:
  25. """
  26. get tool provider icon url
  27. """
  28. url_prefix = dify_config.CONSOLE_API_URL + "/console/api/workspaces/current/tool-provider/"
  29. if provider_type == ToolProviderType.BUILT_IN.value:
  30. return url_prefix + "builtin/" + provider_name + "/icon"
  31. elif provider_type in {ToolProviderType.API.value, ToolProviderType.WORKFLOW.value}:
  32. try:
  33. return cast(dict, json.loads(icon))
  34. except:
  35. return {"background": "#252525", "content": "\ud83d\ude01"}
  36. return ""
  37. @staticmethod
  38. def repack_provider(provider: Union[dict, UserToolProvider]):
  39. """
  40. repack provider
  41. :param provider: the provider dict
  42. """
  43. if isinstance(provider, dict) and "icon" in provider:
  44. provider["icon"] = ToolTransformService.get_tool_provider_icon_url(
  45. provider_type=provider["type"], provider_name=provider["name"], icon=provider["icon"]
  46. )
  47. elif isinstance(provider, UserToolProvider):
  48. provider.icon = cast(
  49. str,
  50. ToolTransformService.get_tool_provider_icon_url(
  51. provider_type=provider.type.value, provider_name=provider.name, icon=provider.icon
  52. ),
  53. )
  54. @staticmethod
  55. def builtin_provider_to_user_provider(
  56. provider_controller: BuiltinToolProviderController,
  57. db_provider: Optional[BuiltinToolProvider],
  58. decrypt_credentials: bool = True,
  59. ) -> UserToolProvider:
  60. """
  61. convert provider controller to user provider
  62. """
  63. if provider_controller.identity is None:
  64. raise ValueError("provider identity is None")
  65. result = UserToolProvider(
  66. id=provider_controller.identity.name,
  67. author=provider_controller.identity.author,
  68. name=provider_controller.identity.name,
  69. description=I18nObject(
  70. en_US=provider_controller.identity.description.en_US,
  71. zh_Hans=provider_controller.identity.description.zh_Hans,
  72. pt_BR=provider_controller.identity.description.pt_BR,
  73. ja_JP=provider_controller.identity.description.ja_JP,
  74. ),
  75. icon=provider_controller.identity.icon,
  76. label=I18nObject(
  77. en_US=provider_controller.identity.label.en_US,
  78. zh_Hans=provider_controller.identity.label.zh_Hans,
  79. pt_BR=provider_controller.identity.label.pt_BR,
  80. ja_JP=provider_controller.identity.label.ja_JP,
  81. ),
  82. type=ToolProviderType.BUILT_IN,
  83. masked_credentials={},
  84. is_team_authorization=False,
  85. tools=[],
  86. labels=provider_controller.tool_labels,
  87. )
  88. # get credentials schema
  89. schema = provider_controller.get_credentials_schema()
  90. for name, value in schema.items():
  91. assert result.masked_credentials is not None, "masked credentials is None"
  92. result.masked_credentials[name] = ToolProviderCredentials.CredentialsType.default(str(value.type))
  93. # check if the provider need credentials
  94. if not provider_controller.need_credentials:
  95. result.is_team_authorization = True
  96. result.allow_delete = False
  97. elif db_provider:
  98. result.is_team_authorization = True
  99. if decrypt_credentials:
  100. credentials = db_provider.credentials
  101. # init tool configuration
  102. tool_configuration = ToolConfigurationManager(
  103. tenant_id=db_provider.tenant_id, provider_controller=provider_controller
  104. )
  105. # decrypt the credentials and mask the credentials
  106. decrypted_credentials = tool_configuration.decrypt_tool_credentials(credentials=credentials)
  107. masked_credentials = tool_configuration.mask_tool_credentials(credentials=decrypted_credentials)
  108. result.masked_credentials = masked_credentials
  109. result.original_credentials = decrypted_credentials
  110. return result
  111. @staticmethod
  112. def api_provider_to_controller(
  113. db_provider: ApiToolProvider,
  114. ) -> ApiToolProviderController:
  115. """
  116. convert provider controller to user provider
  117. """
  118. # package tool provider controller
  119. controller = ApiToolProviderController.from_db(
  120. db_provider=db_provider,
  121. auth_type=ApiProviderAuthType.API_KEY
  122. if db_provider.credentials["auth_type"] == "api_key"
  123. else ApiProviderAuthType.NONE,
  124. )
  125. return controller
  126. @staticmethod
  127. def workflow_provider_to_controller(db_provider: WorkflowToolProvider) -> WorkflowToolProviderController:
  128. """
  129. convert provider controller to provider
  130. """
  131. return WorkflowToolProviderController.from_db(db_provider)
  132. @staticmethod
  133. def workflow_provider_to_user_provider(
  134. provider_controller: WorkflowToolProviderController, labels: Optional[list[str]] = None
  135. ):
  136. """
  137. convert provider controller to user provider
  138. """
  139. if provider_controller.identity is None:
  140. raise ValueError("provider identity is None")
  141. return UserToolProvider(
  142. id=provider_controller.provider_id,
  143. author=provider_controller.identity.author,
  144. name=provider_controller.identity.name,
  145. description=I18nObject(
  146. en_US=provider_controller.identity.description.en_US,
  147. zh_Hans=provider_controller.identity.description.zh_Hans,
  148. ),
  149. icon=provider_controller.identity.icon,
  150. label=I18nObject(
  151. en_US=provider_controller.identity.label.en_US,
  152. zh_Hans=provider_controller.identity.label.zh_Hans,
  153. ),
  154. type=ToolProviderType.WORKFLOW,
  155. masked_credentials={},
  156. is_team_authorization=True,
  157. tools=[],
  158. labels=labels or [],
  159. )
  160. @staticmethod
  161. def api_provider_to_user_provider(
  162. provider_controller: ApiToolProviderController,
  163. db_provider: ApiToolProvider,
  164. decrypt_credentials: bool = True,
  165. labels: Optional[list[str]] = None,
  166. ) -> UserToolProvider:
  167. """
  168. convert provider controller to user provider
  169. """
  170. username = "Anonymous"
  171. if db_provider.user is None:
  172. raise ValueError(f"user is None for api provider {db_provider.id}")
  173. try:
  174. username = db_provider.user.name
  175. except Exception as e:
  176. logger.exception(f"failed to get user name for api provider {db_provider.id}")
  177. # add provider into providers
  178. credentials = db_provider.credentials
  179. result = UserToolProvider(
  180. id=db_provider.id,
  181. author=username,
  182. name=db_provider.name,
  183. description=I18nObject(
  184. en_US=db_provider.description,
  185. zh_Hans=db_provider.description,
  186. ),
  187. icon=db_provider.icon,
  188. label=I18nObject(
  189. en_US=db_provider.name,
  190. zh_Hans=db_provider.name,
  191. ),
  192. type=ToolProviderType.API,
  193. masked_credentials={},
  194. is_team_authorization=True,
  195. tools=[],
  196. labels=labels or [],
  197. )
  198. if decrypt_credentials:
  199. # init tool configuration
  200. tool_configuration = ToolConfigurationManager(
  201. tenant_id=db_provider.tenant_id, provider_controller=provider_controller
  202. )
  203. # decrypt the credentials and mask the credentials
  204. decrypted_credentials = tool_configuration.decrypt_tool_credentials(credentials=credentials)
  205. masked_credentials = tool_configuration.mask_tool_credentials(credentials=decrypted_credentials)
  206. result.masked_credentials = masked_credentials
  207. return result
  208. @staticmethod
  209. def tool_to_user_tool(
  210. tool: Union[ApiToolBundle, WorkflowTool, Tool],
  211. credentials: Optional[dict] = None,
  212. tenant_id: Optional[str] = None,
  213. labels: Optional[list[str]] = None,
  214. ) -> UserTool:
  215. """
  216. convert tool to user tool
  217. """
  218. if isinstance(tool, Tool):
  219. # fork tool runtime
  220. tool = tool.fork_tool_runtime(
  221. runtime={
  222. "credentials": credentials,
  223. "tenant_id": tenant_id,
  224. }
  225. )
  226. # get tool parameters
  227. parameters = tool.parameters or []
  228. # get tool runtime parameters
  229. runtime_parameters = tool.get_runtime_parameters()
  230. # override parameters
  231. current_parameters = parameters.copy()
  232. for runtime_parameter in runtime_parameters:
  233. found = False
  234. for index, parameter in enumerate(current_parameters):
  235. if parameter.name == runtime_parameter.name and parameter.form == runtime_parameter.form:
  236. current_parameters[index] = runtime_parameter
  237. found = True
  238. break
  239. if not found and runtime_parameter.form == ToolParameter.ToolParameterForm.FORM:
  240. current_parameters.append(runtime_parameter)
  241. if tool.identity is None:
  242. raise ValueError("tool identity is None")
  243. return UserTool(
  244. author=tool.identity.author,
  245. name=tool.identity.name,
  246. label=tool.identity.label,
  247. description=tool.description.human if tool.description else "", # type: ignore
  248. parameters=current_parameters,
  249. labels=labels,
  250. )
  251. if isinstance(tool, ApiToolBundle):
  252. return UserTool(
  253. author=tool.author,
  254. name=tool.operation_id or "",
  255. label=I18nObject(en_US=tool.operation_id or "", zh_Hans=tool.operation_id or ""),
  256. description=I18nObject(en_US=tool.summary or "", zh_Hans=tool.summary or ""),
  257. parameters=tool.parameters,
  258. labels=labels,
  259. )