datasets.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. import flask_restful
  2. from flask import request
  3. from flask_login import current_user
  4. from flask_restful import Resource, marshal, marshal_with, reqparse
  5. from werkzeug.exceptions import Forbidden, NotFound
  6. import services
  7. from configs import dify_config
  8. from controllers.console import api
  9. from controllers.console.apikey import api_key_fields, api_key_list
  10. from controllers.console.app.error import ProviderNotInitializeError
  11. from controllers.console.datasets.error import DatasetInUseError, DatasetNameDuplicateError, IndexingEstimateError
  12. from controllers.console.wraps import account_initialization_required, setup_required
  13. from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError
  14. from core.indexing_runner import IndexingRunner
  15. from core.model_runtime.entities.model_entities import ModelType
  16. from core.provider_manager import ProviderManager
  17. from core.rag.datasource.vdb.vector_type import VectorType
  18. from core.rag.extractor.entity.extract_setting import ExtractSetting
  19. from core.rag.retrieval.retrieval_methods import RetrievalMethod
  20. from extensions.ext_database import db
  21. from fields.app_fields import related_app_list
  22. from fields.dataset_fields import dataset_detail_fields, dataset_query_detail_fields
  23. from fields.document_fields import document_status_fields
  24. from libs.login import login_required
  25. from models import ApiToken, Dataset, Document, DocumentSegment, UploadFile
  26. from models.dataset import DatasetPermissionEnum
  27. from services.dataset_service import DatasetPermissionService, DatasetService, DocumentService
  28. def _validate_name(name):
  29. if not name or len(name) < 1 or len(name) > 40:
  30. raise ValueError("Name must be between 1 to 40 characters.")
  31. return name
  32. def _validate_description_length(description):
  33. if len(description) > 400:
  34. raise ValueError("Description cannot exceed 400 characters.")
  35. return description
  36. class DatasetListApi(Resource):
  37. @setup_required
  38. @login_required
  39. @account_initialization_required
  40. def get(self):
  41. page = request.args.get("page", default=1, type=int)
  42. limit = request.args.get("limit", default=20, type=int)
  43. ids = request.args.getlist("ids")
  44. # provider = request.args.get("provider", default="vendor")
  45. search = request.args.get("keyword", default=None, type=str)
  46. tag_ids = request.args.getlist("tag_ids")
  47. if ids:
  48. datasets, total = DatasetService.get_datasets_by_ids(ids, current_user.current_tenant_id)
  49. else:
  50. datasets, total = DatasetService.get_datasets(
  51. page, limit, current_user.current_tenant_id, current_user, search, tag_ids
  52. )
  53. # check embedding setting
  54. provider_manager = ProviderManager()
  55. configurations = provider_manager.get_configurations(tenant_id=current_user.current_tenant_id)
  56. embedding_models = configurations.get_models(model_type=ModelType.TEXT_EMBEDDING, only_active=True)
  57. model_names = []
  58. for embedding_model in embedding_models:
  59. model_names.append(f"{embedding_model.model}:{embedding_model.provider.provider}")
  60. data = marshal(datasets, dataset_detail_fields)
  61. for item in data:
  62. if item["indexing_technique"] == "high_quality":
  63. item_model = f"{item['embedding_model']}:{item['embedding_model_provider']}"
  64. if item_model in model_names:
  65. item["embedding_available"] = True
  66. else:
  67. item["embedding_available"] = False
  68. else:
  69. item["embedding_available"] = True
  70. if item.get("permission") == "partial_members":
  71. part_users_list = DatasetPermissionService.get_dataset_partial_member_list(item["id"])
  72. item.update({"partial_member_list": part_users_list})
  73. else:
  74. item.update({"partial_member_list": []})
  75. response = {"data": data, "has_more": len(datasets) == limit, "limit": limit, "total": total, "page": page}
  76. return response, 200
  77. @setup_required
  78. @login_required
  79. @account_initialization_required
  80. def post(self):
  81. parser = reqparse.RequestParser()
  82. parser.add_argument(
  83. "name",
  84. nullable=False,
  85. required=True,
  86. help="type is required. Name must be between 1 to 40 characters.",
  87. type=_validate_name,
  88. )
  89. parser.add_argument(
  90. "description",
  91. type=str,
  92. nullable=True,
  93. required=False,
  94. default="",
  95. )
  96. parser.add_argument(
  97. "indexing_technique",
  98. type=str,
  99. location="json",
  100. choices=Dataset.INDEXING_TECHNIQUE_LIST,
  101. nullable=True,
  102. help="Invalid indexing technique.",
  103. )
  104. parser.add_argument(
  105. "external_knowledge_api_id",
  106. type=str,
  107. nullable=True,
  108. required=False,
  109. )
  110. parser.add_argument(
  111. "provider",
  112. type=str,
  113. nullable=True,
  114. choices=Dataset.PROVIDER_LIST,
  115. required=False,
  116. default="vendor",
  117. )
  118. parser.add_argument(
  119. "external_knowledge_id",
  120. type=str,
  121. nullable=True,
  122. required=False,
  123. )
  124. args = parser.parse_args()
  125. # The role of the current user in the ta table must be admin, owner, or editor, or dataset_operator
  126. if not current_user.is_dataset_editor:
  127. raise Forbidden()
  128. try:
  129. dataset = DatasetService.create_empty_dataset(
  130. tenant_id=current_user.current_tenant_id,
  131. name=args["name"],
  132. description=args["description"],
  133. indexing_technique=args["indexing_technique"],
  134. account=current_user,
  135. permission=DatasetPermissionEnum.ONLY_ME,
  136. provider=args["provider"],
  137. external_knowledge_api_id=args["external_knowledge_api_id"],
  138. external_knowledge_id=args["external_knowledge_id"],
  139. )
  140. except services.errors.dataset.DatasetNameDuplicateError:
  141. raise DatasetNameDuplicateError()
  142. return marshal(dataset, dataset_detail_fields), 201
  143. class DatasetApi(Resource):
  144. @setup_required
  145. @login_required
  146. @account_initialization_required
  147. def get(self, dataset_id):
  148. dataset_id_str = str(dataset_id)
  149. dataset = DatasetService.get_dataset(dataset_id_str)
  150. if dataset is None:
  151. raise NotFound("Dataset not found.")
  152. try:
  153. DatasetService.check_dataset_permission(dataset, current_user)
  154. except services.errors.account.NoPermissionError as e:
  155. raise Forbidden(str(e))
  156. data = marshal(dataset, dataset_detail_fields)
  157. if data.get("permission") == "partial_members":
  158. part_users_list = DatasetPermissionService.get_dataset_partial_member_list(dataset_id_str)
  159. data.update({"partial_member_list": part_users_list})
  160. # check embedding setting
  161. provider_manager = ProviderManager()
  162. configurations = provider_manager.get_configurations(tenant_id=current_user.current_tenant_id)
  163. embedding_models = configurations.get_models(model_type=ModelType.TEXT_EMBEDDING, only_active=True)
  164. model_names = []
  165. for embedding_model in embedding_models:
  166. model_names.append(f"{embedding_model.model}:{embedding_model.provider.provider}")
  167. if data["indexing_technique"] == "high_quality":
  168. item_model = f"{data['embedding_model']}:{data['embedding_model_provider']}"
  169. if item_model in model_names:
  170. data["embedding_available"] = True
  171. else:
  172. data["embedding_available"] = False
  173. else:
  174. data["embedding_available"] = True
  175. if data.get("permission") == "partial_members":
  176. part_users_list = DatasetPermissionService.get_dataset_partial_member_list(dataset_id_str)
  177. data.update({"partial_member_list": part_users_list})
  178. return data, 200
  179. @setup_required
  180. @login_required
  181. @account_initialization_required
  182. def patch(self, dataset_id):
  183. dataset_id_str = str(dataset_id)
  184. dataset = DatasetService.get_dataset(dataset_id_str)
  185. if dataset is None:
  186. raise NotFound("Dataset not found.")
  187. parser = reqparse.RequestParser()
  188. parser.add_argument(
  189. "name",
  190. nullable=False,
  191. help="type is required. Name must be between 1 to 40 characters.",
  192. type=_validate_name,
  193. )
  194. parser.add_argument("description", location="json", store_missing=False, type=_validate_description_length)
  195. parser.add_argument(
  196. "indexing_technique",
  197. type=str,
  198. location="json",
  199. choices=Dataset.INDEXING_TECHNIQUE_LIST,
  200. nullable=True,
  201. help="Invalid indexing technique.",
  202. )
  203. parser.add_argument(
  204. "permission",
  205. type=str,
  206. location="json",
  207. choices=(DatasetPermissionEnum.ONLY_ME, DatasetPermissionEnum.ALL_TEAM, DatasetPermissionEnum.PARTIAL_TEAM),
  208. help="Invalid permission.",
  209. )
  210. parser.add_argument("embedding_model", type=str, location="json", help="Invalid embedding model.")
  211. parser.add_argument(
  212. "embedding_model_provider", type=str, location="json", help="Invalid embedding model provider."
  213. )
  214. parser.add_argument("retrieval_model", type=dict, location="json", help="Invalid retrieval model.")
  215. parser.add_argument("partial_member_list", type=list, location="json", help="Invalid parent user list.")
  216. parser.add_argument(
  217. "external_retrieval_model",
  218. type=dict,
  219. required=False,
  220. nullable=True,
  221. location="json",
  222. help="Invalid external retrieval model.",
  223. )
  224. parser.add_argument(
  225. "external_knowledge_id",
  226. type=str,
  227. required=False,
  228. nullable=True,
  229. location="json",
  230. help="Invalid external knowledge id.",
  231. )
  232. parser.add_argument(
  233. "external_knowledge_api_id",
  234. type=str,
  235. required=False,
  236. nullable=True,
  237. location="json",
  238. help="Invalid external knowledge api id.",
  239. )
  240. args = parser.parse_args()
  241. data = request.get_json()
  242. # check embedding model setting
  243. if data.get("indexing_technique") == "high_quality":
  244. DatasetService.check_embedding_model_setting(
  245. dataset.tenant_id, data.get("embedding_model_provider"), data.get("embedding_model")
  246. )
  247. # The role of the current user in the ta table must be admin, owner, editor, or dataset_operator
  248. DatasetPermissionService.check_permission(
  249. current_user, dataset, data.get("permission"), data.get("partial_member_list")
  250. )
  251. dataset = DatasetService.update_dataset(dataset_id_str, args, current_user)
  252. if dataset is None:
  253. raise NotFound("Dataset not found.")
  254. result_data = marshal(dataset, dataset_detail_fields)
  255. tenant_id = current_user.current_tenant_id
  256. if data.get("partial_member_list") and data.get("permission") == "partial_members":
  257. DatasetPermissionService.update_partial_member_list(
  258. tenant_id, dataset_id_str, data.get("partial_member_list")
  259. )
  260. # clear partial member list when permission is only_me or all_team_members
  261. elif (
  262. data.get("permission") == DatasetPermissionEnum.ONLY_ME
  263. or data.get("permission") == DatasetPermissionEnum.ALL_TEAM
  264. ):
  265. DatasetPermissionService.clear_partial_member_list(dataset_id_str)
  266. partial_member_list = DatasetPermissionService.get_dataset_partial_member_list(dataset_id_str)
  267. result_data.update({"partial_member_list": partial_member_list})
  268. return result_data, 200
  269. @setup_required
  270. @login_required
  271. @account_initialization_required
  272. def delete(self, dataset_id):
  273. dataset_id_str = str(dataset_id)
  274. # The role of the current user in the ta table must be admin, owner, or editor
  275. if not current_user.is_editor or current_user.is_dataset_operator:
  276. raise Forbidden()
  277. try:
  278. if DatasetService.delete_dataset(dataset_id_str, current_user):
  279. DatasetPermissionService.clear_partial_member_list(dataset_id_str)
  280. return {"result": "success"}, 204
  281. else:
  282. raise NotFound("Dataset not found.")
  283. except services.errors.dataset.DatasetInUseError:
  284. raise DatasetInUseError()
  285. class DatasetUseCheckApi(Resource):
  286. @setup_required
  287. @login_required
  288. @account_initialization_required
  289. def get(self, dataset_id):
  290. dataset_id_str = str(dataset_id)
  291. dataset_is_using = DatasetService.dataset_use_check(dataset_id_str)
  292. return {"is_using": dataset_is_using}, 200
  293. class DatasetQueryApi(Resource):
  294. @setup_required
  295. @login_required
  296. @account_initialization_required
  297. def get(self, dataset_id):
  298. dataset_id_str = str(dataset_id)
  299. dataset = DatasetService.get_dataset(dataset_id_str)
  300. if dataset is None:
  301. raise NotFound("Dataset not found.")
  302. try:
  303. DatasetService.check_dataset_permission(dataset, current_user)
  304. except services.errors.account.NoPermissionError as e:
  305. raise Forbidden(str(e))
  306. page = request.args.get("page", default=1, type=int)
  307. limit = request.args.get("limit", default=20, type=int)
  308. dataset_queries, total = DatasetService.get_dataset_queries(dataset_id=dataset.id, page=page, per_page=limit)
  309. response = {
  310. "data": marshal(dataset_queries, dataset_query_detail_fields),
  311. "has_more": len(dataset_queries) == limit,
  312. "limit": limit,
  313. "total": total,
  314. "page": page,
  315. }
  316. return response, 200
  317. class DatasetIndexingEstimateApi(Resource):
  318. @setup_required
  319. @login_required
  320. @account_initialization_required
  321. def post(self):
  322. parser = reqparse.RequestParser()
  323. parser.add_argument("info_list", type=dict, required=True, nullable=True, location="json")
  324. parser.add_argument("process_rule", type=dict, required=True, nullable=True, location="json")
  325. parser.add_argument(
  326. "indexing_technique",
  327. type=str,
  328. required=True,
  329. choices=Dataset.INDEXING_TECHNIQUE_LIST,
  330. nullable=True,
  331. location="json",
  332. )
  333. parser.add_argument("doc_form", type=str, default="text_model", required=False, nullable=False, location="json")
  334. parser.add_argument("dataset_id", type=str, required=False, nullable=False, location="json")
  335. parser.add_argument(
  336. "doc_language", type=str, default="English", required=False, nullable=False, location="json"
  337. )
  338. args = parser.parse_args()
  339. # validate args
  340. DocumentService.estimate_args_validate(args)
  341. extract_settings = []
  342. if args["info_list"]["data_source_type"] == "upload_file":
  343. file_ids = args["info_list"]["file_info_list"]["file_ids"]
  344. file_details = (
  345. db.session.query(UploadFile)
  346. .filter(UploadFile.tenant_id == current_user.current_tenant_id, UploadFile.id.in_(file_ids))
  347. .all()
  348. )
  349. if file_details is None:
  350. raise NotFound("File not found.")
  351. if file_details:
  352. for file_detail in file_details:
  353. extract_setting = ExtractSetting(
  354. datasource_type="upload_file", upload_file=file_detail, document_model=args["doc_form"]
  355. )
  356. extract_settings.append(extract_setting)
  357. elif args["info_list"]["data_source_type"] == "notion_import":
  358. notion_info_list = args["info_list"]["notion_info_list"]
  359. for notion_info in notion_info_list:
  360. workspace_id = notion_info["workspace_id"]
  361. for page in notion_info["pages"]:
  362. extract_setting = ExtractSetting(
  363. datasource_type="notion_import",
  364. notion_info={
  365. "notion_workspace_id": workspace_id,
  366. "notion_obj_id": page["page_id"],
  367. "notion_page_type": page["type"],
  368. "tenant_id": current_user.current_tenant_id,
  369. },
  370. document_model=args["doc_form"],
  371. )
  372. extract_settings.append(extract_setting)
  373. elif args["info_list"]["data_source_type"] == "website_crawl":
  374. website_info_list = args["info_list"]["website_info_list"]
  375. for url in website_info_list["urls"]:
  376. extract_setting = ExtractSetting(
  377. datasource_type="website_crawl",
  378. website_info={
  379. "provider": website_info_list["provider"],
  380. "job_id": website_info_list["job_id"],
  381. "url": url,
  382. "tenant_id": current_user.current_tenant_id,
  383. "mode": "crawl",
  384. "only_main_content": website_info_list["only_main_content"],
  385. },
  386. document_model=args["doc_form"],
  387. )
  388. extract_settings.append(extract_setting)
  389. else:
  390. raise ValueError("Data source type not support")
  391. indexing_runner = IndexingRunner()
  392. try:
  393. response = indexing_runner.indexing_estimate(
  394. current_user.current_tenant_id,
  395. extract_settings,
  396. args["process_rule"],
  397. args["doc_form"],
  398. args["doc_language"],
  399. args["dataset_id"],
  400. args["indexing_technique"],
  401. )
  402. except LLMBadRequestError:
  403. raise ProviderNotInitializeError(
  404. "No Embedding Model available. Please configure a valid provider " "in the Settings -> Model Provider."
  405. )
  406. except ProviderTokenNotInitError as ex:
  407. raise ProviderNotInitializeError(ex.description)
  408. except Exception as e:
  409. raise IndexingEstimateError(str(e))
  410. return response, 200
  411. class DatasetRelatedAppListApi(Resource):
  412. @setup_required
  413. @login_required
  414. @account_initialization_required
  415. @marshal_with(related_app_list)
  416. def get(self, dataset_id):
  417. dataset_id_str = str(dataset_id)
  418. dataset = DatasetService.get_dataset(dataset_id_str)
  419. if dataset is None:
  420. raise NotFound("Dataset not found.")
  421. try:
  422. DatasetService.check_dataset_permission(dataset, current_user)
  423. except services.errors.account.NoPermissionError as e:
  424. raise Forbidden(str(e))
  425. app_dataset_joins = DatasetService.get_related_apps(dataset.id)
  426. related_apps = []
  427. for app_dataset_join in app_dataset_joins:
  428. app_model = app_dataset_join.app
  429. if app_model:
  430. related_apps.append(app_model)
  431. return {"data": related_apps, "total": len(related_apps)}, 200
  432. class DatasetIndexingStatusApi(Resource):
  433. @setup_required
  434. @login_required
  435. @account_initialization_required
  436. def get(self, dataset_id):
  437. dataset_id = str(dataset_id)
  438. documents = (
  439. db.session.query(Document)
  440. .filter(Document.dataset_id == dataset_id, Document.tenant_id == current_user.current_tenant_id)
  441. .all()
  442. )
  443. documents_status = []
  444. for document in documents:
  445. completed_segments = DocumentSegment.query.filter(
  446. DocumentSegment.completed_at.isnot(None),
  447. DocumentSegment.document_id == str(document.id),
  448. DocumentSegment.status != "re_segment",
  449. ).count()
  450. total_segments = DocumentSegment.query.filter(
  451. DocumentSegment.document_id == str(document.id), DocumentSegment.status != "re_segment"
  452. ).count()
  453. document.completed_segments = completed_segments
  454. document.total_segments = total_segments
  455. documents_status.append(marshal(document, document_status_fields))
  456. data = {"data": documents_status}
  457. return data
  458. class DatasetApiKeyApi(Resource):
  459. max_keys = 10
  460. token_prefix = "dataset-"
  461. resource_type = "dataset"
  462. @setup_required
  463. @login_required
  464. @account_initialization_required
  465. @marshal_with(api_key_list)
  466. def get(self):
  467. keys = (
  468. db.session.query(ApiToken)
  469. .filter(ApiToken.type == self.resource_type, ApiToken.tenant_id == current_user.current_tenant_id)
  470. .all()
  471. )
  472. return {"items": keys}
  473. @setup_required
  474. @login_required
  475. @account_initialization_required
  476. @marshal_with(api_key_fields)
  477. def post(self):
  478. # The role of the current user in the ta table must be admin or owner
  479. if not current_user.is_admin_or_owner:
  480. raise Forbidden()
  481. current_key_count = (
  482. db.session.query(ApiToken)
  483. .filter(ApiToken.type == self.resource_type, ApiToken.tenant_id == current_user.current_tenant_id)
  484. .count()
  485. )
  486. if current_key_count >= self.max_keys:
  487. flask_restful.abort(
  488. 400,
  489. message=f"Cannot create more than {self.max_keys} API keys for this resource type.",
  490. code="max_keys_exceeded",
  491. )
  492. key = ApiToken.generate_api_key(self.token_prefix, 24)
  493. api_token = ApiToken()
  494. api_token.tenant_id = current_user.current_tenant_id
  495. api_token.token = key
  496. api_token.type = self.resource_type
  497. db.session.add(api_token)
  498. db.session.commit()
  499. return api_token, 200
  500. class DatasetApiDeleteApi(Resource):
  501. resource_type = "dataset"
  502. @setup_required
  503. @login_required
  504. @account_initialization_required
  505. def delete(self, api_key_id):
  506. api_key_id = str(api_key_id)
  507. # The role of the current user in the ta table must be admin or owner
  508. if not current_user.is_admin_or_owner:
  509. raise Forbidden()
  510. key = (
  511. db.session.query(ApiToken)
  512. .filter(
  513. ApiToken.tenant_id == current_user.current_tenant_id,
  514. ApiToken.type == self.resource_type,
  515. ApiToken.id == api_key_id,
  516. )
  517. .first()
  518. )
  519. if key is None:
  520. flask_restful.abort(404, message="API key not found")
  521. db.session.query(ApiToken).filter(ApiToken.id == api_key_id).delete()
  522. db.session.commit()
  523. return {"result": "success"}, 204
  524. class DatasetApiBaseUrlApi(Resource):
  525. @setup_required
  526. @login_required
  527. @account_initialization_required
  528. def get(self):
  529. return {"api_base_url": (dify_config.SERVICE_API_URL or request.host_url.rstrip("/")) + "/v1"}
  530. class DatasetRetrievalSettingApi(Resource):
  531. @setup_required
  532. @login_required
  533. @account_initialization_required
  534. def get(self):
  535. vector_type = dify_config.VECTOR_STORE
  536. match vector_type:
  537. case (
  538. VectorType.MILVUS
  539. | VectorType.RELYT
  540. | VectorType.PGVECTOR
  541. | VectorType.TIDB_VECTOR
  542. | VectorType.CHROMA
  543. | VectorType.TENCENT
  544. | VectorType.PGVECTO_RS
  545. | VectorType.BAIDU
  546. | VectorType.VIKINGDB
  547. | VectorType.UPSTASH
  548. | VectorType.OCEANBASE
  549. ):
  550. return {"retrieval_method": [RetrievalMethod.SEMANTIC_SEARCH.value]}
  551. case (
  552. VectorType.QDRANT
  553. | VectorType.WEAVIATE
  554. | VectorType.OPENSEARCH
  555. | VectorType.ANALYTICDB
  556. | VectorType.MYSCALE
  557. | VectorType.ORACLE
  558. | VectorType.ELASTICSEARCH
  559. | VectorType.PGVECTOR
  560. | VectorType.TIDB_ON_QDRANT
  561. | VectorType.LINDORM
  562. | VectorType.COUCHBASE
  563. ):
  564. return {
  565. "retrieval_method": [
  566. RetrievalMethod.SEMANTIC_SEARCH.value,
  567. RetrievalMethod.FULL_TEXT_SEARCH.value,
  568. RetrievalMethod.HYBRID_SEARCH.value,
  569. ]
  570. }
  571. case _:
  572. raise ValueError(f"Unsupported vector db type {vector_type}.")
  573. class DatasetRetrievalSettingMockApi(Resource):
  574. @setup_required
  575. @login_required
  576. @account_initialization_required
  577. def get(self, vector_type):
  578. match vector_type:
  579. case (
  580. VectorType.MILVUS
  581. | VectorType.RELYT
  582. | VectorType.TIDB_VECTOR
  583. | VectorType.CHROMA
  584. | VectorType.TENCENT
  585. | VectorType.PGVECTO_RS
  586. | VectorType.BAIDU
  587. | VectorType.VIKINGDB
  588. | VectorType.UPSTASH
  589. | VectorType.OCEANBASE
  590. ):
  591. return {"retrieval_method": [RetrievalMethod.SEMANTIC_SEARCH.value]}
  592. case (
  593. VectorType.QDRANT
  594. | VectorType.WEAVIATE
  595. | VectorType.OPENSEARCH
  596. | VectorType.ANALYTICDB
  597. | VectorType.MYSCALE
  598. | VectorType.ORACLE
  599. | VectorType.ELASTICSEARCH
  600. | VectorType.COUCHBASE
  601. | VectorType.PGVECTOR
  602. | VectorType.LINDORM
  603. ):
  604. return {
  605. "retrieval_method": [
  606. RetrievalMethod.SEMANTIC_SEARCH.value,
  607. RetrievalMethod.FULL_TEXT_SEARCH.value,
  608. RetrievalMethod.HYBRID_SEARCH.value,
  609. ]
  610. }
  611. case _:
  612. raise ValueError(f"Unsupported vector db type {vector_type}.")
  613. class DatasetErrorDocs(Resource):
  614. @setup_required
  615. @login_required
  616. @account_initialization_required
  617. def get(self, dataset_id):
  618. dataset_id_str = str(dataset_id)
  619. dataset = DatasetService.get_dataset(dataset_id_str)
  620. if dataset is None:
  621. raise NotFound("Dataset not found.")
  622. results = DocumentService.get_error_documents_by_dataset_id(dataset_id_str)
  623. return {"data": [marshal(item, document_status_fields) for item in results], "total": len(results)}, 200
  624. class DatasetPermissionUserListApi(Resource):
  625. @setup_required
  626. @login_required
  627. @account_initialization_required
  628. def get(self, dataset_id):
  629. dataset_id_str = str(dataset_id)
  630. dataset = DatasetService.get_dataset(dataset_id_str)
  631. if dataset is None:
  632. raise NotFound("Dataset not found.")
  633. try:
  634. DatasetService.check_dataset_permission(dataset, current_user)
  635. except services.errors.account.NoPermissionError as e:
  636. raise Forbidden(str(e))
  637. partial_members_list = DatasetPermissionService.get_dataset_partial_member_list(dataset_id_str)
  638. return {
  639. "data": partial_members_list,
  640. }, 200
  641. api.add_resource(DatasetListApi, "/datasets")
  642. api.add_resource(DatasetApi, "/datasets/<uuid:dataset_id>")
  643. api.add_resource(DatasetUseCheckApi, "/datasets/<uuid:dataset_id>/use-check")
  644. api.add_resource(DatasetQueryApi, "/datasets/<uuid:dataset_id>/queries")
  645. api.add_resource(DatasetErrorDocs, "/datasets/<uuid:dataset_id>/error-docs")
  646. api.add_resource(DatasetIndexingEstimateApi, "/datasets/indexing-estimate")
  647. api.add_resource(DatasetRelatedAppListApi, "/datasets/<uuid:dataset_id>/related-apps")
  648. api.add_resource(DatasetIndexingStatusApi, "/datasets/<uuid:dataset_id>/indexing-status")
  649. api.add_resource(DatasetApiKeyApi, "/datasets/api-keys")
  650. api.add_resource(DatasetApiDeleteApi, "/datasets/api-keys/<uuid:api_key_id>")
  651. api.add_resource(DatasetApiBaseUrlApi, "/datasets/api-base-info")
  652. api.add_resource(DatasetRetrievalSettingApi, "/datasets/retrieval-setting")
  653. api.add_resource(DatasetRetrievalSettingMockApi, "/datasets/retrieval-setting/<string:vector_type>")
  654. api.add_resource(DatasetPermissionUserListApi, "/datasets/<uuid:dataset_id>/permission-part-users")