diff --git a/README.md b/README.md
index 93bc7ae81..372803d56 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,8 @@ docker run -d --name=maxkb --restart=always -p 8080:8080 -v C:/maxkb:/var/lib/po
- 你也可以通过 [1Panel 应用商店](https://apps.fit2cloud.com/1panel) 快速部署 MaxKB;
- 如果是内网环境,推荐使用 [离线安装包](https://community.fit2cloud.com/#/products/maxkb/downloads) 进行安装部署;
-- MaxKB 产品版本分为社区版和专业版,详情请参见:[MaxKB 产品版本对比](https://maxkb.cn/pricing.html)。
+- MaxKB 产品版本分为社区版和专业版,详情请参见:[MaxKB 产品版本对比](https://maxkb.cn/pricing.html);
+- 如果您需要向团队介绍 MaxKB,可以使用这个 [官方 PPT 材料](https://maxkb.cn/download/introduce-maxkb_202411.pdf)。
如你有更多问题,可以查看使用手册,或者通过论坛与我们交流。
diff --git a/apps/application/flow/i_step_node.py b/apps/application/flow/i_step_node.py
index 3d30758a2..360c46bb5 100644
--- a/apps/application/flow/i_step_node.py
+++ b/apps/application/flow/i_step_node.py
@@ -32,7 +32,7 @@ def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
if workflow.is_result(node, NodeResult(step_variable, global_variable)) and 'answer' in step_variable:
answer = step_variable['answer']
yield answer
- workflow.append_answer(answer)
+ node.answer_text = answer
if global_variable is not None:
for key in global_variable:
workflow.context[key] = global_variable[key]
diff --git a/apps/application/flow/step_node/document_extract_node/i_document_extract_node.py b/apps/application/flow/step_node/document_extract_node/i_document_extract_node.py
index d030e0078..ceda39444 100644
--- a/apps/application/flow/step_node/document_extract_node/i_document_extract_node.py
+++ b/apps/application/flow/step_node/document_extract_node/i_document_extract_node.py
@@ -9,12 +9,7 @@ from common.util.field_message import ErrMessage
class DocumentExtractNodeSerializer(serializers.Serializer):
- # 需要查询的数据集id列表
- file_list = serializers.ListField(required=True, child=serializers.UUIDField(required=True),
- error_messages=ErrMessage.list("数据集id列表"))
-
- def is_valid(self, *, raise_exception=False):
- super().is_valid(raise_exception=True)
+ document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
class IDocumentExtractNode(INode):
@@ -24,7 +19,9 @@ class IDocumentExtractNode(INode):
return DocumentExtractNodeSerializer
def _run(self):
- return self.execute(**self.flow_params_serializer.data)
+ res = self.workflow_manage.get_reference_field(self.node_params_serializer.data.get('document_list')[0],
+ self.node_params_serializer.data.get('document_list')[1:])
+ return self.execute(document=res, **self.flow_params_serializer.data)
- def execute(self, file_list, **kwargs) -> NodeResult:
+ def execute(self, document, **kwargs) -> NodeResult:
pass
diff --git a/apps/application/flow/step_node/document_extract_node/impl/base_document_extract_node.py b/apps/application/flow/step_node/document_extract_node/impl/base_document_extract_node.py
index bf900ffe2..176230d2d 100644
--- a/apps/application/flow/step_node/document_extract_node/impl/base_document_extract_node.py
+++ b/apps/application/flow/step_node/document_extract_node/impl/base_document_extract_node.py
@@ -1,11 +1,34 @@
# coding=utf-8
+from django.db.models import QuerySet
+from application.flow.i_step_node import NodeResult
from application.flow.step_node.document_extract_node.i_document_extract_node import IDocumentExtractNode
+from dataset.models import File
class BaseDocumentExtractNode(IDocumentExtractNode):
- def execute(self, file_list, **kwargs):
- pass
+ def execute(self, document, **kwargs):
+ self.context['document_list'] = document
+ content = ''
+ spliter = '\n-----------------------------------\n'
+ if len(document) > 0:
+ for doc in document:
+ file = QuerySet(File).filter(id=doc['file_id']).first()
+ file_type = doc['name'].split('.')[-1]
+ if file_type.lower() in ['txt', 'md', 'csv', 'html']:
+ content += spliter + doc['name'] + '\n' + file.get_byte().tobytes().decode('utf-8')
+
+
+ return NodeResult({'content': content}, {})
def get_details(self, index: int, **kwargs):
- pass
+ return {
+ 'name': self.node.properties.get('stepName'),
+ "index": index,
+ 'run_time': self.context.get('run_time'),
+ 'type': self.node.type,
+ 'content': self.context.get('content'),
+ 'status': self.status,
+ 'err_message': self.err_message,
+ 'document_list': self.context.get('document_list')
+ }
diff --git a/apps/application/flow/step_node/image_understand_step_node/i_image_understand_node.py b/apps/application/flow/step_node/image_understand_step_node/i_image_understand_node.py
index 4c15ad8cd..26fb431d0 100644
--- a/apps/application/flow/step_node/image_understand_step_node/i_image_understand_node.py
+++ b/apps/application/flow/step_node/image_understand_step_node/i_image_understand_node.py
@@ -18,7 +18,7 @@ class ImageUnderstandNodeSerializer(serializers.Serializer):
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean('是否返回内容'))
- image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片仅1张"))
+ image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
class IImageUnderstandNode(INode):
diff --git a/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py b/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py
index e6a88a9f1..046d6f783 100644
--- a/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py
+++ b/apps/application/flow/step_node/image_understand_step_node/impl/base_image_understand_node.py
@@ -25,7 +25,7 @@ def _write_context(node_variable: Dict, workflow_variable: Dict, node: INode, wo
node.context['question'] = node_variable['question']
node.context['run_time'] = time.time() - node.context['start_time']
if workflow.is_result(node, NodeResult(node_variable, workflow_variable)):
- workflow.answer += answer
+ node.answer_text = answer
def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INode, workflow):
diff --git a/apps/application/flow/step_node/start_node/impl/base_start_node.py b/apps/application/flow/step_node/start_node/impl/base_start_node.py
index 9ac7e2aef..6388e4dfd 100644
--- a/apps/application/flow/step_node/start_node/impl/base_start_node.py
+++ b/apps/application/flow/step_node/start_node/impl/base_start_node.py
@@ -52,8 +52,12 @@ class BaseStartStepNode(IStarNode):
"""
开始节点 初始化全局变量
"""
- return NodeResult({'question': question, 'image': self.workflow_manage.image_list},
- workflow_variable)
+ node_variable = {
+ 'question': question,
+ 'image': self.workflow_manage.image_list,
+ 'document': self.workflow_manage.document_list
+ }
+ return NodeResult(node_variable, workflow_variable)
def get_details(self, index: int, **kwargs):
global_fields = []
diff --git a/apps/application/flow/workflow_manage.py b/apps/application/flow/workflow_manage.py
index 39c42aa24..0cd92e8e1 100644
--- a/apps/application/flow/workflow_manage.py
+++ b/apps/application/flow/workflow_manage.py
@@ -240,16 +240,20 @@ class NodeChunk:
class WorkflowManage:
def __init__(self, flow: Flow, params, work_flow_post_handler: WorkFlowPostHandler,
base_to_response: BaseToResponse = SystemToResponse(), form_data=None, image_list=None,
+ document_list=None,
start_node_id=None,
start_node_data=None, chat_record=None):
if form_data is None:
form_data = {}
if image_list is None:
image_list = []
+ if document_list is None:
+ document_list = []
self.start_node = None
self.start_node_result_future = None
self.form_data = form_data
self.image_list = image_list
+ self.document_list = document_list
self.params = params
self.flow = flow
self.lock = threading.Lock()
@@ -511,7 +515,7 @@ class WorkflowManage:
if index == 0:
result.append(answer.get('content'))
continue
- if answer.get('type') != answer_text_list[index - 1]:
+ if answer.get('type') != answer_text_list[index - 1].get('type'):
result.append(answer.get('content'))
else:
result[-1] += answer.get('content')
diff --git a/apps/application/migrations/0011_application_model_params_setting.py b/apps/application/migrations/0011_application_model_params_setting.py
index 440b94df5..656b54775 100644
--- a/apps/application/migrations/0011_application_model_params_setting.py
+++ b/apps/application/migrations/0011_application_model_params_setting.py
@@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='application',
name='model_params_setting',
- field=models.JSONField(default={}, verbose_name='模型参数相关设置'),
+ field=models.JSONField(default=dict, verbose_name='模型参数相关设置'),
),
]
diff --git a/apps/application/migrations/0017_application_tts_model_params_setting.py b/apps/application/migrations/0017_application_tts_model_params_setting.py
index 43428841f..3276ca632 100644
--- a/apps/application/migrations/0017_application_tts_model_params_setting.py
+++ b/apps/application/migrations/0017_application_tts_model_params_setting.py
@@ -13,6 +13,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='application',
name='tts_model_params_setting',
- field=models.JSONField(default={}, verbose_name='模型参数相关设置'),
+ field=models.JSONField(default=dict, verbose_name='模型参数相关设置'),
),
]
diff --git a/apps/application/migrations/0019_application_file_upload_enable_and_more.py b/apps/application/migrations/0019_application_file_upload_enable_and_more.py
index f59a4990c..f8c33c2c1 100644
--- a/apps/application/migrations/0019_application_file_upload_enable_and_more.py
+++ b/apps/application/migrations/0019_application_file_upload_enable_and_more.py
@@ -23,7 +23,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='application',
name='file_upload_setting',
- field=models.JSONField(default={}, verbose_name='文件上传相关设置'),
+ field=models.JSONField(default=dict, verbose_name='文件上传相关设置'),
),
migrations.AddField(
model_name='chatrecord',
diff --git a/apps/application/models/application.py b/apps/application/models/application.py
index 5df928c4d..c90d1325c 100644
--- a/apps/application/models/application.py
+++ b/apps/application/models/application.py
@@ -48,8 +48,8 @@ class Application(AppModelMixin):
model = models.ForeignKey(Model, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
dataset_setting = models.JSONField(verbose_name="数据集参数设置", default=get_dataset_setting_dict)
model_setting = models.JSONField(verbose_name="模型参数相关设置", default=get_model_setting_dict)
- model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default={})
- tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default={})
+ model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
+ tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
problem_optimization = models.BooleanField(verbose_name="问题优化", default=False)
icon = models.CharField(max_length=256, verbose_name="应用icon", default="/ui/favicon.ico")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
@@ -67,7 +67,7 @@ class Application(AppModelMixin):
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
- file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default={})
+ file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
@staticmethod
diff --git a/apps/application/serializers/chat_message_serializers.py b/apps/application/serializers/chat_message_serializers.py
index 455ef6a67..919cb71cf 100644
--- a/apps/application/serializers/chat_message_serializers.py
+++ b/apps/application/serializers/chat_message_serializers.py
@@ -230,7 +230,8 @@ class ChatMessageSerializer(serializers.Serializer):
client_id = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端id"))
client_type = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端类型"))
form_data = serializers.DictField(required=False, error_messages=ErrMessage.char("全局变量"))
- image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片仅1张"))
+ image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
+ document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
def is_valid_application_workflow(self, *, raise_exception=False):
self.is_valid_intraday_access_num()
@@ -322,6 +323,7 @@ class ChatMessageSerializer(serializers.Serializer):
client_type = self.data.get('client_type')
form_data = self.data.get('form_data')
image_list = self.data.get('image_list')
+ document_list = self.data.get('document_list')
user_id = chat_info.application.user_id
chat_record_id = self.data.get('chat_record_id')
chat_record = None
@@ -336,7 +338,7 @@ class ChatMessageSerializer(serializers.Serializer):
'client_id': client_id,
'client_type': client_type,
'user_id': user_id}, WorkFlowPostHandler(chat_info, client_id, client_type),
- base_to_response, form_data, image_list, self.data.get('runtime_node_id'),
+ base_to_response, form_data, image_list, document_list, self.data.get('runtime_node_id'),
self.data.get('node_data'), chat_record)
r = work_flow_manage.run()
return r
diff --git a/apps/application/views/chat_views.py b/apps/application/views/chat_views.py
index 586787b20..790277860 100644
--- a/apps/application/views/chat_views.py
+++ b/apps/application/views/chat_views.py
@@ -132,6 +132,8 @@ class ChatView(APIView):
'image_list': request.data.get(
'image_list') if 'image_list' in request.data else [],
+ 'document_list': request.data.get(
+ 'document_list') if 'document_list' in request.data else [],
'client_type': request.auth.client_type,
'runtime_node_id': request.data.get('runtime_node_id', None),
'node_data': request.data.get('node_data', {}),
diff --git a/ui/package.json b/ui/package.json
index e6067f69c..3203bd466 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -17,6 +17,7 @@
"@ctrl/tinycolor": "^4.1.0",
"@logicflow/core": "^1.2.27",
"@logicflow/extension": "^1.2.27",
+ "@antv/layout": "^0.3.1",
"@vueuse/core": "^10.9.0",
"@wecom/jssdk": "^2.1.0",
"axios": "^0.28.0",
diff --git a/ui/src/api/type/application.ts b/ui/src/api/type/application.ts
index 5d4971f7f..11b630f13 100644
--- a/ui/src/api/type/application.ts
+++ b/ui/src/api/type/application.ts
@@ -39,7 +39,8 @@ interface chatType {
record_id: string
chat_id: string
vote_status: string
- status?: number
+ status?: number,
+ execution_details: any[]
}
export class ChatRecordManage {
diff --git a/ui/src/components/ai-chat/component/answer-content/index.vue b/ui/src/components/ai-chat/component/answer-content/index.vue
index f02fd74dd..1a75737bb 100644
--- a/ui/src/components/ai-chat/component/answer-content/index.vue
+++ b/ui/src/components/ai-chat/component/answer-content/index.vue
@@ -1,14 +1,20 @@