plugin.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import io
  2. from flask import request, send_file
  3. from flask_login import current_user
  4. from flask_restful import Resource, reqparse
  5. from werkzeug.exceptions import Forbidden
  6. from configs import dify_config
  7. from controllers.console import api
  8. from controllers.console.setup import setup_required
  9. from controllers.console.wraps import account_initialization_required
  10. from core.model_runtime.utils.encoders import jsonable_encoder
  11. from libs.login import login_required
  12. from services.plugin.plugin_service import PluginService
  13. class PluginDebuggingKeyApi(Resource):
  14. @setup_required
  15. @login_required
  16. @account_initialization_required
  17. def get(self):
  18. user = current_user
  19. if not user.is_admin_or_owner:
  20. raise Forbidden()
  21. tenant_id = user.current_tenant_id
  22. return {
  23. "key": PluginService.get_debugging_key(tenant_id),
  24. "host": dify_config.PLUGIN_REMOTE_INSTALL_HOST,
  25. "port": dify_config.PLUGIN_REMOTE_INSTALL_PORT,
  26. }
  27. class PluginListApi(Resource):
  28. @setup_required
  29. @login_required
  30. @account_initialization_required
  31. def get(self):
  32. user = current_user
  33. tenant_id = user.current_tenant_id
  34. plugins = PluginService.list(tenant_id)
  35. return jsonable_encoder({"plugins": plugins})
  36. class PluginIconApi(Resource):
  37. @setup_required
  38. def get(self):
  39. req = reqparse.RequestParser()
  40. req.add_argument("tenant_id", type=str, required=True, location="args")
  41. req.add_argument("filename", type=str, required=True, location="args")
  42. args = req.parse_args()
  43. icon_bytes, mimetype = PluginService.get_asset(args["tenant_id"], args["filename"])
  44. icon_cache_max_age = dify_config.TOOL_ICON_CACHE_MAX_AGE
  45. return send_file(io.BytesIO(icon_bytes), mimetype=mimetype, max_age=icon_cache_max_age)
  46. class PluginUploadPkgApi(Resource):
  47. @setup_required
  48. @login_required
  49. @account_initialization_required
  50. def post(self):
  51. user = current_user
  52. if not user.is_admin_or_owner:
  53. raise Forbidden()
  54. tenant_id = user.current_tenant_id
  55. file = request.files["pkg"]
  56. content = file.read()
  57. return jsonable_encoder(PluginService.upload_pkg(tenant_id, content))
  58. class PluginUploadFromPkgApi(Resource):
  59. @setup_required
  60. @login_required
  61. @account_initialization_required
  62. def post(self):
  63. user = current_user
  64. if not user.is_admin_or_owner:
  65. raise Forbidden()
  66. tenant_id = user.current_tenant_id
  67. file = request.files["pkg"]
  68. # check file size
  69. if file.content_length > dify_config.PLUGIN_MAX_PACKAGE_SIZE:
  70. raise ValueError("File size exceeds the maximum allowed size")
  71. content = file.read()
  72. response = PluginService.upload_pkg(tenant_id, content)
  73. return jsonable_encoder(response)
  74. class PluginUploadFromGithubApi(Resource):
  75. @setup_required
  76. @login_required
  77. @account_initialization_required
  78. def post(self):
  79. user = current_user
  80. if not user.is_admin_or_owner:
  81. raise Forbidden()
  82. tenant_id = user.current_tenant_id
  83. parser = reqparse.RequestParser()
  84. parser.add_argument("repo", type=str, required=True, location="json")
  85. parser.add_argument("version", type=str, required=True, location="json")
  86. parser.add_argument("package", type=str, required=True, location="json")
  87. args = parser.parse_args()
  88. response = PluginService.upload_pkg_from_github(tenant_id, args["repo"], args["version"], args["package"])
  89. return {
  90. "plugin_unique_identifier": response,
  91. }
  92. class PluginInstallFromPkgApi(Resource):
  93. @setup_required
  94. @login_required
  95. @account_initialization_required
  96. def post(self):
  97. user = current_user
  98. if not user.is_admin_or_owner:
  99. raise Forbidden()
  100. tenant_id = user.current_tenant_id
  101. parser = reqparse.RequestParser()
  102. parser.add_argument("plugin_unique_identifiers", type=list, required=True, location="json")
  103. args = parser.parse_args()
  104. # check if all plugin_unique_identifiers are valid string
  105. for plugin_unique_identifier in args["plugin_unique_identifiers"]:
  106. if not isinstance(plugin_unique_identifier, str):
  107. raise ValueError("Invalid plugin unique identifier")
  108. response = PluginService.install_from_local_pkg(tenant_id, args["plugin_unique_identifiers"])
  109. return jsonable_encoder(response)
  110. class PluginInstallFromGithubApi(Resource):
  111. @setup_required
  112. @login_required
  113. @account_initialization_required
  114. def post(self):
  115. user = current_user
  116. if not user.is_admin_or_owner:
  117. raise Forbidden()
  118. tenant_id = user.current_tenant_id
  119. parser = reqparse.RequestParser()
  120. parser.add_argument("repo", type=str, required=True, location="json")
  121. parser.add_argument("version", type=str, required=True, location="json")
  122. parser.add_argument("package", type=str, required=True, location="json")
  123. parser.add_argument("plugin_unique_identifier", type=str, required=True, location="json")
  124. args = parser.parse_args()
  125. response = PluginService.install_from_github(
  126. tenant_id,
  127. args["plugin_unique_identifier"],
  128. args["repo"],
  129. args["version"],
  130. args["package"],
  131. )
  132. return jsonable_encoder(response)
  133. class PluginInstallFromMarketplaceApi(Resource):
  134. @setup_required
  135. @login_required
  136. @account_initialization_required
  137. def post(self):
  138. user = current_user
  139. if not user.is_admin_or_owner:
  140. raise Forbidden()
  141. tenant_id = user.current_tenant_id
  142. parser = reqparse.RequestParser()
  143. parser.add_argument("plugin_unique_identifiers", type=list, required=True, location="json")
  144. args = parser.parse_args()
  145. # check if all plugin_unique_identifiers are valid string
  146. for plugin_unique_identifier in args["plugin_unique_identifiers"]:
  147. if not isinstance(plugin_unique_identifier, str):
  148. raise ValueError("Invalid plugin unique identifier")
  149. response = PluginService.install_from_marketplace_pkg(tenant_id, args["plugin_unique_identifiers"])
  150. return jsonable_encoder(response)
  151. class PluginFetchManifestApi(Resource):
  152. @setup_required
  153. @login_required
  154. @account_initialization_required
  155. def get(self):
  156. user = current_user
  157. parser = reqparse.RequestParser()
  158. parser.add_argument("plugin_unique_identifier", type=str, required=True, location="args")
  159. args = parser.parse_args()
  160. tenant_id = user.current_tenant_id
  161. return jsonable_encoder(
  162. {"manifest": PluginService.fetch_plugin_manifest(tenant_id, args["plugin_unique_identifier"]).model_dump()}
  163. )
  164. class PluginFetchInstallTasksApi(Resource):
  165. @setup_required
  166. @login_required
  167. @account_initialization_required
  168. def get(self):
  169. user = current_user
  170. if not user.is_admin_or_owner:
  171. raise Forbidden()
  172. tenant_id = user.current_tenant_id
  173. parser = reqparse.RequestParser()
  174. parser.add_argument("page", type=int, required=True, location="args")
  175. parser.add_argument("page_size", type=int, required=True, location="args")
  176. args = parser.parse_args()
  177. return jsonable_encoder(
  178. {"tasks": PluginService.fetch_install_tasks(tenant_id, args["page"], args["page_size"])}
  179. )
  180. class PluginFetchInstallTaskApi(Resource):
  181. @setup_required
  182. @login_required
  183. @account_initialization_required
  184. def get(self, task_id: str):
  185. user = current_user
  186. if not user.is_admin_or_owner:
  187. raise Forbidden()
  188. tenant_id = user.current_tenant_id
  189. return jsonable_encoder({"task": PluginService.fetch_install_task(tenant_id, task_id)})
  190. class PluginDeleteInstallTaskApi(Resource):
  191. @setup_required
  192. @login_required
  193. @account_initialization_required
  194. def post(self, task_id: str):
  195. user = current_user
  196. if not user.is_admin_or_owner:
  197. raise Forbidden()
  198. tenant_id = user.current_tenant_id
  199. return {"success": PluginService.delete_install_task(tenant_id, task_id)}
  200. class PluginUninstallApi(Resource):
  201. @setup_required
  202. @login_required
  203. @account_initialization_required
  204. def post(self):
  205. req = reqparse.RequestParser()
  206. req.add_argument("plugin_installation_id", type=str, required=True, location="json")
  207. args = req.parse_args()
  208. user = current_user
  209. if not user.is_admin_or_owner:
  210. raise Forbidden()
  211. tenant_id = user.current_tenant_id
  212. return {"success": PluginService.uninstall(tenant_id, args["plugin_installation_id"])}
  213. api.add_resource(PluginDebuggingKeyApi, "/workspaces/current/plugin/debugging-key")
  214. api.add_resource(PluginListApi, "/workspaces/current/plugin/list")
  215. api.add_resource(PluginIconApi, "/workspaces/current/plugin/icon")
  216. api.add_resource(PluginUploadFromPkgApi, "/workspaces/current/plugin/upload/pkg")
  217. api.add_resource(PluginUploadFromGithubApi, "/workspaces/current/plugin/upload/github")
  218. api.add_resource(PluginInstallFromPkgApi, "/workspaces/current/plugin/install/pkg")
  219. api.add_resource(PluginInstallFromGithubApi, "/workspaces/current/plugin/install/github")
  220. api.add_resource(PluginInstallFromMarketplaceApi, "/workspaces/current/plugin/install/marketplace")
  221. api.add_resource(PluginFetchManifestApi, "/workspaces/current/plugin/fetch-manifest")
  222. api.add_resource(PluginFetchInstallTasksApi, "/workspaces/current/plugin/tasks")
  223. api.add_resource(PluginFetchInstallTaskApi, "/workspaces/current/plugin/tasks/<task_id>")
  224. api.add_resource(PluginDeleteInstallTaskApi, "/workspaces/current/plugin/tasks/<task_id>/delete")
  225. api.add_resource(PluginUninstallApi, "/workspaces/current/plugin/uninstall")