Skip to content

Commit c47c70a

Browse files
committed
feat: implement knowledge tag management functionality
1 parent 56d32c1 commit c47c70a

File tree

26 files changed

+2146
-82
lines changed

26 files changed

+2146
-82
lines changed

apps/common/constants/permission_constants.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ class Group(Enum):
3939
SYSTEM_RES_KNOWLEDGE = "SYSTEM_RESOURCE_KNOWLEDGE"
4040
KNOWLEDGE_HIT_TEST = "KNOWLEDGE_HIT_TEST"
4141
KNOWLEDGE_DOCUMENT = "KNOWLEDGE_DOCUMENT"
42+
KNOWLEDGE_TAG = "KNOWLEDGE_TAG"
4243
SYSTEM_KNOWLEDGE_DOCUMENT = "SYSTEM_KNOWLEDGE_DOCUMENT"
4344
SYSTEM_RES_KNOWLEDGE_DOCUMENT = "SYSTEM_RESOURCE_KNOWLEDGE_DOCUMENT"
45+
SYSTEM_RES_KNOWLEDGE_TAG = "SYSTEM_RES_KNOWLEDGE_TAG"
46+
SYSTEM_KNOWLEDGE_TAG = "SYSTEM_KNOWLEDGE_TAG"
4447

4548
KNOWLEDGE_PROBLEM = "KNOWLEDGE_PROBLEM"
4649
SYSTEM_KNOWLEDGE_PROBLEM = "SYSTEM_KNOWLEDGE_PROBLEM"
@@ -696,6 +699,28 @@ class PermissionConstants(Enum):
696699
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE],
697700
parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
698701
)
702+
KNOWLEDGE_TAG_READ = Permission(
703+
group=Group.KNOWLEDGE_TAG, operate=Operate.READ,
704+
role_list=[RoleConstants.ADMIN, RoleConstants.USER],
705+
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE],
706+
parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
707+
)
708+
KNOWLEDGE_TAG_CREATE = Permission(
709+
group=Group.KNOWLEDGE_TAG, operate=Operate.CREATE,
710+
role_list=[RoleConstants.ADMIN, RoleConstants.USER],
711+
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE],
712+
parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
713+
)
714+
KNOWLEDGE_TAG_EDIT = Permission(
715+
group=Group.KNOWLEDGE_TAG, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN, RoleConstants.USER],
716+
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE],
717+
parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
718+
)
719+
KNOWLEDGE_TAG_DELETE = Permission(
720+
group=Group.KNOWLEDGE_TAG, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN, RoleConstants.USER],
721+
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_MANGE],
722+
parent_group=[WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
723+
)
699724
APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION_READ = Permission(
700725
group=Group.APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION, operate=Operate.READ,
701726
role_list=[RoleConstants.ADMIN, RoleConstants.WORKSPACE_MANAGE],
@@ -1199,6 +1224,22 @@ class PermissionConstants(Enum):
11991224
group=Group.SYSTEM_KNOWLEDGE_DOCUMENT, operate=Operate.MIGRATE, role_list=[RoleConstants.ADMIN],
12001225
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
12011226
)
1227+
SHARED_KNOWLEDGE_TAG_READ = Permission(
1228+
group=Group.SYSTEM_KNOWLEDGE_TAG, operate=Operate.READ, role_list=[RoleConstants.ADMIN],
1229+
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
1230+
)
1231+
SHARED_KNOWLEDGE_TAG_CREATE = Permission(
1232+
group=Group.SYSTEM_KNOWLEDGE_TAG, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN],
1233+
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
1234+
)
1235+
SHARED_KNOWLEDGE_TAG_EDIT = Permission(
1236+
group=Group.SYSTEM_KNOWLEDGE_TAG, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN],
1237+
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
1238+
)
1239+
SHARED_KNOWLEDGE_TAG_DELETE = Permission(
1240+
group=Group.SYSTEM_KNOWLEDGE_TAG, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN],
1241+
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
1242+
)
12021243
SHARED_KNOWLEDGE_PROBLEM_READ = Permission(
12031244
group=Group.SYSTEM_KNOWLEDGE_PROBLEM, operate=Operate.READ, role_list=[RoleConstants.ADMIN],
12041245
parent_group=[SystemGroup.SHARED_KNOWLEDGE], is_ee=settings.edition == "EE"
@@ -1427,6 +1468,22 @@ class PermissionConstants(Enum):
14271468
group=Group.SYSTEM_RES_KNOWLEDGE_PROBLEM, operate=Operate.RELATE, role_list=[RoleConstants.ADMIN],
14281469
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"
14291470
)
1471+
RESOURCE_KNOWLEDGE_TAG_READ = Permission(
1472+
group=Group.SYSTEM_RES_KNOWLEDGE_TAG, operate=Operate.READ, role_list=[RoleConstants.ADMIN],
1473+
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"
1474+
)
1475+
RESOURCE_KNOWLEDGE_TAG_CREATE = Permission(
1476+
group=Group.SYSTEM_RES_KNOWLEDGE_TAG, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN],
1477+
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"
1478+
)
1479+
RESOURCE_KNOWLEDGE_TAG_EDIT = Permission(
1480+
group=Group.SYSTEM_RES_KNOWLEDGE_TAG, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN],
1481+
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"
1482+
)
1483+
RESOURCE_KNOWLEDGE_TAG_DELETE = Permission(
1484+
group=Group.SYSTEM_RES_KNOWLEDGE_TAG, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN],
1485+
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"
1486+
)
14301487
RESOURCE_KNOWLEDGE_CHAT_USER_READ = Permission(
14311488
group=Group.SYSTEM_RES_KNOWLEDGE_CHAT_USER, operate=Operate.READ, role_list=[RoleConstants.ADMIN],
14321489
parent_group=[SystemGroup.RESOURCE_KNOWLEDGE], is_ee=settings.edition == "EE"

apps/knowledge/api/document.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,3 +535,39 @@ def get_parameters():
535535
@staticmethod
536536
def get_response():
537537
return DefaultResultSerializer
538+
539+
540+
class DocumentTagsAPI(APIMixin):
541+
@staticmethod
542+
def get_parameters():
543+
return [
544+
OpenApiParameter(
545+
name="workspace_id",
546+
description="工作空间id",
547+
type=OpenApiTypes.STR,
548+
location='path',
549+
required=True,
550+
),
551+
OpenApiParameter(
552+
name="knowledge_id",
553+
description="知识库id",
554+
type=OpenApiTypes.STR,
555+
location='path',
556+
required=True,
557+
),
558+
OpenApiParameter(
559+
name="document_id",
560+
description="文档id",
561+
type=OpenApiTypes.STR,
562+
location='path',
563+
required=True,
564+
),
565+
]
566+
567+
@staticmethod
568+
def get_request():
569+
return None
570+
571+
@staticmethod
572+
def get_response():
573+
return DefaultResultSerializer

apps/knowledge/api/tag.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from drf_spectacular.types import OpenApiTypes
2+
from drf_spectacular.utils import OpenApiParameter
3+
4+
from common.mixins.api_mixin import APIMixin
5+
from common.result import DefaultResultSerializer
6+
from knowledge.serializers.tag import TagCreateSerializer, TagEditSerializer
7+
8+
9+
class TagCreateAPI(APIMixin):
10+
@staticmethod
11+
def get_parameters():
12+
return [
13+
OpenApiParameter(
14+
name="workspace_id",
15+
description="工作空间id",
16+
type=OpenApiTypes.STR,
17+
location='path',
18+
required=True,
19+
),
20+
OpenApiParameter(
21+
name="knowledge_id",
22+
description="知识库id",
23+
type=OpenApiTypes.STR,
24+
location='path',
25+
required=True,
26+
),
27+
]
28+
29+
@staticmethod
30+
def get_request():
31+
return TagCreateSerializer
32+
33+
@staticmethod
34+
def get_response():
35+
return DefaultResultSerializer
36+
37+
38+
class TagDeleteAPI(APIMixin):
39+
@staticmethod
40+
def get_parameters():
41+
return [
42+
OpenApiParameter(
43+
name="workspace_id",
44+
description="工作空间id",
45+
type=OpenApiTypes.STR,
46+
location='path',
47+
required=True,
48+
),
49+
OpenApiParameter(
50+
name="knowledge_id",
51+
description="知识库id",
52+
type=OpenApiTypes.STR,
53+
location='path',
54+
required=True,
55+
),
56+
OpenApiParameter(
57+
name="tag_id",
58+
description="标签id",
59+
type=OpenApiTypes.STR,
60+
location='path',
61+
required=True,
62+
),
63+
]
64+
65+
@staticmethod
66+
def get_request():
67+
return None
68+
69+
@staticmethod
70+
def get_response():
71+
return DefaultResultSerializer
72+
73+
74+
class TagEditAPI(APIMixin):
75+
@staticmethod
76+
def get_parameters():
77+
return [
78+
OpenApiParameter(
79+
name="workspace_id",
80+
description="工作空间id",
81+
type=OpenApiTypes.STR,
82+
location='path',
83+
required=True,
84+
),
85+
OpenApiParameter(
86+
name="knowledge_id",
87+
description="知识库id",
88+
type=OpenApiTypes.STR,
89+
location='path',
90+
required=True,
91+
),
92+
OpenApiParameter(
93+
name="tag_id",
94+
description="标签id",
95+
type=OpenApiTypes.STR,
96+
location='path',
97+
required=True,
98+
),
99+
]
100+
101+
@staticmethod
102+
def get_request():
103+
return TagEditSerializer
104+
105+
@staticmethod
106+
def get_response():
107+
return DefaultResultSerializer
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Generated by Django 5.2.7 on 2025-10-11 07:38
2+
3+
import django.db.models.deletion
4+
import uuid_utils.compat
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('knowledge', '0002_alter_file_source_type'),
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name='Tag',
17+
fields=[
18+
('create_time', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='创建时间')),
19+
('update_time', models.DateTimeField(auto_now=True, db_index=True, verbose_name='修改时间')),
20+
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
21+
('key', models.CharField(db_index=True, max_length=64, verbose_name='标签键')),
22+
('value', models.CharField(db_index=True, max_length=128, verbose_name='标签值')),
23+
('knowledge', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='knowledge.knowledge', verbose_name='知识库')),
24+
],
25+
options={
26+
'db_table': 'tag',
27+
},
28+
),
29+
migrations.CreateModel(
30+
name='DocumentTag',
31+
fields=[
32+
('create_time', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='创建时间')),
33+
('update_time', models.DateTimeField(auto_now=True, db_index=True, verbose_name='修改时间')),
34+
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
35+
('document', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='knowledge.document', verbose_name='文档')),
36+
('tag', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='knowledge.tag', verbose_name='标签')),
37+
],
38+
options={
39+
'db_table': 'document_tag',
40+
},
41+
),
42+
migrations.AddIndex(
43+
model_name='tag',
44+
index=models.Index(fields=['knowledge', 'key'], name='tag_knowled_cba590_idx'),
45+
),
46+
migrations.AlterUniqueTogether(
47+
name='tag',
48+
unique_together={('knowledge', 'key', 'value')},
49+
),
50+
migrations.AlterUniqueTogether(
51+
name='documenttag',
52+
unique_together={('document', 'tag')},
53+
),
54+
]

apps/knowledge/models/knowledge.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,35 @@ class Document(AppModelMixin):
162162
class Meta:
163163
db_table = "document"
164164

165+
class Tag(AppModelMixin):
166+
"""
167+
标签表 - 存储标签的key-value定义
168+
"""
169+
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
170+
knowledge = models.ForeignKey(Knowledge, on_delete=models.DO_NOTHING, verbose_name="知识库", db_constraint=False)
171+
key = models.CharField(max_length=64, verbose_name="标签键", db_index=True)
172+
value = models.CharField(max_length=128, verbose_name="标签值", db_index=True)
173+
174+
class Meta:
175+
db_table = "tag"
176+
unique_together = [['knowledge', 'key', 'value']] # 在同一知识库内key-value组合唯一
177+
indexes = [
178+
models.Index(fields=['knowledge', 'key']),
179+
]
180+
181+
182+
class DocumentTag(AppModelMixin):
183+
"""
184+
文档标签关联表
185+
"""
186+
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
187+
document = models.ForeignKey(Document, on_delete=models.DO_NOTHING, verbose_name="文档", db_constraint=False)
188+
tag = models.ForeignKey(Tag, on_delete=models.DO_NOTHING, verbose_name="标签", db_constraint=False)
189+
190+
class Meta:
191+
db_table = "document_tag"
192+
unique_together = [['document', 'tag']] # 文档和标签的组合唯一
193+
165194

166195
class Paragraph(AppModelMixin):
167196
"""

0 commit comments

Comments
 (0)