tools_transform_service.py 11 KB

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