plugin.py 9.7 KB

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