Skip to content

Commit 633c005

Browse files
authored
Pr@main@problem manage (#37)
* feat: 问题模块
1 parent c67f463 commit 633c005

File tree

27 files changed

+1405
-119
lines changed

27 files changed

+1405
-119
lines changed

apps/dataset/serializers/paragraph_serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def is_valid(self, *, raise_exception=True):
218218
def association(self, with_valid=True, with_embedding=True):
219219
if with_valid:
220220
self.is_valid(raise_exception=True)
221-
problem = QuerySet(Problem).filter(id=self.data.get("problem_id"))
221+
problem = QuerySet(Problem).filter(id=self.data.get("problem_id")).first()
222222
problem_paragraph_mapping = ProblemParagraphMapping(id=uuid.uuid1(),
223223
document_id=self.data.get('document_id'),
224224
paragraph_id=self.data.get('paragraph_id'),

apps/dataset/serializers/problem_serializers.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"""
99
import os
1010
import uuid
11-
from typing import Dict
11+
from typing import Dict, List
1212

1313
from django.db import transaction
1414
from django.db.models import QuerySet
@@ -83,6 +83,7 @@ def get_query_set(self):
8383
**{'dataset_id': self.data.get('dataset_id')})
8484
if 'content' in self.data:
8585
query_set = query_set.filter(**{'content__contains': self.data.get('content')})
86+
query_set = query_set.order_by("-create_time")
8687
return query_set
8788

8889
def list(self):
@@ -95,6 +96,22 @@ def page(self, current_page, page_size):
9596
return native_page_search(current_page, page_size, query_set, select_string=get_file_content(
9697
os.path.join(PROJECT_DIR, "apps", "dataset", 'sql', 'list_problem.sql')))
9798

99+
class BatchOperate(serializers.Serializer):
100+
dataset_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("知识库id"))
101+
102+
def delete(self, problem_id_list: List, with_valid=True):
103+
if with_valid:
104+
self.is_valid(raise_exception=True)
105+
dataset_id = self.data.get('dataset_id')
106+
problem_paragraph_mapping_list = QuerySet(ProblemParagraphMapping).filter(
107+
dataset_id=dataset_id,
108+
problem_id__in=problem_id_list)
109+
source_ids = [row.id for row in problem_paragraph_mapping_list]
110+
problem_paragraph_mapping_list.delete()
111+
QuerySet(Problem).filter(id__in=problem_id_list).delete()
112+
ListenerManagement.delete_embedding_by_source_ids_signal.send(source_ids)
113+
return True
114+
98115
class Operate(serializers.Serializer):
99116
dataset_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("知识库id"))
100117

@@ -105,6 +122,8 @@ def list_paragraph(self, with_valid=True):
105122
self.is_valid(raise_exception=True)
106123
problem_paragraph_mapping = QuerySet(ProblemParagraphMapping).filter(dataset_id=self.data.get("dataset_id"),
107124
problem_id=self.data.get("problem_id"))
125+
if problem_paragraph_mapping is None or len(problem_paragraph_mapping)==0:
126+
return []
108127
return native_search(
109128
QuerySet(Paragraph).filter(id__in=[row.paragraph_id for row in problem_paragraph_mapping]),
110129
select_string=get_file_content(
@@ -123,6 +142,7 @@ def delete(self, with_valid=True):
123142
dataset_id=self.data.get('dataset_id'),
124143
problem_id=self.data.get('problem_id'))
125144
source_ids = [row.id for row in problem_paragraph_mapping_list]
145+
problem_paragraph_mapping_list.delete()
126146
QuerySet(Problem).filter(id=self.data.get('problem_id')).delete()
127147
ListenerManagement.delete_embedding_by_source_ids_signal.send(source_ids)
128148
return True

apps/dataset/swagger_api/problem_api.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ def get_response_body_api():
3636
}
3737
)
3838

39+
class BatchOperate(ApiMixin):
40+
@staticmethod
41+
def get_request_params_api():
42+
return [openapi.Parameter(name='dataset_id',
43+
in_=openapi.IN_PATH,
44+
type=openapi.TYPE_STRING,
45+
required=True,
46+
description='知识库id'),
47+
]
48+
49+
@staticmethod
50+
def get_request_body_api():
51+
return openapi.Schema(
52+
title="问题id列表",
53+
description="问题id列表",
54+
type=openapi.TYPE_ARRAY,
55+
items=openapi.Schema(type=openapi.TYPE_STRING)
56+
)
57+
3958
class Operate(ApiMixin):
4059
@staticmethod
4160
def get_request_params_api():

apps/dataset/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
'dataset/<str:dataset_id>/document/<str:document_id>/paragraph/<str:paragraph_id>/problem/<str:problem_id>/association',
3737
views.Paragraph.Problem.Association.as_view()),
3838
path('dataset/<str:dataset_id>/problem', views.Problem.as_view()),
39+
path('dataset/<str:dataset_id>/problem/_batch', views.Problem.OperateBatch.as_view()),
3940
path('dataset/<str:dataset_id>/problem/<int:current_page>/<int:page_size>', views.Problem.Page.as_view()),
4041
path('dataset/<str:dataset_id>/problem/<str:problem_id>', views.Problem.Operate.as_view()),
4142
path('dataset/<str:dataset_id>/problem/<str:problem_id>/paragraph', views.Problem.Paragraph.as_view()),

apps/dataset/views/problem.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get(self, request: Request, dataset_id: str):
5151
def post(self, request: Request, dataset_id: str):
5252
return result.success(
5353
ProblemSerializers.Create(
54-
data={'dataset_id': dataset_id, 'problem_list': request.query_params.get('problem_list')}).save())
54+
data={'dataset_id': dataset_id, 'problem_list': request.data}).batch())
5555

5656
class Paragraph(APIView):
5757
authentication_classes = [TokenAuth]
@@ -70,6 +70,24 @@ def get(self, request: Request, dataset_id: str, problem_id: str):
7070
data={**query_params_to_single_dict(request.query_params), 'dataset_id': dataset_id,
7171
'problem_id': problem_id}).list_paragraph())
7272

73+
class OperateBatch(APIView):
74+
authentication_classes = [TokenAuth]
75+
76+
@action(methods=['DELETE'], detail=False)
77+
@swagger_auto_schema(operation_summary="批量删除问题",
78+
operation_id="批量删除问题",
79+
request_body=
80+
ProblemApi.BatchOperate.get_request_body_api(),
81+
manual_parameters=ProblemApi.BatchOperate.get_request_params_api(),
82+
responses=result.get_default_response(),
83+
tags=["知识库/文档/段落/问题"])
84+
@has_permissions(
85+
lambda r, k: Permission(group=Group.DATASET, operate=Operate.MANAGE,
86+
dynamic_tag=k.get('dataset_id')))
87+
def delete(self, request: Request, dataset_id: str):
88+
return result.success(
89+
ProblemSerializers.BatchOperate(data={'dataset_id': dataset_id}).delete(request.data))
90+
7391
class Operate(APIView):
7492
authentication_classes = [TokenAuth]
7593

ui/src/api/paragraph.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,55 @@ const postProblem: (
129129
dataset_id: string,
130130
document_id: string,
131131
paragraph_id: string,
132-
data: any
133-
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, data: any) => {
132+
data: any,
133+
loading?: Ref<boolean>
134+
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, data: any, loading) => {
134135
return post(
135136
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem`,
136-
data
137+
data,
138+
{},
139+
loading
140+
)
141+
}
142+
/**
143+
*
144+
* @param dataset_id 数据集id
145+
* @param document_id 文档id
146+
* @param paragraph_id 段落id
147+
* @param problem_id 问题id
148+
* @param loading 加载器
149+
* @returns
150+
*/
151+
const associationProblem: (
152+
dataset_id: string,
153+
document_id: string,
154+
paragraph_id: string,
155+
problem_id: string,
156+
loading?: Ref<boolean>
157+
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, problem_id, loading) => {
158+
return put(
159+
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/association`,
160+
{},
161+
{},
162+
loading
137163
)
138164
}
139165
/**
140166
* 解除关联问题
141167
* @param 参数 dataset_id, document_id, paragraph_id,problem_id
142168
*/
143-
const delProblem: (
169+
const disassociationProblem: (
144170
dataset_id: string,
145171
document_id: string,
146172
paragraph_id: string,
147-
problem_id: string
148-
) => Promise<Result<boolean>> = (dataset_id, document_id, paragraph_id, problem_id) => {
173+
problem_id: string,
174+
loading?: Ref<boolean>
175+
) => Promise<Result<boolean>> = (dataset_id, document_id, paragraph_id, problem_id, loading) => {
149176
return put(
150-
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/un_association`
177+
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/un_association`,
178+
{},
179+
{},
180+
loading
151181
)
152182
}
153183

@@ -158,5 +188,6 @@ export default {
158188
postParagraph,
159189
getProblem,
160190
postProblem,
161-
delProblem
191+
disassociationProblem,
192+
associationProblem
162193
}

ui/src/api/problem.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { Result } from '@/request/Result'
2+
import { get, post, del, put } from '@/request/index'
3+
import type { Ref } from 'vue'
4+
import type { KeyValue } from '@/api/type/common'
5+
import type { pageRequest } from '@/api/type/common'
6+
const prefix = '/dataset'
7+
8+
/**
9+
* 文档分页列表
10+
* @param 参数 dataset_id,
11+
* page {
12+
"current_page": "string",
13+
"page_size": "string",
14+
}
15+
* query {
16+
"content": "string",
17+
}
18+
*/
19+
20+
const getProblems: (
21+
dataset_id: string,
22+
page: pageRequest,
23+
param: any,
24+
loading?: Ref<boolean>
25+
) => Promise<Result<any>> = (dataset_id, page, param, loading) => {
26+
return get(
27+
`${prefix}/${dataset_id}/problem/${page.current_page}/${page.page_size}`,
28+
param,
29+
loading
30+
)
31+
}
32+
33+
/**
34+
* 创建问题
35+
* @param 参数 dataset_id
36+
* data: array[string]
37+
*/
38+
const postProblems: (
39+
dataset_id: string,
40+
data: any,
41+
loading?: Ref<boolean>
42+
) => Promise<Result<any>> = (dataset_id, data, loading) => {
43+
return post(`${prefix}/${dataset_id}/problem`, data, undefined, loading)
44+
}
45+
46+
/**
47+
* 删除问题
48+
* @param 参数 dataset_id, problem_id,
49+
*/
50+
const delProblems: (
51+
dataset_id: string,
52+
problem_id: string,
53+
loading?: Ref<boolean>
54+
) => Promise<Result<boolean>> = (dataset_id, problem_id, loading) => {
55+
return del(`${prefix}/${dataset_id}/problem/${problem_id}`, loading)
56+
}
57+
58+
/**
59+
* 批量删除问题
60+
* @param 参数 dataset_id,
61+
*/
62+
const delMulProblem: (
63+
dataset_id: string,
64+
data: any,
65+
loading?: Ref<boolean>
66+
) => Promise<Result<boolean>> = (dataset_id, data, loading) => {
67+
return del(`${prefix}/${dataset_id}/problem/_batch`, undefined, data, loading)
68+
}
69+
70+
/**
71+
* 修改问题
72+
* @param 参数
73+
* dataset_id, problem_id,
74+
* {
75+
"content": "string",
76+
}
77+
*/
78+
const putProblems: (
79+
dataset_id: string,
80+
problem_id: string,
81+
data: any,
82+
loading?: Ref<boolean>
83+
) => Promise<Result<any>> = (dataset_id, problem_id, data: any, loading) => {
84+
return put(`${prefix}/${dataset_id}/problem/${problem_id}`, data, undefined, loading)
85+
}
86+
87+
/**
88+
* 问题详情
89+
* @param 参数
90+
* dataset_id, problem_id,
91+
*/
92+
const getDetailProblems: (
93+
dataset_id: string,
94+
problem_id: string,
95+
loading?: Ref<boolean>
96+
) => Promise<Result<any>> = (dataset_id, problem_id, loading) => {
97+
return get(`${prefix}/${dataset_id}/problem/${problem_id}/paragraph`, undefined, loading)
98+
}
99+
100+
export default {
101+
getProblems,
102+
postProblems,
103+
delProblems,
104+
putProblems,
105+
getDetailProblems,
106+
delMulProblem
107+
}

ui/src/components/ai-chat/ParagraphSourceDialog.vue

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,4 @@ defineExpose({ open })
102102
height: calc(100vh - 260px);
103103
}
104104
}
105-
.paragraph-source-card {
106-
height: 210px;
107-
width: 100%;
108-
.active-button {
109-
position: absolute;
110-
right: 16px;
111-
top: 16px;
112-
}
113-
}
114105
</style>

ui/src/components/app-table/index.vue

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
<el-input
77
ref="quickInputRef"
88
v-model="inputValue"
9-
placeholder="请输入文档名称"
9+
:placeholder="`请输入${quickCreateName}`"
1010
class="w-500 mr-12"
1111
autofocus
12+
:maxlength="quickCreateMaxlength"
13+
:show-word-limit="quickCreateMaxlength ? true : false"
1214
/>
1315

1416
<el-button type="primary" @click="submitHandle" :disabled="loading">创建</el-button>
@@ -17,7 +19,7 @@
1719
<div v-else @click="quickCreateHandel" class="w-full">
1820
<el-button type="primary" link class="quich-button">
1921
<el-icon><Plus /></el-icon>
20-
<span class="ml-4">快速创建空白文档</span>
22+
<span class="ml-4">{{ quickCreatePlaceholder }}</span>
2123
</el-button>
2224
</div>
2325
</template>
@@ -51,6 +53,18 @@ const props = defineProps({
5153
quickCreate: {
5254
type: Boolean,
5355
default: false
56+
},
57+
quickCreateName: {
58+
type: String,
59+
default: '文档名称'
60+
},
61+
quickCreatePlaceholder: {
62+
type: String,
63+
default: '快速创建空白文档'
64+
},
65+
quickCreateMaxlength: {
66+
type: Number,
67+
default: () => 0
5468
}
5569
})
5670
const emit = defineEmits(['changePage', 'sizeChange', 'creatQuick'])
@@ -81,7 +95,7 @@ function submitHandle() {
8195
loading.value = false
8296
}, 200)
8397
} else {
84-
MsgError('文件名称不能为空!')
98+
MsgError(`${props.quickCreateName}不能为空!`)
8599
}
86100
}
87101

0 commit comments

Comments
 (0)