plugin.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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 {"plugin_unique_identifier": 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 {
  74. "plugin_unique_identifier": response,
  75. }
  76. class PluginUploadFromGithubApi(Resource):
  77. @setup_required
  78. @login_required
  79. @account_initialization_required
  80. def post(self):
  81. user = current_user
  82. if not user.is_admin_or_owner:
  83. raise Forbidden()
  84. tenant_id = user.current_tenant_id
  85. parser = reqparse.RequestParser()
  86. parser.add_argument("repo", type=str, required=True, location="json")
  87. parser.add_argument("version", type=str, required=True, location="json")
  88. parser.add_argument("package", type=str, required=True, location="json")
  89. args = parser.parse_args()
  90. response = PluginService.upload_pkg_from_github(tenant_id, args["repo"], args["version"], args["package"])
  91. return {
  92. "plugin_unique_identifier": response,
  93. }
  94. class PluginInstallFromPkgApi(Resource):
  95. @setup_required
  96. @login_required
  97. @account_initialization_required
  98. def post(self):
  99. user = current_user
  100. if not user.is_admin_or_owner:
  101. raise Forbidden()
  102. tenant_id = user.current_tenant_id
  103. parser = reqparse.RequestParser()
  104. parser.add_argument("plugin_unique_identifiers", type=list, required=True, location="json")
  105. args = parser.parse_args()
  106. # check if all plugin_unique_identifiers are valid string
  107. for plugin_unique_identifier in args["plugin_unique_identifiers"]:
  108. if not isinstance(plugin_unique_identifier, str):
  109. raise ValueError("Invalid plugin unique identifier")
  110. response = PluginService.install_from_local_pkg(tenant_id, args["plugin_unique_identifiers"])
  111. return response.model_dump()
  112. class PluginInstallFromGithubApi(Resource):
  113. @setup_required
  114. @login_required
  115. @account_initialization_required
  116. def post(self):
  117. user = current_user
  118. if not user.is_admin_or_owner:
  119. raise Forbidden()
  120. tenant_id = user.current_tenant_id
  121. parser = reqparse.RequestParser()
  122. parser.add_argument("repo", type=str, required=True, location="json")
  123. parser.add_argument("version", type=str, required=True, location="json")
  124. parser.add_argument("package", type=str, required=True, location="json")
  125. parser.add_argument("plugin_unique_identifier", type=str, required=True, location="json")
  126. args = parser.parse_args()
  127. response = PluginService.install_from_github(
  128. tenant_id,
  129. args["plugin_unique_identifier"],
  130. args["repo"],
  131. args["version"],
  132. args["package"],
  133. )
  134. return response.model_dump()
  135. class PluginInstallFromMarketplaceApi(Resource):
  136. @setup_required
  137. @login_required
  138. @account_initialization_required
  139. def post(self):
  140. user = current_user
  141. if not user.is_admin_or_owner:
  142. raise Forbidden()
  143. tenant_id = user.current_tenant_id
  144. parser = reqparse.RequestParser()
  145. parser.add_argument("plugin_unique_identifiers", type=list, required=True, location="json")
  146. args = parser.parse_args()
  147. # check if all plugin_unique_identifiers are valid string
  148. for plugin_unique_identifier in args["plugin_unique_identifiers"]:
  149. if not isinstance(plugin_unique_identifier, str):
  150. raise ValueError("Invalid plugin unique identifier")
  151. response = PluginService.install_from_marketplace_pkg(tenant_id, args["plugin_unique_identifiers"])
  152. return response.model_dump()
  153. class PluginFetchManifestApi(Resource):
  154. @setup_required
  155. @login_required
  156. @account_initialization_required
  157. def get(self):
  158. user = current_user
  159. parser = reqparse.RequestParser()
  160. parser.add_argument("plugin_unique_identifier", type=str, required=True, location="args")
  161. args = parser.parse_args()
  162. tenant_id = user.current_tenant_id
  163. return jsonable_encoder(
  164. {"manifest": PluginService.fetch_plugin_manifest(tenant_id, args["plugin_unique_identifier"]).model_dump()}
  165. )
  166. class PluginFetchInstallTasksApi(Resource):
  167. @setup_required
  168. @login_required
  169. @account_initialization_required
  170. def get(self):
  171. user = current_user
  172. if not user.is_admin_or_owner:
  173. raise Forbidden()
  174. tenant_id = user.current_tenant_id
  175. parser = reqparse.RequestParser()
  176. parser.add_argument("page", type=int, required=True, location="args")
  177. parser.add_argument("page_size", type=int, required=True, location="args")
  178. args = parser.parse_args()
  179. return jsonable_encoder(
  180. {"tasks": PluginService.fetch_install_tasks(tenant_id, args["page"], args["page_size"])}
  181. )
  182. class PluginFetchInstallTaskApi(Resource):
  183. @setup_required
  184. @login_required
  185. @account_initialization_required
  186. def get(self, task_id: str):
  187. user = current_user
  188. if not user.is_admin_or_owner:
  189. raise Forbidden()
  190. tenant_id = user.current_tenant_id
  191. return jsonable_encoder({"task": PluginService.fetch_install_task(tenant_id, task_id)})
  192. class PluginDeleteInstallTaskApi(Resource):
  193. @setup_required
  194. @login_required
  195. @account_initialization_required
  196. def post(self, task_id: str):
  197. user = current_user
  198. if not user.is_admin_or_owner:
  199. raise Forbidden()
  200. tenant_id = user.current_tenant_id
  201. return {"success": PluginService.delete_install_task(tenant_id, task_id)}
  202. class PluginUninstallApi(Resource):
  203. @setup_required
  204. @login_required
  205. @account_initialization_required
  206. def post(self):
  207. req = reqparse.RequestParser()
  208. req.add_argument("plugin_installation_id", type=str, required=True, location="json")
  209. args = req.parse_args()
  210. user = current_user
  211. if not user.is_admin_or_owner:
  212. raise Forbidden()
  213. tenant_id = user.current_tenant_id
  214. return {"success": PluginService.uninstall(tenant_id, args["plugin_installation_id"])}
  215. api.add_resource(PluginDebuggingKeyApi, "/workspaces/current/plugin/debugging-key")
  216. api.add_resource(PluginListApi, "/workspaces/current/plugin/list")
  217. api.add_resource(PluginIconApi, "/workspaces/current/plugin/icon")
  218. api.add_resource(PluginUploadFromPkgApi, "/workspaces/current/plugin/upload/pkg")
  219. api.add_resource(PluginUploadFromGithubApi, "/workspaces/current/plugin/upload/github")
  220. api.add_resource(PluginInstallFromPkgApi, "/workspaces/current/plugin/install/pkg")
  221. api.add_resource(PluginInstallFromGithubApi, "/workspaces/current/plugin/install/github")
  222. api.add_resource(PluginInstallFromMarketplaceApi, "/workspaces/current/plugin/install/marketplace")
  223. api.add_resource(PluginFetchManifestApi, "/workspaces/current/plugin/fetch-manifest")
  224. api.add_resource(PluginFetchInstallTasksApi, "/workspaces/current/plugin/tasks")
  225. api.add_resource(PluginFetchInstallTaskApi, "/workspaces/current/plugin/tasks/<task_id>")
  226. api.add_resource(PluginDeleteInstallTaskApi, "/workspaces/current/plugin/tasks/<task_id>/delete")
  227. api.add_resource(PluginUninstallApi, "/workspaces/current/plugin/uninstall")