plugin.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import io
  2. import json
  3. from flask import Response, request, send_file
  4. from flask_login import current_user
  5. from flask_restful import Resource, reqparse
  6. from werkzeug.exceptions import Forbidden
  7. from configs import dify_config
  8. from controllers.console import api
  9. from controllers.console.setup import setup_required
  10. from controllers.console.wraps import account_initialization_required
  11. from core.model_runtime.utils.encoders import jsonable_encoder
  12. from core.plugin.entities.plugin_daemon import InstallPluginMessage
  13. from libs.login import login_required
  14. from services.plugin.plugin_service import PluginService
  15. class PluginDebuggingKeyApi(Resource):
  16. @setup_required
  17. @login_required
  18. @account_initialization_required
  19. def get(self):
  20. user = current_user
  21. if not user.is_admin_or_owner:
  22. raise Forbidden()
  23. tenant_id = user.current_tenant_id
  24. return {
  25. "key": PluginService.get_debugging_key(tenant_id),
  26. "host": dify_config.PLUGIN_REMOTE_INSTALL_HOST,
  27. "port": dify_config.PLUGIN_REMOTE_INSTALL_PORT,
  28. }
  29. class PluginListApi(Resource):
  30. @setup_required
  31. @login_required
  32. @account_initialization_required
  33. def get(self):
  34. user = current_user
  35. tenant_id = user.current_tenant_id
  36. plugins = PluginService.list(tenant_id)
  37. return jsonable_encoder({"plugins": plugins})
  38. class PluginIconApi(Resource):
  39. @setup_required
  40. def get(self):
  41. req = reqparse.RequestParser()
  42. req.add_argument("tenant_id", type=str, required=True, location="args")
  43. req.add_argument("filename", type=str, required=True, location="args")
  44. args = req.parse_args()
  45. icon_bytes, mimetype = PluginService.get_asset(args["tenant_id"], args["filename"])
  46. icon_cache_max_age = dify_config.TOOL_ICON_CACHE_MAX_AGE
  47. return send_file(io.BytesIO(icon_bytes), mimetype=mimetype, max_age=icon_cache_max_age)
  48. class PluginInstallCheckUniqueIdentifierApi(Resource):
  49. @setup_required
  50. @login_required
  51. @account_initialization_required
  52. def get(self):
  53. req = reqparse.RequestParser()
  54. req.add_argument("plugin_unique_identifier", type=str, required=True, location="args")
  55. args = req.parse_args()
  56. user = current_user
  57. tenant_id = user.current_tenant_id
  58. return {"installed": PluginService.check_plugin_unique_identifier(tenant_id, args["plugin_unique_identifier"])}
  59. class PluginInstallFromUniqueIdentifierApi(Resource):
  60. @setup_required
  61. @login_required
  62. @account_initialization_required
  63. def post(self):
  64. req = reqparse.RequestParser()
  65. req.add_argument("plugin_unique_identifier", type=str, required=True, location="json")
  66. args = req.parse_args()
  67. user = current_user
  68. if not user.is_admin_or_owner:
  69. raise Forbidden()
  70. tenant_id = user.current_tenant_id
  71. return {"success": PluginService.install_from_unique_identifier(tenant_id, args["plugin_unique_identifier"])}
  72. class PluginInstallFromPkgApi(Resource):
  73. @setup_required
  74. @login_required
  75. @account_initialization_required
  76. def post(self):
  77. user = current_user
  78. if not user.is_admin_or_owner:
  79. raise Forbidden()
  80. tenant_id = user.current_tenant_id
  81. file = request.files["pkg"]
  82. content = file.read()
  83. def generator():
  84. try:
  85. response = PluginService.install_from_local_pkg(tenant_id, content)
  86. for message in response:
  87. yield f"data: {json.dumps(jsonable_encoder(message))}\n\n"
  88. except ValueError as e:
  89. error_message = InstallPluginMessage(event=InstallPluginMessage.Event.Error, data=str(e))
  90. yield f"data: {json.dumps(jsonable_encoder(error_message))}\n\n"
  91. return Response(generator(), mimetype="text/event-stream")
  92. class PluginInstallFromGithubApi(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("repo", type=str, required=True, location="json")
  103. parser.add_argument("version", type=str, required=True, location="json")
  104. parser.add_argument("package", type=str, required=True, location="json")
  105. args = parser.parse_args()
  106. def generator():
  107. try:
  108. response = PluginService.install_from_github_pkg(
  109. tenant_id, args["repo"], args["version"], args["package"]
  110. )
  111. for message in response:
  112. yield f"data: {json.dumps(jsonable_encoder(message))}\n\n"
  113. except ValueError as e:
  114. error_message = InstallPluginMessage(event=InstallPluginMessage.Event.Error, data=str(e))
  115. yield f"data: {json.dumps(jsonable_encoder(error_message))}\n\n"
  116. return Response(generator(), mimetype="text/event-stream")
  117. class PluginInstallFromMarketplaceApi(Resource):
  118. @setup_required
  119. @login_required
  120. @account_initialization_required
  121. def post(self):
  122. user = current_user
  123. if not user.is_admin_or_owner:
  124. raise Forbidden()
  125. tenant_id = user.current_tenant_id
  126. parser = reqparse.RequestParser()
  127. parser.add_argument("plugin_unique_identifier", type=str, required=True, location="json")
  128. args = parser.parse_args()
  129. def generator():
  130. try:
  131. response = PluginService.install_from_marketplace_pkg(tenant_id, args["plugin_unique_identifier"])
  132. for message in response:
  133. yield f"data: {json.dumps(jsonable_encoder(message))}\n\n"
  134. except ValueError as e:
  135. error_message = InstallPluginMessage(event=InstallPluginMessage.Event.Error, data=str(e))
  136. yield f"data: {json.dumps(jsonable_encoder(error_message))}\n\n"
  137. return Response(generator(), mimetype="text/event-stream")
  138. class PluginUninstallApi(Resource):
  139. @setup_required
  140. @login_required
  141. @account_initialization_required
  142. def post(self):
  143. req = reqparse.RequestParser()
  144. req.add_argument("plugin_installation_id", type=str, required=True, location="json")
  145. args = req.parse_args()
  146. user = current_user
  147. if not user.is_admin_or_owner:
  148. raise Forbidden()
  149. tenant_id = user.current_tenant_id
  150. return {"success": PluginService.uninstall(tenant_id, args["plugin_installation_id"])}
  151. api.add_resource(PluginDebuggingKeyApi, "/workspaces/current/plugin/debugging-key")
  152. api.add_resource(PluginListApi, "/workspaces/current/plugin/list")
  153. api.add_resource(PluginIconApi, "/workspaces/current/plugin/icon")
  154. api.add_resource(PluginInstallCheckUniqueIdentifierApi, "/workspaces/current/plugin/install/check_unique_identifier")
  155. api.add_resource(PluginInstallFromUniqueIdentifierApi, "/workspaces/current/plugin/install/from_unique_identifier")
  156. api.add_resource(PluginInstallFromPkgApi, "/workspaces/current/plugin/install/from_pkg")
  157. api.add_resource(PluginInstallFromGithubApi, "/workspaces/current/plugin/install/from_github")
  158. api.add_resource(PluginInstallFromMarketplaceApi, "/workspaces/current/plugin/install/from_marketplace")
  159. api.add_resource(PluginUninstallApi, "/workspaces/current/plugin/uninstall")