Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

external.py 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. from flask import request
  2. from flask_login import current_user
  3. from flask_restful import Resource, marshal, reqparse
  4. from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
  5. import services
  6. from controllers.console import api
  7. from controllers.console.datasets.error import DatasetNameDuplicateError
  8. from controllers.console.wraps import account_initialization_required, setup_required
  9. from fields.dataset_fields import dataset_detail_fields
  10. from libs.login import login_required
  11. from services.dataset_service import DatasetService
  12. from services.external_knowledge_service import ExternalDatasetService
  13. from services.hit_testing_service import HitTestingService
  14. from services.knowledge_service import ExternalDatasetTestService
  15. def _validate_name(name):
  16. if not name or len(name) < 1 or len(name) > 100:
  17. raise ValueError("Name must be between 1 to 100 characters.")
  18. return name
  19. class ExternalApiTemplateListApi(Resource):
  20. @setup_required
  21. @login_required
  22. @account_initialization_required
  23. def get(self):
  24. page = request.args.get("page", default=1, type=int)
  25. limit = request.args.get("limit", default=20, type=int)
  26. search = request.args.get("keyword", default=None, type=str)
  27. external_knowledge_apis, total = ExternalDatasetService.get_external_knowledge_apis(
  28. page, limit, current_user.current_tenant_id, search
  29. )
  30. response = {
  31. "data": [item.to_dict() for item in external_knowledge_apis],
  32. "has_more": len(external_knowledge_apis) == limit,
  33. "limit": limit,
  34. "total": total,
  35. "page": page,
  36. }
  37. return response, 200
  38. @setup_required
  39. @login_required
  40. @account_initialization_required
  41. def post(self):
  42. parser = reqparse.RequestParser()
  43. parser.add_argument(
  44. "name",
  45. nullable=False,
  46. required=True,
  47. help="Name is required. Name must be between 1 to 100 characters.",
  48. type=_validate_name,
  49. )
  50. parser.add_argument(
  51. "settings",
  52. type=dict,
  53. location="json",
  54. nullable=False,
  55. required=True,
  56. )
  57. args = parser.parse_args()
  58. ExternalDatasetService.validate_api_list(args["settings"])
  59. # The role of the current user in the ta table must be admin, owner, or editor, or dataset_operator
  60. if not current_user.is_dataset_editor:
  61. raise Forbidden()
  62. try:
  63. external_knowledge_api = ExternalDatasetService.create_external_knowledge_api(
  64. tenant_id=current_user.current_tenant_id, user_id=current_user.id, args=args
  65. )
  66. except services.errors.dataset.DatasetNameDuplicateError:
  67. raise DatasetNameDuplicateError()
  68. return external_knowledge_api.to_dict(), 201
  69. class ExternalApiTemplateApi(Resource):
  70. @setup_required
  71. @login_required
  72. @account_initialization_required
  73. def get(self, external_knowledge_api_id):
  74. external_knowledge_api_id = str(external_knowledge_api_id)
  75. external_knowledge_api = ExternalDatasetService.get_external_knowledge_api(external_knowledge_api_id)
  76. if external_knowledge_api is None:
  77. raise NotFound("API template not found.")
  78. return external_knowledge_api.to_dict(), 200
  79. @setup_required
  80. @login_required
  81. @account_initialization_required
  82. def patch(self, external_knowledge_api_id):
  83. external_knowledge_api_id = str(external_knowledge_api_id)
  84. parser = reqparse.RequestParser()
  85. parser.add_argument(
  86. "name",
  87. nullable=False,
  88. required=True,
  89. help="type is required. Name must be between 1 to 100 characters.",
  90. type=_validate_name,
  91. )
  92. parser.add_argument(
  93. "settings",
  94. type=dict,
  95. location="json",
  96. nullable=False,
  97. required=True,
  98. )
  99. args = parser.parse_args()
  100. ExternalDatasetService.validate_api_list(args["settings"])
  101. external_knowledge_api = ExternalDatasetService.update_external_knowledge_api(
  102. tenant_id=current_user.current_tenant_id,
  103. user_id=current_user.id,
  104. external_knowledge_api_id=external_knowledge_api_id,
  105. args=args,
  106. )
  107. return external_knowledge_api.to_dict(), 200
  108. @setup_required
  109. @login_required
  110. @account_initialization_required
  111. def delete(self, external_knowledge_api_id):
  112. external_knowledge_api_id = str(external_knowledge_api_id)
  113. # The role of the current user in the ta table must be admin, owner, or editor
  114. if not current_user.is_editor or current_user.is_dataset_operator:
  115. raise Forbidden()
  116. ExternalDatasetService.delete_external_knowledge_api(current_user.current_tenant_id, external_knowledge_api_id)
  117. return {"result": "success"}, 204
  118. class ExternalApiUseCheckApi(Resource):
  119. @setup_required
  120. @login_required
  121. @account_initialization_required
  122. def get(self, external_knowledge_api_id):
  123. external_knowledge_api_id = str(external_knowledge_api_id)
  124. external_knowledge_api_is_using, count = ExternalDatasetService.external_knowledge_api_use_check(
  125. external_knowledge_api_id
  126. )
  127. return {"is_using": external_knowledge_api_is_using, "count": count}, 200
  128. class ExternalDatasetCreateApi(Resource):
  129. @setup_required
  130. @login_required
  131. @account_initialization_required
  132. def post(self):
  133. # The role of the current user in the ta table must be admin, owner, or editor
  134. if not current_user.is_editor:
  135. raise Forbidden()
  136. parser = reqparse.RequestParser()
  137. parser.add_argument("external_knowledge_api_id", type=str, required=True, nullable=False, location="json")
  138. parser.add_argument("external_knowledge_id", type=str, required=True, nullable=False, location="json")
  139. parser.add_argument(
  140. "name",
  141. nullable=False,
  142. required=True,
  143. help="name is required. Name must be between 1 to 100 characters.",
  144. type=_validate_name,
  145. )
  146. parser.add_argument("description", type=str, required=False, nullable=True, location="json")
  147. parser.add_argument("external_retrieval_model", type=dict, required=False, location="json")
  148. args = parser.parse_args()
  149. # The role of the current user in the ta table must be admin, owner, or editor, or dataset_operator
  150. if not current_user.is_dataset_editor:
  151. raise Forbidden()
  152. try:
  153. dataset = ExternalDatasetService.create_external_dataset(
  154. tenant_id=current_user.current_tenant_id,
  155. user_id=current_user.id,
  156. args=args,
  157. )
  158. except services.errors.dataset.DatasetNameDuplicateError:
  159. raise DatasetNameDuplicateError()
  160. return marshal(dataset, dataset_detail_fields), 201
  161. class ExternalKnowledgeHitTestingApi(Resource):
  162. @setup_required
  163. @login_required
  164. @account_initialization_required
  165. def post(self, dataset_id):
  166. dataset_id_str = str(dataset_id)
  167. dataset = DatasetService.get_dataset(dataset_id_str)
  168. if dataset is None:
  169. raise NotFound("Dataset not found.")
  170. try:
  171. DatasetService.check_dataset_permission(dataset, current_user)
  172. except services.errors.account.NoPermissionError as e:
  173. raise Forbidden(str(e))
  174. parser = reqparse.RequestParser()
  175. parser.add_argument("query", type=str, location="json")
  176. parser.add_argument("external_retrieval_model", type=dict, required=False, location="json")
  177. parser.add_argument("metadata_filtering_conditions", type=dict, required=False, location="json")
  178. args = parser.parse_args()
  179. HitTestingService.hit_testing_args_check(args)
  180. try:
  181. response = HitTestingService.external_retrieve(
  182. dataset=dataset,
  183. query=args["query"],
  184. account=current_user,
  185. external_retrieval_model=args["external_retrieval_model"],
  186. metadata_filtering_conditions=args["metadata_filtering_conditions"],
  187. )
  188. return response
  189. except Exception as e:
  190. raise InternalServerError(str(e))
  191. class BedrockRetrievalApi(Resource):
  192. # this api is only for internal testing
  193. def post(self):
  194. parser = reqparse.RequestParser()
  195. parser.add_argument("retrieval_setting", nullable=False, required=True, type=dict, location="json")
  196. parser.add_argument(
  197. "query",
  198. nullable=False,
  199. required=True,
  200. type=str,
  201. )
  202. parser.add_argument("knowledge_id", nullable=False, required=True, type=str)
  203. args = parser.parse_args()
  204. # Call the knowledge retrieval service
  205. result = ExternalDatasetTestService.knowledge_retrieval(
  206. args["retrieval_setting"], args["query"], args["knowledge_id"]
  207. )
  208. return result, 200
  209. api.add_resource(ExternalKnowledgeHitTestingApi, "/datasets/<uuid:dataset_id>/external-hit-testing")
  210. api.add_resource(ExternalDatasetCreateApi, "/datasets/external")
  211. api.add_resource(ExternalApiTemplateListApi, "/datasets/external-knowledge-api")
  212. api.add_resource(ExternalApiTemplateApi, "/datasets/external-knowledge-api/<uuid:external_knowledge_api_id>")
  213. api.add_resource(ExternalApiUseCheckApi, "/datasets/external-knowledge-api/<uuid:external_knowledge_api_id>/use-check")
  214. # this api is only for internal test
  215. api.add_resource(BedrockRetrievalApi, "/test/retrieval")