feat: enhance search functionality with dynamic scope selection and improved UI
parent
3ba1a0be7b
commit
947152ed33
|
|
@ -7,6 +7,8 @@ from django.db.models import QuerySet
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from application.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.search_document_node.i_search_document_node import ISearchDocumentStepNode
|
from application.flow.step_node.search_document_node.i_search_document_node import ISearchDocumentStepNode
|
||||||
|
from common.constants.permission_constants import RoleConstants
|
||||||
|
from common.database_model_manage.database_model_manage import DatabaseModelManage
|
||||||
from knowledge.models import Document, DocumentTag, Knowledge
|
from knowledge.models import Document, DocumentTag, Knowledge
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,6 +41,23 @@ class BaseSearchDocumentNode(ISearchDocumentStepNode):
|
||||||
knowledge_id__in=self.get_reference_content(search_scope_reference)
|
knowledge_id__in=self.get_reference_content(search_scope_reference)
|
||||||
).values_list('id', flat=True)
|
).values_list('id', flat=True)
|
||||||
|
|
||||||
|
# 权限过滤
|
||||||
|
get_knowledge_list_of_authorized = DatabaseModelManage.get_model('get_knowledge_list_of_authorized')
|
||||||
|
chat_user_type = self.workflow_manage.get_body().get('chat_user_type')
|
||||||
|
|
||||||
|
if get_knowledge_list_of_authorized is not None and RoleConstants.CHAT_USER.value.name == chat_user_type:
|
||||||
|
# 获取授权的知识库ID列表
|
||||||
|
authorized_knowledge_ids = get_knowledge_list_of_authorized(
|
||||||
|
self.workflow_manage.get_body().get('chat_user_id'),
|
||||||
|
knowledge_id_list
|
||||||
|
)
|
||||||
|
|
||||||
|
# 过滤出授权知识库下的文档
|
||||||
|
document_id_list = QuerySet(Document).filter(
|
||||||
|
id__in=document_id_list,
|
||||||
|
knowledge_id__in=authorized_knowledge_ids
|
||||||
|
).values_list('id', flat=True)
|
||||||
|
|
||||||
if search_mode == 'auto': # 通过问题自动检索
|
if search_mode == 'auto': # 通过问题自动检索
|
||||||
matched_doc_ids = self.handle_auto_tags(document_id_list, question_reference)
|
matched_doc_ids = self.handle_auto_tags(document_id_list, question_reference)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,12 @@ import re
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from application.flow.i_step_node import INode, NodeResult
|
||||||
from common.utils.common import flat_map
|
from common.utils.common import flat_map
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class DatasetSettingSerializer(serializers.Serializer):
|
class DatasetSettingSerializer(serializers.Serializer):
|
||||||
# 需要查询的条数
|
# 需要查询的条数
|
||||||
|
|
@ -43,6 +42,17 @@ class SearchDatasetStepNodeSerializer(serializers.Serializer):
|
||||||
|
|
||||||
show_knowledge = serializers.BooleanField(required=True,
|
show_knowledge = serializers.BooleanField(required=True,
|
||||||
label=_("The results are displayed in the knowledge sources"))
|
label=_("The results are displayed in the knowledge sources"))
|
||||||
|
search_scope_type = serializers.ChoiceField(
|
||||||
|
required=False, choices=['custom', 'referencing'], label=_("search scope type"),
|
||||||
|
allow_null=True, default='custom'
|
||||||
|
)
|
||||||
|
search_scope_source = serializers.ChoiceField(
|
||||||
|
required=False, choices=['document', 'knowledge'],
|
||||||
|
label=_("search scope variable type"), default='knowledge'
|
||||||
|
)
|
||||||
|
search_scope_reference = serializers.ListField(
|
||||||
|
required=False, label=_("search scope variable"), default=list
|
||||||
|
)
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
|
|
@ -76,7 +86,9 @@ class ISearchKnowledgeStepNode(INode):
|
||||||
return self.execute(**self.node_params_serializer.data, question=str(question),
|
return self.execute(**self.node_params_serializer.data, question=str(question),
|
||||||
exclude_paragraph_id_list=exclude_paragraph_id_list)
|
exclude_paragraph_id_list=exclude_paragraph_id_list)
|
||||||
|
|
||||||
def execute(self, dataset_id_list, dataset_setting, question, show_knowledge,
|
def execute(self, dataset_id_list, dataset_setting, question, show_knowledge, search_scope_type,
|
||||||
|
search_scope_source,
|
||||||
|
search_scope_reference,
|
||||||
exclude_paragraph_id_list=None,
|
exclude_paragraph_id_list=None,
|
||||||
**kwargs) -> NodeResult:
|
**kwargs) -> NodeResult:
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,27 @@ class BaseSearchKnowledgeNode(ISearchKnowledgeStepNode):
|
||||||
result])[0:knowledge_setting.get('max_paragraph_char_number', 5000)]
|
result])[0:knowledge_setting.get('max_paragraph_char_number', 5000)]
|
||||||
self.context['directly_return'] = directly_return
|
self.context['directly_return'] = directly_return
|
||||||
|
|
||||||
def execute(self, knowledge_id_list, knowledge_setting, question, show_knowledge,
|
def get_reference_content(self, fields: List[str]):
|
||||||
|
return self.workflow_manage.get_reference_field(fields[0], fields[1:])
|
||||||
|
|
||||||
|
def execute(self, knowledge_id_list, knowledge_setting, question, show_knowledge, search_scope_type,
|
||||||
|
search_scope_source,
|
||||||
|
search_scope_reference,
|
||||||
exclude_paragraph_id_list=None,
|
exclude_paragraph_id_list=None,
|
||||||
**kwargs) -> NodeResult:
|
**kwargs) -> NodeResult:
|
||||||
self.context['question'] = question
|
self.context['question'] = question
|
||||||
self.context['show_knowledge'] = show_knowledge
|
self.context['show_knowledge'] = show_knowledge
|
||||||
|
|
||||||
|
if search_scope_type == 'referencing': # 引用上一步知识库/文档
|
||||||
|
if search_scope_source == 'knowledge': # 知识库
|
||||||
|
knowledge_id_list = self.get_reference_content(search_scope_reference)
|
||||||
|
else: # 文档
|
||||||
|
knowledge_id_list = QuerySet(Document).filter(
|
||||||
|
id__in=self.get_reference_content(search_scope_reference)
|
||||||
|
).values_list(
|
||||||
|
'knowledge_id', flat=True
|
||||||
|
).distinct()
|
||||||
|
|
||||||
get_knowledge_list_of_authorized = DatabaseModelManage.get_model('get_knowledge_list_of_authorized')
|
get_knowledge_list_of_authorized = DatabaseModelManage.get_model('get_knowledge_list_of_authorized')
|
||||||
chat_user_type = self.workflow_manage.get_body().get('chat_user_type')
|
chat_user_type = self.workflow_manage.get_body().get('chat_user_type')
|
||||||
if get_knowledge_list_of_authorized is not None and RoleConstants.CHAT_USER.value.name == chat_user_type:
|
if get_knowledge_list_of_authorized is not None and RoleConstants.CHAT_USER.value.name == chat_user_type:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
{{ $t('views.applicationWorkflow.nodes.searchDocumentNode.selectKnowledge') }}
|
{{ $t('views.applicationWorkflow.nodes.searchDocumentNode.selectKnowledge') }}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<el-button type="primary" link @click="openKnowledgeDialog">
|
<el-button v-if="form_data.search_scope_type === 'custom'"
|
||||||
|
type="primary" link @click="openKnowledgeDialog"
|
||||||
|
>
|
||||||
<AppIcon iconName="app-add-outlined"></AppIcon>
|
<AppIcon iconName="app-add-outlined"></AppIcon>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-select
|
<el-select
|
||||||
|
|
@ -78,9 +80,6 @@
|
||||||
{{ $t('选择变量') }}
|
{{ $t('选择变量') }}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<el-button type="primary" link @click="openKnowledgeDialog">
|
|
||||||
<AppIcon iconName="app-add-outlined"></AppIcon>
|
|
||||||
</el-button>
|
|
||||||
<el-select
|
<el-select
|
||||||
:teleported="false"
|
:teleported="false"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
@ -89,11 +88,11 @@
|
||||||
@change="form_data.search_scope_reference = []"
|
@change="form_data.search_scope_reference = []"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
:label="$t('知识库列表')"
|
:label="$t('views.applicationWorkflow.nodes.searchDocumentNode.knowledge_list')"
|
||||||
value="knowledge"
|
value="knowledge"
|
||||||
/>
|
/>
|
||||||
<el-option
|
<el-option
|
||||||
:label="$t('文档列表')"
|
:label="$t('views.applicationWorkflow.nodes.searchDocumentNode.document_list')"
|
||||||
value="document"
|
value="document"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,31 @@
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex-between">
|
<div class="flex-between">
|
||||||
<span>{{ $t('views.chatLog.selectKnowledge') }}</span>
|
<span>{{ $t('views.chatLog.selectKnowledge') }}</span>
|
||||||
<el-button type="primary" link @click="openknowledgeDialog">
|
<span>
|
||||||
<AppIcon iconName="app-add-outlined"></AppIcon>
|
<el-button v-if="form_data.search_scope_type === 'custom'"
|
||||||
</el-button>
|
type="primary" link @click="openknowledgeDialog"
|
||||||
|
>
|
||||||
|
<AppIcon iconName="app-add-outlined"></AppIcon>
|
||||||
|
</el-button>
|
||||||
|
<el-select
|
||||||
|
:teleported="false"
|
||||||
|
size="small"
|
||||||
|
v-model="form_data.search_scope_type"
|
||||||
|
style="width: 85px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
:label="$t('views.applicationWorkflow.nodes.searchDocumentNode.custom')"
|
||||||
|
value="custom"
|
||||||
|
/>
|
||||||
|
<el-option
|
||||||
|
:label="$t('views.applicationWorkflow.variable.Referencing')"
|
||||||
|
value="referencing"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="w-full">
|
<div class="w-full" v-if="form_data.search_scope_type === 'custom'">
|
||||||
<el-text type="info" v-if="form_data.knowledge_id_list?.length === 0">
|
<el-text type="info" v-if="form_data.knowledge_id_list?.length === 0">
|
||||||
{{ $t('views.application.form.relatedKnowledge.placeholder') }}
|
{{ $t('views.application.form.relatedKnowledge.placeholder') }}
|
||||||
</el-text>
|
</el-text>
|
||||||
|
|
@ -42,6 +61,49 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w-full" v-else>
|
||||||
|
<el-form-item
|
||||||
|
prop="search_scope_reference"
|
||||||
|
:rules="{
|
||||||
|
message: $t('views.applicationWorkflow.variable.placeholder'),
|
||||||
|
trigger: 'blur',
|
||||||
|
required: true,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div class="flex-between">
|
||||||
|
<span>
|
||||||
|
{{ $t('选择变量') }}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<el-select
|
||||||
|
:teleported="false"
|
||||||
|
size="small"
|
||||||
|
v-model="form_data.search_scope_source"
|
||||||
|
style="width: 95px"
|
||||||
|
@change="form_data.search_scope_reference = []"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
:label="$t('views.applicationWorkflow.nodes.searchDocumentNode.knowledge_list')"
|
||||||
|
value="knowledge"
|
||||||
|
/>
|
||||||
|
<el-option
|
||||||
|
:label="$t('views.applicationWorkflow.nodes.searchDocumentNode.document_list')"
|
||||||
|
value="document"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<NodeCascader
|
||||||
|
ref="nodeCascaderRef"
|
||||||
|
:nodeModel="nodeModel"
|
||||||
|
class="w-full"
|
||||||
|
:placeholder="$t('views.applicationWorkflow.variable.placeholder')"
|
||||||
|
v-model="form_data.search_scope_reference"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('views.applicationWorkflow.nodes.searchKnowledgeNode.searchParam')"
|
:label="$t('views.applicationWorkflow.nodes.searchKnowledgeNode.searchParam')"
|
||||||
|
|
@ -142,6 +204,7 @@ import type { FormInstance } from 'element-plus'
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { relatedObject } from '@/utils/array'
|
import { relatedObject } from '@/utils/array'
|
||||||
import { SearchMode } from '@/enums/application'
|
import { SearchMode } from '@/enums/application'
|
||||||
|
import AppIcon from "@/components/app-icon/AppIcon.vue";
|
||||||
|
|
||||||
const props = defineProps<{ nodeModel: any }>()
|
const props = defineProps<{ nodeModel: any }>()
|
||||||
const nodeCascaderRef = ref()
|
const nodeCascaderRef = ref()
|
||||||
|
|
@ -155,6 +218,9 @@ const form = {
|
||||||
},
|
},
|
||||||
question_reference_address: [],
|
question_reference_address: [],
|
||||||
show_knowledge: false,
|
show_knowledge: false,
|
||||||
|
search_scope_type: 'custom',
|
||||||
|
search_scope_source: 'knowledge',
|
||||||
|
search_scope_reference: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const form_data = computed({
|
const form_data = computed({
|
||||||
|
|
@ -221,6 +287,15 @@ onMounted(() => {
|
||||||
form_data.value.show_knowledge = form_data.value.show_knowledge
|
form_data.value.show_knowledge = form_data.value.show_knowledge
|
||||||
? form_data.value.show_knowledge
|
? form_data.value.show_knowledge
|
||||||
: false
|
: false
|
||||||
|
form_data.value.search_scope_type = form_data.value.search_scope_type
|
||||||
|
? form_data.value.search_scope_type
|
||||||
|
: 'custom'
|
||||||
|
form_data.value.search_scope_source = form_data.value.search_scope_source
|
||||||
|
? form_data.value.search_scope_source
|
||||||
|
: 'knowledge'
|
||||||
|
form_data.value.knowledge_id_list = form_data.value.knowledge_id_list
|
||||||
|
? form_data.value.knowledge_id_list
|
||||||
|
: []
|
||||||
set(props.nodeModel, 'validate', validate)
|
set(props.nodeModel, 'validate', validate)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue