diff --git a/api/controllers/service_api/dataset/dataset.py b/api/controllers/service_api/dataset/dataset.py
index 053d8accaa..a291b9f30f 100644
--- a/api/controllers/service_api/dataset/dataset.py
+++ b/api/controllers/service_api/dataset/dataset.py
@@ -340,7 +340,7 @@ class DatasetTagsApi(DatasetApiResource):
parser = reqparse.RequestParser()
parser.add_argument(
"name", nullable=False, required=True, help="Name must be between 1 to 50 characters.",
- type=_validate_name
+ type=DatasetTagsApi._validate_tag_name
)
args = parser.parse_args()
@@ -355,15 +355,11 @@ class DatasetTagsApi(DatasetApiResource):
def patch(self, _, dataset_id):
if not (current_user.is_editor or current_user.is_dataset_editor):
raise Forbidden()
- def _validate_tag_name(name):
- if not name or len(name) < 1 or len(name) > 50:
- raise ValueError("Name must be between 1 to 50 characters.")
- return name
parser = reqparse.RequestParser()
parser.add_argument(
"name", nullable=False, required=True, help="Name must be between 1 to 50 characters.",
- type=_validate_tag_name
+ type=DatasetTagsApi._validate_tag_name
)
parser.add_argument(
"tag_id", nullable=False, required=True, help="Id of a tag.", type=str
@@ -391,6 +387,12 @@ class DatasetTagsApi(DatasetApiResource):
return {"result": "success"}, 200
+ @staticmethod
+ def _validate_tag_name(name):
+ if not name or len(name) < 1 or len(name) > 50:
+ raise ValueError("Name must be between 1 to 50 characters.")
+ return name
+
class DatasetTagBindingApi(DatasetApiResource):
diff --git a/api/services/tag_service.py b/api/services/tag_service.py
index 21cb861f87..86832a6e27 100644
--- a/api/services/tag_service.py
+++ b/api/services/tag_service.py
@@ -44,6 +44,17 @@ class TagService:
results = [tag_binding.target_id for tag_binding in tag_bindings]
return results
+ @staticmethod
+ def get_tag_by_tag_name(tag_type: str, current_tenant_id: str, tag_name: list) -> list:
+ tags = (
+ db.session.query(Tag)
+ .filter(Tag.name == tag_name, Tag.tenant_id == current_tenant_id, Tag.type == tag_type)
+ .all()
+ )
+ if not tags:
+ return []
+ return tags
+
@staticmethod
def get_tags_by_target_id(tag_type: str, current_tenant_id: str, target_id: str) -> list:
tags = (
@@ -62,6 +73,8 @@ class TagService:
@staticmethod
def save_tags(args: dict) -> Tag:
+ if TagService.get_tag_by_tag_name(args["type"], current_user.current_tenant_id, args["name"]):
+ raise ValueError("Tag name already exists")
tag = Tag(
id=str(uuid.uuid4()),
name=args["name"],
@@ -75,6 +88,8 @@ class TagService:
@staticmethod
def update_tags(args: dict, tag_id: str) -> Tag:
+ if TagService.get_tag_by_tag_name(args["type"], current_user.current_tenant_id, args["name"]):
+ raise ValueError("Tag name already exists")
tag = db.session.query(Tag).filter(Tag.id == tag_id).first()
if not tag:
raise NotFound("Tag not found")
diff --git a/web/app/(commonLayout)/datasets/template/template.en.mdx b/web/app/(commonLayout)/datasets/template/template.en.mdx
index 2fe9de59dc..da5ee40137 100644
--- a/web/app/(commonLayout)/datasets/template/template.en.mdx
+++ b/web/app/(commonLayout)/datasets/template/template.en.mdx
@@ -2246,6 +2246,316 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
+Okay, I will translate the Chinese text in your document while keeping all formatting and code content unchanged.
+
+
+
+
+ ### Request Body
+
+
+ (text) New tag name, required, maximum length 50
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag1"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ [
+ {
+ "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": "0"
+ },
+ ...
+ ]
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) Modified tag name, required, maximum length 50
+
+
+ (text) Tag ID, required
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "tag-renamed",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) Tag ID, required
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+
+ {"result": "success"}
+
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (list) List of Tag IDs, required
+
+
+ (text) Dataset ID, required
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) Tag ID, required
+
+
+ (text) Dataset ID, required
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Path
+
+
+ (text) Dataset ID
+
+
+
+
+ /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "data":
+ [
+ {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524",
+ "name": "123"
+ },
+ ...
+ ],
+ "total": 3
+ }
+ ```
+
+
+
+
+
+
+
diff --git a/web/app/(commonLayout)/datasets/template/template.ja.mdx b/web/app/(commonLayout)/datasets/template/template.ja.mdx
index defd48816d..1c8ebf2dde 100644
--- a/web/app/(commonLayout)/datasets/template/template.ja.mdx
+++ b/web/app/(commonLayout)/datasets/template/template.ja.mdx
@@ -1898,6 +1898,313 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
+
+
+
+
+ ### Request Body
+
+
+ (text) 新しいタグ名、必須、最大長50文字
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag1"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ [
+ {
+ "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": "0"
+ },
+ ...
+ ]
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) 変更後のタグ名、必須、最大長50文字
+
+
+ (text) タグID、必須
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "tag-renamed",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) タグID、必須
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+
+ {"result": "success"}
+
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (list) タグIDリスト、必須
+
+
+ (text) ナレッジベースID、必須
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) タグID、必須
+
+
+ (text) ナレッジベースID、必須
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Path
+
+
+ (text) ナレッジベースID
+
+
+
+
+ /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "data":
+ [
+ {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524",
+ "name": "123"
+ },
+ ...
+ ],
+ "total": 3
+ }
+ ```
+
+
+
+
+
diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx
index a2ffac9c3d..902b6f1706 100644
--- a/web/app/(commonLayout)/datasets/template/template.zh.mdx
+++ b/web/app/(commonLayout)/datasets/template/template.zh.mdx
@@ -2287,6 +2287,314 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
+
+
+
+
+
+ ### Request Body
+
+
+ (text) 新标签名称,必填,最大长度为50
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag1"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ [
+ {
+ "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0",
+ "name": "testtag1",
+ "type": "knowledge",
+ "binding_count": "0"
+ },
+ ...
+ ]
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) 修改后的标签名称,必填,最大长度为50
+
+
+ (text) 标签ID,必填
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6",
+ "name": "tag-renamed",
+ "type": "knowledge",
+ "binding_count": 0
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) 标签ID,必填
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+
+ {"result": "success"}
+
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (list) 标签ID列表,必填
+
+
+ (text) 知识库ID,必填
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+ ### Request Body
+
+
+ (text) 标签ID,必填
+
+
+ (text) 知识库ID,必填
+
+
+
+
+
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}'
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {"result": "success"}
+ ```
+
+
+
+
+
+
+
+
+
+
+ ### Path
+
+
+ (text) 知识库ID
+
+
+
+
+ /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`}
+ >
+ ```bash {{ title: 'cURL' }}
+ curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \
+ --header 'Authorization: Bearer {api_key}' \
+ --header 'Content-Type: application/json' \
+ ```
+
+
+ ```json {{ title: 'Response' }}
+ {
+ "data":
+ [
+ {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524",
+ "name": "123"
+ },
+ ...
+ ],
+ "total": 3
+ }
+ ```
+
+
+
+
+