Compare commits

...

8 Commits
main ... v1.3.1

Author SHA1 Message Date
shaohuzhang1 499fc90f2f fix: 修复在线知识库爬取文档名超过128个字符报错 #706 (#778)
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Typos Check / Spell Check with Typos (push) Has been cancelled
(cherry picked from commit 3249811428)
2024-07-16 11:00:40 +08:00
shaohuzhang1 56a7b7b524 fix: 修复换个答案在工作流中一直生效问题 (#766)
(cherry picked from commit 5308ad9c89)
2024-07-16 10:38:55 +08:00
shaohuzhang1 28ed136f2d fix: 修复【问答页面】- 当应用关联的知识库中含有禁用状态的文档时,问答时点击换个答案不会换一批命中分段 #759 (#765)
(cherry picked from commit be49147d4a)
2024-07-16 10:38:52 +08:00
shaohuzhang1 16f490567e fix: 修复返回的分段结果排序不对,不是按照命中高低顺序排序[BUG] #746 (#770)
(cherry picked from commit d554e0ae88)
2024-07-16 10:37:24 +08:00
wxg0103 a5ca97ac06 fix: 修复判断器删除其中一个条件后,前端序号未更新的缺陷
https://github.com/1Panel-dev/MaxKB/issues/753
(cherry picked from commit 1eace87463)
2024-07-16 10:36:46 +08:00
wangdan-fit2cloud 601d19d7ad fix: 修复打开doc/chat显示404(#747)
(cherry picked from commit a914a7d1c0)
2024-07-16 10:35:07 +08:00
shaohuzhang1 5e7879c582 fix: 修复AI编排中,指定回复的内容,不能在任务流程中传递 #726 (#728)
(cherry picked from commit c1823110d9)
2024-07-16 09:56:12 +08:00
wangdan-fit2cloud 0ce3fc5cfa feat: 【应用编排】修复选择器滚动条问题
(cherry picked from commit fb4722cdd7)
2024-07-16 09:55:47 +08:00
11 changed files with 57 additions and 12 deletions

View File

@ -105,12 +105,14 @@ class FlowParamsSerializer(serializers.Serializer):
chat_record_id = serializers.CharField(required=True, error_messages=ErrMessage.char("对话记录id"))
stream = serializers.BooleanField(required=True, error_messages=ErrMessage.base("流式输出"))
stream = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("流式输出"))
client_id = serializers.CharField(required=False, error_messages=ErrMessage.char("客户端id"))
client_type = serializers.CharField(required=False, error_messages=ErrMessage.char("客户端类型"))
re_chat = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("换个答案"))
class INode:
def __init__(self, node, workflow_params, workflow_manage):

View File

@ -65,10 +65,10 @@ class BaseReplyNode(IReplyNode):
else:
result = self.generate_reply_content(content)
if stream:
return NodeResult({'result': iter([AIMessageChunk(content=result)])}, {},
return NodeResult({'result': iter([AIMessageChunk(content=result)]), 'answer': result}, {},
_to_response=to_stream_response)
else:
return NodeResult({'result': AIMessage(content=result)}, {}, _to_response=to_response)
return NodeResult({'result': AIMessage(content=result), 'answer': result}, {}, _to_response=to_response)
def generate_reply_content(self, prompt):
return self.workflow_manage.generate_prompt(prompt)

View File

@ -13,6 +13,7 @@ from django.core import validators
from rest_framework import serializers
from application.flow.i_step_node import INode, NodeResult
from common.util.common import flat_map
from common.util.field_message import ErrMessage
@ -43,6 +44,13 @@ class SearchDatasetStepNodeSerializer(serializers.Serializer):
super().is_valid(raise_exception=True)
def get_paragraph_list(chat_record, node_id):
return flat_map([chat_record.details[key].get('paragraph_list', []) for key in chat_record.details if
(chat_record.details[
key].get('type', '') == 'search-dataset-node') and chat_record.details[key].get(
'paragraph_list', []) is not None and key == node_id])
class ISearchDatasetStepNode(INode):
type = 'search-dataset-node'
@ -53,7 +61,16 @@ class ISearchDatasetStepNode(INode):
question = self.workflow_manage.get_reference_field(
self.node_params_serializer.data.get('question_reference_address')[0],
self.node_params_serializer.data.get('question_reference_address')[1:])
return self.execute(**self.node_params_serializer.data, question=str(question), exclude_paragraph_id_list=[])
exclude_paragraph_id_list = []
if self.flow_params_serializer.data.get('re_chat', False):
history_chat_record = self.flow_params_serializer.data.get('history_chat_record', [])
paragraph_id_list = [p.get('id') for p in flat_map(
[get_paragraph_list(chat_record, self.node.id) for chat_record in history_chat_record if
chat_record.problem_text == question])]
exclude_paragraph_id_list = list(set(paragraph_id_list))
return self.execute(**self.node_params_serializer.data, question=str(question),
exclude_paragraph_id_list=exclude_paragraph_id_list)
def execute(self, dataset_id_list, dataset_setting, question,
exclude_paragraph_id_list=None,

View File

@ -40,6 +40,7 @@ class BaseSearchDatasetNode(ISearchDatasetStepNode):
return NodeResult({'paragraph_list': [], 'is_hit_handling_method': []}, {})
paragraph_list = self.list_paragraph(embedding_list, vector)
result = [self.reset_paragraph(paragraph, embedding_list) for paragraph in paragraph_list]
result = sorted(result, key=lambda p: p.get('similarity'), reverse=True)
return NodeResult({'paragraph_list': result,
'is_hit_handling_method_list': [row for row in result if row.get('is_hit_handling_method')],
'data': '\n'.join([paragraph.get('content') for paragraph in paragraph_list]),

View File

@ -576,6 +576,8 @@ class ApplicationSerializer(serializers.Serializer):
'dataset_id_list': dataset_id_list}
def get_search_node(self, work_flow):
if work_flow is None:
return []
return [node for node in work_flow.get('nodes', []) if node.get('type', '') == 'search-dataset-node']
def update_search_node(self, work_flow, user_dataset_id_list: List):

View File

@ -656,13 +656,13 @@ class DocumentSerializers(ApiMixin, serializers.Serializer):
paragraphs = get_split_model('web.md').parse(response.content)
# 插入
DocumentSerializers.Create(data={'dataset_id': dataset_id}).save(
{'name': source_url, 'paragraphs': paragraphs,
{'name': source_url[0:128], 'paragraphs': paragraphs,
'meta': {'source_url': source_url, 'selector': selector},
'type': Type.web}, with_valid=True)
except Exception as e:
logging.getLogger("max_kb_error").error(f'{str(e)}:{traceback.format_exc()}')
else:
Document(name=source_url,
Document(name=source_url[0:128],
meta={'source_url': source_url, 'selector': selector},
type=Type.web,
char_length=0,

View File

@ -105,9 +105,9 @@ class PGVector(BaseVectorStore):
return []
query_set = QuerySet(Embedding).filter(dataset_id__in=dataset_id_list, is_active=is_active)
if exclude_document_id_list is not None and len(exclude_document_id_list) > 0:
exclude_dict.__setitem__('document_id__in', exclude_document_id_list)
query_set = query_set.exclude(document_id__in=exclude_document_id_list)
if exclude_paragraph_list is not None and len(exclude_paragraph_list) > 0:
exclude_dict.__setitem__('paragraph_id__in', exclude_paragraph_list)
query_set = query_set.exclude(paragraph_id__in=exclude_paragraph_list)
query_set = query_set.exclude(**exclude_dict)
for search_handle in search_handle_list:
if search_handle.support(search_mode):

View File

@ -150,7 +150,7 @@ const {
params: { id }
} = route as any
const apiUrl = window.location.origin + '/doc/chat'
const apiUrl = window.location.origin + '/doc/chat/'
const EditAvatarDialogRef = ref()
const LimitDialogRef = ref()

View File

@ -15,7 +15,7 @@
</div>
</template>
<div class="border-t mt-16">
<div class="mt-16">
<ul>
<li class="flex mt-16">
<el-text type="info">模型类型</el-text>
@ -176,7 +176,7 @@ onBeforeUnmount(() => {
</script>
<style lang="scss" scoped>
.model-card {
min-height: 153px;
min-height: 135px;
min-width: auto;
.operation-button {
position: absolute;

View File

@ -1,5 +1,8 @@
<template>
<el-cascader
@wheel="wheel"
@keydown="isKeyDown = true"
@keyup="isKeyDown = false"
:teleported="false"
:options="options"
@visible-change="visibleChange"
@ -8,7 +11,12 @@
separator=" > "
>
<template #default="{ node, data }">
<span class="flex align-center">
<span
class="flex align-center"
@wheel="wheel"
@keydown="isKeyDown = true"
@keyup="isKeyDown = false"
>
<component :is="iconComponent(`${data.type}-icon`)" class="mr-8" :size="18" />{{
data.label
}}</span
@ -34,6 +42,15 @@ const data = computed({
}
})
const options = ref<Array<any>>([])
const isKeyDown = ref(false)
const wheel = (e: any) => {
if (isKeyDown.value) {
e.preventDefault()
} else {
e.stopPropagation()
return true
}
}
function visibleChange(bool: boolean) {
if (bool) {

View File

@ -277,6 +277,12 @@ function deleteCondition(index: number, cIndex: number) {
.map((item: any) => item.id)
)
refreshBranchAnchor(list, false)
list.forEach((item: any, index: number) => {
if (item.type === 'ELSE IF ' + (index + 1)) {
item.type = 'ELSE IF ' + index
}
})
}
set(props.nodeModel.properties.node_data, 'branch', list)
}