Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

tools_transform_service.py 12KB

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