tools_transform_service.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import json
  2. import logging
  3. from typing import Optional, Union
  4. from configs import dify_config
  5. from core.tools.__base.tool import Tool
  6. from core.tools.__base.tool_runtime import ToolRuntime
  7. from core.tools.builtin_tool.provider import BuiltinToolProviderController
  8. from core.tools.custom_tool.provider import ApiToolProviderController
  9. from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity
  10. from core.tools.entities.common_entities import I18nObject
  11. from core.tools.entities.tool_bundle import ApiToolBundle
  12. from core.tools.entities.tool_entities import (
  13. ApiProviderAuthType,
  14. ToolParameter,
  15. ToolProviderType,
  16. )
  17. from core.tools.plugin_tool.provider import PluginToolProviderController
  18. from core.tools.utils.configuration import ProviderConfigEncrypter
  19. from core.tools.workflow_as_tool.provider import WorkflowToolProviderController
  20. from core.tools.workflow_as_tool.tool import WorkflowTool
  21. from models.tools import ApiToolProvider, BuiltinToolProvider, WorkflowToolProvider
  22. logger = logging.getLogger(__name__)
  23. class ToolTransformService:
  24. @classmethod
  25. def get_tool_provider_icon_url(cls, provider_type: str, provider_name: str, icon: str | dict) -> Union[str, dict]:
  26. """
  27. get tool provider icon url
  28. """
  29. url_prefix = dify_config.CONSOLE_API_URL + "/console/api/workspaces/current/tool-provider/"
  30. if provider_type == ToolProviderType.BUILT_IN.value:
  31. return url_prefix + "builtin/" + provider_name + "/icon"
  32. elif provider_type in {ToolProviderType.API.value, ToolProviderType.WORKFLOW.value}:
  33. try:
  34. if isinstance(icon, str):
  35. return json.loads(icon)
  36. return icon
  37. except:
  38. return {"background": "#252525", "content": "\ud83d\ude01"}
  39. return ""
  40. @staticmethod
  41. def repack_provider(provider: Union[dict, ToolProviderApiEntity]):
  42. """
  43. repack provider
  44. :param provider: the provider dict
  45. """
  46. if isinstance(provider, dict) and "icon" in provider:
  47. provider["icon"] = ToolTransformService.get_tool_provider_icon_url(
  48. provider_type=provider["type"], provider_name=provider["name"], icon=provider["icon"]
  49. )
  50. elif isinstance(provider, ToolProviderApiEntity):
  51. provider.icon = ToolTransformService.get_tool_provider_icon_url(
  52. provider_type=provider.type.value, provider_name=provider.name, icon=provider.icon
  53. )
  54. @classmethod
  55. def builtin_provider_to_user_provider(
  56. cls,
  57. provider_controller: BuiltinToolProviderController | PluginToolProviderController,
  58. db_provider: Optional[BuiltinToolProvider],
  59. decrypt_credentials: bool = True,
  60. ) -> ToolProviderApiEntity:
  61. """
  62. convert provider controller to user provider
  63. """
  64. result = ToolProviderApiEntity(
  65. id=provider_controller.entity.identity.name,
  66. author=provider_controller.entity.identity.author,
  67. name=provider_controller.entity.identity.name,
  68. description=I18nObject(
  69. en_US=provider_controller.entity.identity.description.en_US,
  70. zh_Hans=provider_controller.entity.identity.description.zh_Hans,
  71. pt_BR=provider_controller.entity.identity.description.pt_BR,
  72. ),
  73. icon=provider_controller.entity.identity.icon,
  74. label=I18nObject(
  75. en_US=provider_controller.entity.identity.label.en_US,
  76. zh_Hans=provider_controller.entity.identity.label.zh_Hans,
  77. pt_BR=provider_controller.entity.identity.label.pt_BR,
  78. ),
  79. type=ToolProviderType.BUILT_IN,
  80. masked_credentials={},
  81. is_team_authorization=False,
  82. tools=[],
  83. labels=provider_controller.tool_labels,
  84. )
  85. # get credentials schema
  86. schema = provider_controller.get_credentials_schema()
  87. for name, value in schema.items():
  88. if result.masked_credentials:
  89. result.masked_credentials[name] = ""
  90. # check if the provider need credentials
  91. if not provider_controller.need_credentials:
  92. result.is_team_authorization = True
  93. result.allow_delete = False
  94. elif db_provider:
  95. result.is_team_authorization = True
  96. if decrypt_credentials:
  97. credentials = db_provider.credentials
  98. # init tool configuration
  99. tool_configuration = ProviderConfigEncrypter(
  100. tenant_id=db_provider.tenant_id,
  101. config=provider_controller.get_credentials_schema(),
  102. provider_type=provider_controller.provider_type.value,
  103. provider_identity=provider_controller.entity.identity.name,
  104. )
  105. # decrypt the credentials and mask the credentials
  106. decrypted_credentials = tool_configuration.decrypt(data=credentials)
  107. masked_credentials = tool_configuration.mask_tool_credentials(data=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: list[str] | None = None
  135. ):
  136. """
  137. convert provider controller to user provider
  138. """
  139. return ToolProviderApiEntity(
  140. id=provider_controller.provider_id,
  141. author=provider_controller.entity.identity.author,
  142. name=provider_controller.entity.identity.name,
  143. description=I18nObject(
  144. en_US=provider_controller.entity.identity.description.en_US,
  145. zh_Hans=provider_controller.entity.identity.description.zh_Hans,
  146. ),
  147. icon=provider_controller.entity.identity.icon,
  148. label=I18nObject(
  149. en_US=provider_controller.entity.identity.label.en_US,
  150. zh_Hans=provider_controller.entity.identity.label.zh_Hans,
  151. ),
  152. type=ToolProviderType.WORKFLOW,
  153. masked_credentials={},
  154. is_team_authorization=True,
  155. tools=[],
  156. labels=labels or [],
  157. )
  158. @classmethod
  159. def api_provider_to_user_provider(
  160. cls,
  161. provider_controller: ApiToolProviderController,
  162. db_provider: ApiToolProvider,
  163. decrypt_credentials: bool = True,
  164. labels: list[str] | None = None,
  165. ) -> ToolProviderApiEntity:
  166. """
  167. convert provider controller to user provider
  168. """
  169. username = "Anonymous"
  170. try:
  171. user = db_provider.user
  172. if not user:
  173. raise ValueError("user not found")
  174. username = user.name
  175. except Exception as e:
  176. logger.error(f"failed to get user name for api provider {db_provider.id}: {str(e)}")
  177. # add provider into providers
  178. credentials = db_provider.credentials
  179. result = ToolProviderApiEntity(
  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 = ProviderConfigEncrypter(
  201. tenant_id=db_provider.tenant_id,
  202. config=provider_controller.get_credentials_schema(),
  203. provider_type=provider_controller.provider_type.value,
  204. provider_identity=provider_controller.entity.identity.name,
  205. )
  206. # decrypt the credentials and mask the credentials
  207. decrypted_credentials = tool_configuration.decrypt(data=credentials)
  208. masked_credentials = tool_configuration.mask_tool_credentials(data=decrypted_credentials)
  209. result.masked_credentials = masked_credentials
  210. return result
  211. @staticmethod
  212. def tool_to_user_tool(
  213. tool: Union[ApiToolBundle, WorkflowTool, Tool],
  214. tenant_id: str,
  215. credentials: dict | None = None,
  216. labels: list[str] | None = None,
  217. ) -> ToolApiEntity:
  218. """
  219. convert tool to user tool
  220. """
  221. if isinstance(tool, Tool):
  222. # fork tool runtime
  223. tool = tool.fork_tool_runtime(
  224. runtime=ToolRuntime(
  225. credentials=credentials or {},
  226. tenant_id=tenant_id,
  227. )
  228. )
  229. # get tool parameters
  230. parameters = tool.entity.parameters or []
  231. # get tool runtime parameters
  232. runtime_parameters = tool.get_runtime_parameters() or []
  233. # override parameters
  234. current_parameters = parameters.copy()
  235. for runtime_parameter in runtime_parameters:
  236. found = False
  237. for index, parameter in enumerate(current_parameters):
  238. if parameter.name == runtime_parameter.name and parameter.form == runtime_parameter.form:
  239. current_parameters[index] = runtime_parameter
  240. found = True
  241. break
  242. if not found and runtime_parameter.form == ToolParameter.ToolParameterForm.FORM:
  243. current_parameters.append(runtime_parameter)
  244. return ToolApiEntity(
  245. author=tool.entity.identity.author,
  246. name=tool.entity.identity.name,
  247. label=tool.entity.identity.label,
  248. description=tool.entity.description.human if tool.entity.description else I18nObject(en_US=""),
  249. parameters=current_parameters,
  250. labels=labels or [],
  251. )
  252. if isinstance(tool, ApiToolBundle):
  253. return ToolApiEntity(
  254. author=tool.author,
  255. name=tool.operation_id,
  256. label=I18nObject(en_US=tool.operation_id, zh_Hans=tool.operation_id),
  257. description=I18nObject(en_US=tool.summary or "", zh_Hans=tool.summary or ""),
  258. parameters=tool.parameters,
  259. labels=labels or [],
  260. )