tool_providers.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. import io
  2. from flask import send_file
  3. from flask_login import current_user # type: ignore
  4. from flask_restful import Resource, reqparse # type: ignore
  5. from sqlalchemy.orm import Session
  6. from werkzeug.exceptions import Forbidden
  7. from configs import dify_config
  8. from controllers.console import api
  9. from controllers.console.wraps import account_initialization_required, enterprise_license_required, setup_required
  10. from core.model_runtime.utils.encoders import jsonable_encoder
  11. from extensions.ext_database import db
  12. from libs.helper import alphanumeric, uuid_value
  13. from libs.login import login_required
  14. from services.tools.api_tools_manage_service import ApiToolManageService
  15. from services.tools.builtin_tools_manage_service import BuiltinToolManageService
  16. from services.tools.tool_labels_service import ToolLabelsService
  17. from services.tools.tools_manage_service import ToolCommonService
  18. from services.tools.workflow_tools_manage_service import WorkflowToolManageService
  19. class ToolProviderListApi(Resource):
  20. @setup_required
  21. @login_required
  22. @account_initialization_required
  23. def get(self):
  24. user = current_user
  25. user_id = user.id
  26. tenant_id = user.current_tenant_id
  27. req = reqparse.RequestParser()
  28. req.add_argument(
  29. "type",
  30. type=str,
  31. choices=["builtin", "model", "api", "workflow"],
  32. required=False,
  33. nullable=True,
  34. location="args",
  35. )
  36. args = req.parse_args()
  37. return ToolCommonService.list_tool_providers(user_id, tenant_id, args.get("type", None))
  38. class ToolBuiltinProviderListToolsApi(Resource):
  39. @setup_required
  40. @login_required
  41. @account_initialization_required
  42. def get(self, provider):
  43. user = current_user
  44. tenant_id = user.current_tenant_id
  45. return jsonable_encoder(
  46. BuiltinToolManageService.list_builtin_tool_provider_tools(
  47. tenant_id,
  48. provider,
  49. )
  50. )
  51. class ToolBuiltinProviderInfoApi(Resource):
  52. @setup_required
  53. @login_required
  54. @account_initialization_required
  55. def get(self, provider):
  56. user = current_user
  57. user_id = user.id
  58. tenant_id = user.current_tenant_id
  59. return jsonable_encoder(BuiltinToolManageService.get_builtin_tool_provider_info(user_id, tenant_id, provider))
  60. class ToolBuiltinProviderDeleteApi(Resource):
  61. @setup_required
  62. @login_required
  63. @account_initialization_required
  64. def post(self, provider):
  65. user = current_user
  66. if not user.is_admin_or_owner:
  67. raise Forbidden()
  68. user_id = user.id
  69. tenant_id = user.current_tenant_id
  70. return BuiltinToolManageService.delete_builtin_tool_provider(
  71. user_id,
  72. tenant_id,
  73. provider,
  74. )
  75. class ToolBuiltinProviderUpdateApi(Resource):
  76. @setup_required
  77. @login_required
  78. @account_initialization_required
  79. def post(self, provider):
  80. user = current_user
  81. if not user.is_admin_or_owner:
  82. raise Forbidden()
  83. user_id = user.id
  84. tenant_id = user.current_tenant_id
  85. parser = reqparse.RequestParser()
  86. parser.add_argument("credentials", type=dict, required=True, nullable=False, location="json")
  87. args = parser.parse_args()
  88. with Session(db.engine) as session:
  89. result = BuiltinToolManageService.update_builtin_tool_provider(
  90. session=session,
  91. user_id=user_id,
  92. tenant_id=tenant_id,
  93. provider_name=provider,
  94. credentials=args["credentials"],
  95. )
  96. session.commit()
  97. return result
  98. class ToolBuiltinProviderGetCredentialsApi(Resource):
  99. @setup_required
  100. @login_required
  101. @account_initialization_required
  102. def get(self, provider):
  103. tenant_id = current_user.current_tenant_id
  104. return BuiltinToolManageService.get_builtin_tool_provider_credentials(
  105. tenant_id=tenant_id,
  106. provider_name=provider,
  107. )
  108. class ToolBuiltinProviderIconApi(Resource):
  109. @setup_required
  110. def get(self, provider):
  111. icon_bytes, mimetype = BuiltinToolManageService.get_builtin_tool_provider_icon(provider)
  112. icon_cache_max_age = dify_config.TOOL_ICON_CACHE_MAX_AGE
  113. return send_file(io.BytesIO(icon_bytes), mimetype=mimetype, max_age=icon_cache_max_age)
  114. class ToolApiProviderAddApi(Resource):
  115. @setup_required
  116. @login_required
  117. @account_initialization_required
  118. def post(self):
  119. user = current_user
  120. if not user.is_admin_or_owner:
  121. raise Forbidden()
  122. user_id = user.id
  123. tenant_id = user.current_tenant_id
  124. parser = reqparse.RequestParser()
  125. parser.add_argument("credentials", type=dict, required=True, nullable=False, location="json")
  126. parser.add_argument("schema_type", type=str, required=True, nullable=False, location="json")
  127. parser.add_argument("schema", type=str, required=True, nullable=False, location="json")
  128. parser.add_argument("provider", type=str, required=True, nullable=False, location="json")
  129. parser.add_argument("icon", type=dict, required=True, nullable=False, location="json")
  130. parser.add_argument("privacy_policy", type=str, required=False, nullable=True, location="json")
  131. parser.add_argument("labels", type=list[str], required=False, nullable=True, location="json", default=[])
  132. parser.add_argument("custom_disclaimer", type=str, required=False, nullable=True, location="json")
  133. args = parser.parse_args()
  134. return ApiToolManageService.create_api_tool_provider(
  135. user_id,
  136. tenant_id,
  137. args["provider"],
  138. args["icon"],
  139. args["credentials"],
  140. args["schema_type"],
  141. args["schema"],
  142. args.get("privacy_policy", ""),
  143. args.get("custom_disclaimer", ""),
  144. args.get("labels", []),
  145. )
  146. class ToolApiProviderGetRemoteSchemaApi(Resource):
  147. @setup_required
  148. @login_required
  149. @account_initialization_required
  150. def get(self):
  151. user = current_user
  152. user_id = user.id
  153. tenant_id = user.current_tenant_id
  154. parser = reqparse.RequestParser()
  155. parser.add_argument("url", type=str, required=True, nullable=False, location="args")
  156. args = parser.parse_args()
  157. return ApiToolManageService.get_api_tool_provider_remote_schema(
  158. user_id,
  159. tenant_id,
  160. args["url"],
  161. )
  162. class ToolApiProviderListToolsApi(Resource):
  163. @setup_required
  164. @login_required
  165. @account_initialization_required
  166. def get(self):
  167. user = current_user
  168. user_id = user.id
  169. tenant_id = user.current_tenant_id
  170. parser = reqparse.RequestParser()
  171. parser.add_argument("provider", type=str, required=True, nullable=False, location="args")
  172. args = parser.parse_args()
  173. return jsonable_encoder(
  174. ApiToolManageService.list_api_tool_provider_tools(
  175. user_id,
  176. tenant_id,
  177. args["provider"],
  178. )
  179. )
  180. class ToolApiProviderUpdateApi(Resource):
  181. @setup_required
  182. @login_required
  183. @account_initialization_required
  184. def post(self):
  185. user = current_user
  186. if not user.is_admin_or_owner:
  187. raise Forbidden()
  188. user_id = user.id
  189. tenant_id = user.current_tenant_id
  190. parser = reqparse.RequestParser()
  191. parser.add_argument("credentials", type=dict, required=True, nullable=False, location="json")
  192. parser.add_argument("schema_type", type=str, required=True, nullable=False, location="json")
  193. parser.add_argument("schema", type=str, required=True, nullable=False, location="json")
  194. parser.add_argument("provider", type=str, required=True, nullable=False, location="json")
  195. parser.add_argument("original_provider", type=str, required=True, nullable=False, location="json")
  196. parser.add_argument("icon", type=dict, required=True, nullable=False, location="json")
  197. parser.add_argument("privacy_policy", type=str, required=True, nullable=True, location="json")
  198. parser.add_argument("labels", type=list[str], required=False, nullable=True, location="json")
  199. parser.add_argument("custom_disclaimer", type=str, required=True, nullable=True, location="json")
  200. args = parser.parse_args()
  201. return ApiToolManageService.update_api_tool_provider(
  202. user_id,
  203. tenant_id,
  204. args["provider"],
  205. args["original_provider"],
  206. args["icon"],
  207. args["credentials"],
  208. args["schema_type"],
  209. args["schema"],
  210. args["privacy_policy"],
  211. args["custom_disclaimer"],
  212. args.get("labels", []),
  213. )
  214. class ToolApiProviderDeleteApi(Resource):
  215. @setup_required
  216. @login_required
  217. @account_initialization_required
  218. def post(self):
  219. user = current_user
  220. if not user.is_admin_or_owner:
  221. raise Forbidden()
  222. user_id = user.id
  223. tenant_id = user.current_tenant_id
  224. parser = reqparse.RequestParser()
  225. parser.add_argument("provider", type=str, required=True, nullable=False, location="json")
  226. args = parser.parse_args()
  227. return ApiToolManageService.delete_api_tool_provider(
  228. user_id,
  229. tenant_id,
  230. args["provider"],
  231. )
  232. class ToolApiProviderGetApi(Resource):
  233. @setup_required
  234. @login_required
  235. @account_initialization_required
  236. def get(self):
  237. user = current_user
  238. user_id = user.id
  239. tenant_id = user.current_tenant_id
  240. parser = reqparse.RequestParser()
  241. parser.add_argument("provider", type=str, required=True, nullable=False, location="args")
  242. args = parser.parse_args()
  243. return ApiToolManageService.get_api_tool_provider(
  244. user_id,
  245. tenant_id,
  246. args["provider"],
  247. )
  248. class ToolBuiltinProviderCredentialsSchemaApi(Resource):
  249. @setup_required
  250. @login_required
  251. @account_initialization_required
  252. def get(self, provider):
  253. user = current_user
  254. tenant_id = user.current_tenant_id
  255. return BuiltinToolManageService.list_builtin_provider_credentials_schema(provider, tenant_id)
  256. class ToolApiProviderSchemaApi(Resource):
  257. @setup_required
  258. @login_required
  259. @account_initialization_required
  260. def post(self):
  261. parser = reqparse.RequestParser()
  262. parser.add_argument("schema", type=str, required=True, nullable=False, location="json")
  263. args = parser.parse_args()
  264. return ApiToolManageService.parser_api_schema(
  265. schema=args["schema"],
  266. )
  267. class ToolApiProviderPreviousTestApi(Resource):
  268. @setup_required
  269. @login_required
  270. @account_initialization_required
  271. def post(self):
  272. parser = reqparse.RequestParser()
  273. parser.add_argument("tool_name", type=str, required=True, nullable=False, location="json")
  274. parser.add_argument("provider_name", type=str, required=False, nullable=False, location="json")
  275. parser.add_argument("credentials", type=dict, required=True, nullable=False, location="json")
  276. parser.add_argument("parameters", type=dict, required=True, nullable=False, location="json")
  277. parser.add_argument("schema_type", type=str, required=True, nullable=False, location="json")
  278. parser.add_argument("schema", type=str, required=True, nullable=False, location="json")
  279. args = parser.parse_args()
  280. return ApiToolManageService.test_api_tool_preview(
  281. current_user.current_tenant_id,
  282. args["provider_name"] or "",
  283. args["tool_name"],
  284. args["credentials"],
  285. args["parameters"],
  286. args["schema_type"],
  287. args["schema"],
  288. )
  289. class ToolWorkflowProviderCreateApi(Resource):
  290. @setup_required
  291. @login_required
  292. @account_initialization_required
  293. def post(self):
  294. user = current_user
  295. if not user.is_admin_or_owner:
  296. raise Forbidden()
  297. user_id = user.id
  298. tenant_id = user.current_tenant_id
  299. reqparser = reqparse.RequestParser()
  300. reqparser.add_argument("workflow_app_id", type=uuid_value, required=True, nullable=False, location="json")
  301. reqparser.add_argument("name", type=alphanumeric, required=True, nullable=False, location="json")
  302. reqparser.add_argument("label", type=str, required=True, nullable=False, location="json")
  303. reqparser.add_argument("description", type=str, required=True, nullable=False, location="json")
  304. reqparser.add_argument("icon", type=dict, required=True, nullable=False, location="json")
  305. reqparser.add_argument("parameters", type=list[dict], required=True, nullable=False, location="json")
  306. reqparser.add_argument("privacy_policy", type=str, required=False, nullable=True, location="json", default="")
  307. reqparser.add_argument("labels", type=list[str], required=False, nullable=True, location="json")
  308. args = reqparser.parse_args()
  309. return WorkflowToolManageService.create_workflow_tool(
  310. user_id=user_id,
  311. tenant_id=tenant_id,
  312. workflow_app_id=args["workflow_app_id"],
  313. name=args["name"],
  314. label=args["label"],
  315. icon=args["icon"],
  316. description=args["description"],
  317. parameters=args["parameters"],
  318. privacy_policy=args["privacy_policy"],
  319. labels=args["labels"],
  320. )
  321. class ToolWorkflowProviderUpdateApi(Resource):
  322. @setup_required
  323. @login_required
  324. @account_initialization_required
  325. def post(self):
  326. user = current_user
  327. if not user.is_admin_or_owner:
  328. raise Forbidden()
  329. user_id = user.id
  330. tenant_id = user.current_tenant_id
  331. reqparser = reqparse.RequestParser()
  332. reqparser.add_argument("workflow_tool_id", type=uuid_value, required=True, nullable=False, location="json")
  333. reqparser.add_argument("name", type=alphanumeric, required=True, nullable=False, location="json")
  334. reqparser.add_argument("label", type=str, required=True, nullable=False, location="json")
  335. reqparser.add_argument("description", type=str, required=True, nullable=False, location="json")
  336. reqparser.add_argument("icon", type=dict, required=True, nullable=False, location="json")
  337. reqparser.add_argument("parameters", type=list[dict], required=True, nullable=False, location="json")
  338. reqparser.add_argument("privacy_policy", type=str, required=False, nullable=True, location="json", default="")
  339. reqparser.add_argument("labels", type=list[str], required=False, nullable=True, location="json")
  340. args = reqparser.parse_args()
  341. if not args["workflow_tool_id"]:
  342. raise ValueError("incorrect workflow_tool_id")
  343. return WorkflowToolManageService.update_workflow_tool(
  344. user_id,
  345. tenant_id,
  346. args["workflow_tool_id"],
  347. args["name"],
  348. args["label"],
  349. args["icon"],
  350. args["description"],
  351. args["parameters"],
  352. args["privacy_policy"],
  353. args.get("labels", []),
  354. )
  355. class ToolWorkflowProviderDeleteApi(Resource):
  356. @setup_required
  357. @login_required
  358. @account_initialization_required
  359. def post(self):
  360. user = current_user
  361. if not user.is_admin_or_owner:
  362. raise Forbidden()
  363. user_id = user.id
  364. tenant_id = user.current_tenant_id
  365. reqparser = reqparse.RequestParser()
  366. reqparser.add_argument("workflow_tool_id", type=uuid_value, required=True, nullable=False, location="json")
  367. args = reqparser.parse_args()
  368. return WorkflowToolManageService.delete_workflow_tool(
  369. user_id,
  370. tenant_id,
  371. args["workflow_tool_id"],
  372. )
  373. class ToolWorkflowProviderGetApi(Resource):
  374. @setup_required
  375. @login_required
  376. @account_initialization_required
  377. def get(self):
  378. user = current_user
  379. user_id = user.id
  380. tenant_id = user.current_tenant_id
  381. parser = reqparse.RequestParser()
  382. parser.add_argument("workflow_tool_id", type=uuid_value, required=False, nullable=True, location="args")
  383. parser.add_argument("workflow_app_id", type=uuid_value, required=False, nullable=True, location="args")
  384. args = parser.parse_args()
  385. if args.get("workflow_tool_id"):
  386. tool = WorkflowToolManageService.get_workflow_tool_by_tool_id(
  387. user_id,
  388. tenant_id,
  389. args["workflow_tool_id"],
  390. )
  391. elif args.get("workflow_app_id"):
  392. tool = WorkflowToolManageService.get_workflow_tool_by_app_id(
  393. user_id,
  394. tenant_id,
  395. args["workflow_app_id"],
  396. )
  397. else:
  398. raise ValueError("incorrect workflow_tool_id or workflow_app_id")
  399. return jsonable_encoder(tool)
  400. class ToolWorkflowProviderListToolApi(Resource):
  401. @setup_required
  402. @login_required
  403. @account_initialization_required
  404. def get(self):
  405. user = current_user
  406. user_id = user.id
  407. tenant_id = user.current_tenant_id
  408. parser = reqparse.RequestParser()
  409. parser.add_argument("workflow_tool_id", type=uuid_value, required=True, nullable=False, location="args")
  410. args = parser.parse_args()
  411. return jsonable_encoder(
  412. WorkflowToolManageService.list_single_workflow_tools(
  413. user_id,
  414. tenant_id,
  415. args["workflow_tool_id"],
  416. )
  417. )
  418. class ToolBuiltinListApi(Resource):
  419. @setup_required
  420. @login_required
  421. @account_initialization_required
  422. def get(self):
  423. user = current_user
  424. user_id = user.id
  425. tenant_id = user.current_tenant_id
  426. return jsonable_encoder(
  427. [
  428. provider.to_dict()
  429. for provider in BuiltinToolManageService.list_builtin_tools(
  430. user_id,
  431. tenant_id,
  432. )
  433. ]
  434. )
  435. class ToolApiListApi(Resource):
  436. @setup_required
  437. @login_required
  438. @account_initialization_required
  439. def get(self):
  440. user = current_user
  441. user_id = user.id
  442. tenant_id = user.current_tenant_id
  443. return jsonable_encoder(
  444. [
  445. provider.to_dict()
  446. for provider in ApiToolManageService.list_api_tools(
  447. user_id,
  448. tenant_id,
  449. )
  450. ]
  451. )
  452. class ToolWorkflowListApi(Resource):
  453. @setup_required
  454. @login_required
  455. @account_initialization_required
  456. def get(self):
  457. user = current_user
  458. user_id = user.id
  459. tenant_id = user.current_tenant_id
  460. return jsonable_encoder(
  461. [
  462. provider.to_dict()
  463. for provider in WorkflowToolManageService.list_tenant_workflow_tools(
  464. user_id,
  465. tenant_id,
  466. )
  467. ]
  468. )
  469. class ToolLabelsApi(Resource):
  470. @setup_required
  471. @login_required
  472. @account_initialization_required
  473. @enterprise_license_required
  474. def get(self):
  475. return jsonable_encoder(ToolLabelsService.list_tool_labels())
  476. # tool provider
  477. api.add_resource(ToolProviderListApi, "/workspaces/current/tool-providers")
  478. # builtin tool provider
  479. api.add_resource(ToolBuiltinProviderListToolsApi, "/workspaces/current/tool-provider/builtin/<path:provider>/tools")
  480. api.add_resource(ToolBuiltinProviderInfoApi, "/workspaces/current/tool-provider/builtin/<path:provider>/info")
  481. api.add_resource(ToolBuiltinProviderDeleteApi, "/workspaces/current/tool-provider/builtin/<path:provider>/delete")
  482. api.add_resource(ToolBuiltinProviderUpdateApi, "/workspaces/current/tool-provider/builtin/<path:provider>/update")
  483. api.add_resource(
  484. ToolBuiltinProviderGetCredentialsApi, "/workspaces/current/tool-provider/builtin/<path:provider>/credentials"
  485. )
  486. api.add_resource(
  487. ToolBuiltinProviderCredentialsSchemaApi,
  488. "/workspaces/current/tool-provider/builtin/<path:provider>/credentials_schema",
  489. )
  490. api.add_resource(ToolBuiltinProviderIconApi, "/workspaces/current/tool-provider/builtin/<path:provider>/icon")
  491. # api tool provider
  492. api.add_resource(ToolApiProviderAddApi, "/workspaces/current/tool-provider/api/add")
  493. api.add_resource(ToolApiProviderGetRemoteSchemaApi, "/workspaces/current/tool-provider/api/remote")
  494. api.add_resource(ToolApiProviderListToolsApi, "/workspaces/current/tool-provider/api/tools")
  495. api.add_resource(ToolApiProviderUpdateApi, "/workspaces/current/tool-provider/api/update")
  496. api.add_resource(ToolApiProviderDeleteApi, "/workspaces/current/tool-provider/api/delete")
  497. api.add_resource(ToolApiProviderGetApi, "/workspaces/current/tool-provider/api/get")
  498. api.add_resource(ToolApiProviderSchemaApi, "/workspaces/current/tool-provider/api/schema")
  499. api.add_resource(ToolApiProviderPreviousTestApi, "/workspaces/current/tool-provider/api/test/pre")
  500. # workflow tool provider
  501. api.add_resource(ToolWorkflowProviderCreateApi, "/workspaces/current/tool-provider/workflow/create")
  502. api.add_resource(ToolWorkflowProviderUpdateApi, "/workspaces/current/tool-provider/workflow/update")
  503. api.add_resource(ToolWorkflowProviderDeleteApi, "/workspaces/current/tool-provider/workflow/delete")
  504. api.add_resource(ToolWorkflowProviderGetApi, "/workspaces/current/tool-provider/workflow/get")
  505. api.add_resource(ToolWorkflowProviderListToolApi, "/workspaces/current/tool-provider/workflow/tools")
  506. api.add_resource(ToolBuiltinListApi, "/workspaces/current/tools/builtin")
  507. api.add_resource(ToolApiListApi, "/workspaces/current/tools/api")
  508. api.add_resource(ToolWorkflowListApi, "/workspaces/current/tools/workflow")
  509. api.add_resource(ToolLabelsApi, "/workspaces/current/tool-labels")