tools_transform_service.py 11 KB

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