fix: 修复子应用表单调用无法调用问题 (#1741)
This commit is contained in:
parent
d4f9ac9f34
commit
b6c65154c5
@ -40,6 +40,10 @@ def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
|
|||||||
node.context['run_time'] = time.time() - node.context['start_time']
|
node.context['run_time'] = time.time() - node.context['start_time']
|
||||||
|
|
||||||
|
|
||||||
|
def is_interrupt(node, step_variable: Dict, global_variable: Dict):
|
||||||
|
return node.type == 'form-node' and not node.context.get('is_submit', False)
|
||||||
|
|
||||||
|
|
||||||
class WorkFlowPostHandler:
|
class WorkFlowPostHandler:
|
||||||
def __init__(self, chat_info, client_id, client_type):
|
def __init__(self, chat_info, client_id, client_type):
|
||||||
self.chat_info = chat_info
|
self.chat_info = chat_info
|
||||||
@ -57,7 +61,7 @@ class WorkFlowPostHandler:
|
|||||||
answer_tokens = sum([row.get('answer_tokens') for row in details.values() if
|
answer_tokens = sum([row.get('answer_tokens') for row in details.values() if
|
||||||
'answer_tokens' in row and row.get('answer_tokens') is not None])
|
'answer_tokens' in row and row.get('answer_tokens') is not None])
|
||||||
answer_text_list = workflow.get_answer_text_list()
|
answer_text_list = workflow.get_answer_text_list()
|
||||||
answer_text = '\n\n'.join(answer_text_list)
|
answer_text = '\n\n'.join(answer['content'] for answer in answer_text_list)
|
||||||
if workflow.chat_record is not None:
|
if workflow.chat_record is not None:
|
||||||
chat_record = workflow.chat_record
|
chat_record = workflow.chat_record
|
||||||
chat_record.answer_text = answer_text
|
chat_record.answer_text = answer_text
|
||||||
@ -91,10 +95,11 @@ class WorkFlowPostHandler:
|
|||||||
|
|
||||||
class NodeResult:
|
class NodeResult:
|
||||||
def __init__(self, node_variable: Dict, workflow_variable: Dict,
|
def __init__(self, node_variable: Dict, workflow_variable: Dict,
|
||||||
_write_context=write_context):
|
_write_context=write_context, _is_interrupt=is_interrupt):
|
||||||
self._write_context = _write_context
|
self._write_context = _write_context
|
||||||
self.node_variable = node_variable
|
self.node_variable = node_variable
|
||||||
self.workflow_variable = workflow_variable
|
self.workflow_variable = workflow_variable
|
||||||
|
self._is_interrupt = _is_interrupt
|
||||||
|
|
||||||
def write_context(self, node, workflow):
|
def write_context(self, node, workflow):
|
||||||
return self._write_context(self.node_variable, self.workflow_variable, node, workflow)
|
return self._write_context(self.node_variable, self.workflow_variable, node, workflow)
|
||||||
@ -102,6 +107,14 @@ class NodeResult:
|
|||||||
def is_assertion_result(self):
|
def is_assertion_result(self):
|
||||||
return 'branch_id' in self.node_variable
|
return 'branch_id' in self.node_variable
|
||||||
|
|
||||||
|
def is_interrupt_exec(self, current_node):
|
||||||
|
"""
|
||||||
|
是否中断执行
|
||||||
|
@param current_node:
|
||||||
|
@return:
|
||||||
|
"""
|
||||||
|
return self._is_interrupt(current_node, self.node_variable, self.workflow_variable)
|
||||||
|
|
||||||
|
|
||||||
class ReferenceAddressSerializer(serializers.Serializer):
|
class ReferenceAddressSerializer(serializers.Serializer):
|
||||||
node_id = serializers.CharField(required=True, error_messages=ErrMessage.char("节点id"))
|
node_id = serializers.CharField(required=True, error_messages=ErrMessage.char("节点id"))
|
||||||
@ -139,14 +152,18 @@ class INode:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def get_answer_text(self):
|
def get_answer_text(self):
|
||||||
return self.answer_text
|
if self.answer_text is None:
|
||||||
|
return None
|
||||||
|
return {'content': self.answer_text, 'runtime_node_id': self.runtime_node_id,
|
||||||
|
'chat_record_id': self.workflow_params['chat_record_id']}
|
||||||
|
|
||||||
def __init__(self, node, workflow_params, workflow_manage, up_node_id_list=None):
|
def __init__(self, node, workflow_params, workflow_manage, up_node_id_list=None,
|
||||||
|
get_node_params=lambda node: node.properties.get('node_data')):
|
||||||
# 当前步骤上下文,用于存储当前步骤信息
|
# 当前步骤上下文,用于存储当前步骤信息
|
||||||
self.status = 200
|
self.status = 200
|
||||||
self.err_message = ''
|
self.err_message = ''
|
||||||
self.node = node
|
self.node = node
|
||||||
self.node_params = node.properties.get('node_data')
|
self.node_params = get_node_params(node)
|
||||||
self.workflow_params = workflow_params
|
self.workflow_params = workflow_params
|
||||||
self.workflow_manage = workflow_manage
|
self.workflow_manage = workflow_manage
|
||||||
self.node_params_serializer = None
|
self.node_params_serializer = None
|
||||||
|
|||||||
@ -14,6 +14,8 @@ class ApplicationNodeSerializer(serializers.Serializer):
|
|||||||
user_input_field_list = serializers.ListField(required=False, error_messages=ErrMessage.uuid("用户输入字段"))
|
user_input_field_list = serializers.ListField(required=False, error_messages=ErrMessage.uuid("用户输入字段"))
|
||||||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
|
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
|
||||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
|
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
|
||||||
|
child_node = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict("子节点"))
|
||||||
|
node_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict("表单数据"))
|
||||||
|
|
||||||
|
|
||||||
class IApplicationNode(INode):
|
class IApplicationNode(INode):
|
||||||
@ -55,5 +57,5 @@ class IApplicationNode(INode):
|
|||||||
message=str(question), **kwargs)
|
message=str(question), **kwargs)
|
||||||
|
|
||||||
def execute(self, application_id, message, chat_id, chat_record_id, stream, re_chat, client_id, client_type,
|
def execute(self, application_id, message, chat_id, chat_record_id, stream, re_chat, client_id, client_type,
|
||||||
app_document_list=None, app_image_list=None, **kwargs) -> NodeResult:
|
app_document_list=None, app_image_list=None, child_node=None, node_data=None, **kwargs) -> NodeResult:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -2,19 +2,25 @@
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from typing import List, Dict
|
from typing import Dict
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult, INode
|
from application.flow.i_step_node import NodeResult, INode
|
||||||
from application.flow.step_node.application_node.i_application_node import IApplicationNode
|
from application.flow.step_node.application_node.i_application_node import IApplicationNode
|
||||||
from application.models import Chat
|
from application.models import Chat
|
||||||
from common.handle.impl.response.openai_to_response import OpenaiToResponse
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_uuid(input_str):
|
def string_to_uuid(input_str):
|
||||||
return str(uuid.uuid5(uuid.NAMESPACE_DNS, input_str))
|
return str(uuid.uuid5(uuid.NAMESPACE_DNS, input_str))
|
||||||
|
|
||||||
|
|
||||||
|
def _is_interrupt_exec(node, node_variable: Dict, workflow_variable: Dict):
|
||||||
|
return node_variable.get('is_interrupt_exec', False)
|
||||||
|
|
||||||
|
|
||||||
def _write_context(node_variable: Dict, workflow_variable: Dict, node: INode, workflow, answer: str):
|
def _write_context(node_variable: Dict, workflow_variable: Dict, node: INode, workflow, answer: str):
|
||||||
result = node_variable.get('result')
|
result = node_variable.get('result')
|
||||||
|
node.context['child_node'] = node_variable['child_node']
|
||||||
|
node.context['is_interrupt_exec'] = node_variable['is_interrupt_exec']
|
||||||
node.context['message_tokens'] = result.get('usage', {}).get('prompt_tokens', 0)
|
node.context['message_tokens'] = result.get('usage', {}).get('prompt_tokens', 0)
|
||||||
node.context['answer_tokens'] = result.get('usage', {}).get('completion_tokens', 0)
|
node.context['answer_tokens'] = result.get('usage', {}).get('completion_tokens', 0)
|
||||||
node.context['answer'] = answer
|
node.context['answer'] = answer
|
||||||
@ -36,17 +42,34 @@ def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INo
|
|||||||
response = node_variable.get('result')
|
response = node_variable.get('result')
|
||||||
answer = ''
|
answer = ''
|
||||||
usage = {}
|
usage = {}
|
||||||
|
node_child_node = {}
|
||||||
|
is_interrupt_exec = False
|
||||||
for chunk in response:
|
for chunk in response:
|
||||||
# 先把流转成字符串
|
# 先把流转成字符串
|
||||||
response_content = chunk.decode('utf-8')[6:]
|
response_content = chunk.decode('utf-8')[6:]
|
||||||
response_content = json.loads(response_content)
|
response_content = json.loads(response_content)
|
||||||
choices = response_content.get('choices')
|
content = response_content.get('content', '')
|
||||||
if choices and isinstance(choices, list) and len(choices) > 0:
|
runtime_node_id = response_content.get('runtime_node_id', '')
|
||||||
content = choices[0].get('delta', {}).get('content', '')
|
chat_record_id = response_content.get('chat_record_id', '')
|
||||||
answer += content
|
child_node = response_content.get('child_node')
|
||||||
yield content
|
node_type = response_content.get('node_type')
|
||||||
|
real_node_id = response_content.get('real_node_id')
|
||||||
|
node_is_end = response_content.get('node_is_end', False)
|
||||||
|
if node_type == 'form-node':
|
||||||
|
is_interrupt_exec = True
|
||||||
|
answer += content
|
||||||
|
node_child_node = {'runtime_node_id': runtime_node_id, 'chat_record_id': chat_record_id,
|
||||||
|
'child_node': child_node}
|
||||||
|
yield {'content': content,
|
||||||
|
'node_type': node_type,
|
||||||
|
'runtime_node_id': runtime_node_id, 'chat_record_id': chat_record_id,
|
||||||
|
'child_node': child_node,
|
||||||
|
'real_node_id': real_node_id,
|
||||||
|
'node_is_end': node_is_end}
|
||||||
usage = response_content.get('usage', {})
|
usage = response_content.get('usage', {})
|
||||||
node_variable['result'] = {'usage': usage}
|
node_variable['result'] = {'usage': usage}
|
||||||
|
node_variable['is_interrupt_exec'] = is_interrupt_exec
|
||||||
|
node_variable['child_node'] = node_child_node
|
||||||
_write_context(node_variable, workflow_variable, node, workflow, answer)
|
_write_context(node_variable, workflow_variable, node, workflow, answer)
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +87,11 @@ def write_context(node_variable: Dict, workflow_variable: Dict, node: INode, wor
|
|||||||
|
|
||||||
|
|
||||||
class BaseApplicationNode(IApplicationNode):
|
class BaseApplicationNode(IApplicationNode):
|
||||||
|
def get_answer_text(self):
|
||||||
|
if self.answer_text is None:
|
||||||
|
return None
|
||||||
|
return {'content': self.answer_text, 'runtime_node_id': self.runtime_node_id,
|
||||||
|
'chat_record_id': self.workflow_params['chat_record_id'], 'child_node': self.context.get('child_node')}
|
||||||
|
|
||||||
def save_context(self, details, workflow_manage):
|
def save_context(self, details, workflow_manage):
|
||||||
self.context['answer'] = details.get('answer')
|
self.context['answer'] = details.get('answer')
|
||||||
@ -72,7 +100,7 @@ class BaseApplicationNode(IApplicationNode):
|
|||||||
self.answer_text = details.get('answer')
|
self.answer_text = details.get('answer')
|
||||||
|
|
||||||
def execute(self, application_id, message, chat_id, chat_record_id, stream, re_chat, client_id, client_type,
|
def execute(self, application_id, message, chat_id, chat_record_id, stream, re_chat, client_id, client_type,
|
||||||
app_document_list=None, app_image_list=None,
|
app_document_list=None, app_image_list=None, child_node=None, node_data=None,
|
||||||
**kwargs) -> NodeResult:
|
**kwargs) -> NodeResult:
|
||||||
from application.serializers.chat_message_serializers import ChatMessageSerializer
|
from application.serializers.chat_message_serializers import ChatMessageSerializer
|
||||||
# 生成嵌入应用的chat_id
|
# 生成嵌入应用的chat_id
|
||||||
@ -85,6 +113,14 @@ class BaseApplicationNode(IApplicationNode):
|
|||||||
app_document_list = []
|
app_document_list = []
|
||||||
if app_image_list is None:
|
if app_image_list is None:
|
||||||
app_image_list = []
|
app_image_list = []
|
||||||
|
runtime_node_id = None
|
||||||
|
record_id = None
|
||||||
|
child_node_value = None
|
||||||
|
if child_node is not None:
|
||||||
|
runtime_node_id = child_node.get('runtime_node_id')
|
||||||
|
record_id = child_node.get('chat_record_id')
|
||||||
|
child_node_value = child_node.get('child_node')
|
||||||
|
|
||||||
response = ChatMessageSerializer(
|
response = ChatMessageSerializer(
|
||||||
data={'chat_id': current_chat_id, 'message': message,
|
data={'chat_id': current_chat_id, 'message': message,
|
||||||
're_chat': re_chat,
|
're_chat': re_chat,
|
||||||
@ -94,16 +130,20 @@ class BaseApplicationNode(IApplicationNode):
|
|||||||
'client_type': client_type,
|
'client_type': client_type,
|
||||||
'document_list': app_document_list,
|
'document_list': app_document_list,
|
||||||
'image_list': app_image_list,
|
'image_list': app_image_list,
|
||||||
'form_data': kwargs}).chat(base_to_response=OpenaiToResponse())
|
'runtime_node_id': runtime_node_id,
|
||||||
|
'chat_record_id': record_id,
|
||||||
|
'child_node': child_node_value,
|
||||||
|
'node_data': node_data,
|
||||||
|
'form_data': kwargs}).chat()
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
if stream:
|
if stream:
|
||||||
content_generator = response.streaming_content
|
content_generator = response.streaming_content
|
||||||
return NodeResult({'result': content_generator, 'question': message}, {},
|
return NodeResult({'result': content_generator, 'question': message}, {},
|
||||||
_write_context=write_context_stream)
|
_write_context=write_context_stream, _is_interrupt=_is_interrupt_exec)
|
||||||
else:
|
else:
|
||||||
data = json.loads(response.content)
|
data = json.loads(response.content)
|
||||||
return NodeResult({'result': data, 'question': message}, {},
|
return NodeResult({'result': data, 'question': message}, {},
|
||||||
_write_context=write_context)
|
_write_context=write_context, _is_interrupt=_is_interrupt_exec)
|
||||||
|
|
||||||
def get_details(self, index: int, **kwargs):
|
def get_details(self, index: int, **kwargs):
|
||||||
global_fields = []
|
global_fields = []
|
||||||
|
|||||||
@ -17,6 +17,7 @@ from common.util.field_message import ErrMessage
|
|||||||
class FormNodeParamsSerializer(serializers.Serializer):
|
class FormNodeParamsSerializer(serializers.Serializer):
|
||||||
form_field_list = serializers.ListField(required=True, error_messages=ErrMessage.list("表单配置"))
|
form_field_list = serializers.ListField(required=True, error_messages=ErrMessage.list("表单配置"))
|
||||||
form_content_format = serializers.CharField(required=True, error_messages=ErrMessage.char('表单输出内容'))
|
form_content_format = serializers.CharField(required=True, error_messages=ErrMessage.char('表单输出内容'))
|
||||||
|
form_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict("表单数据"))
|
||||||
|
|
||||||
|
|
||||||
class IFormNode(INode):
|
class IFormNode(INode):
|
||||||
@ -29,5 +30,5 @@ class IFormNode(INode):
|
|||||||
def _run(self):
|
def _run(self):
|
||||||
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
|
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data)
|
||||||
|
|
||||||
def execute(self, form_field_list, form_content_format, **kwargs) -> NodeResult:
|
def execute(self, form_field_list, form_content_format, form_data, **kwargs) -> NodeResult:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -42,7 +42,12 @@ class BaseFormNode(IFormNode):
|
|||||||
for key in form_data:
|
for key in form_data:
|
||||||
self.context[key] = form_data[key]
|
self.context[key] = form_data[key]
|
||||||
|
|
||||||
def execute(self, form_field_list, form_content_format, **kwargs) -> NodeResult:
|
def execute(self, form_field_list, form_content_format, form_data, **kwargs) -> NodeResult:
|
||||||
|
if form_data is not None:
|
||||||
|
self.context['is_submit'] = True
|
||||||
|
self.context['form_data'] = form_data
|
||||||
|
else:
|
||||||
|
self.context['is_submit'] = False
|
||||||
form_setting = {"form_field_list": form_field_list, "runtime_node_id": self.runtime_node_id,
|
form_setting = {"form_field_list": form_field_list, "runtime_node_id": self.runtime_node_id,
|
||||||
"chat_record_id": self.flow_params_serializer.data.get("chat_record_id"),
|
"chat_record_id": self.flow_params_serializer.data.get("chat_record_id"),
|
||||||
"is_submit": self.context.get("is_submit", False)}
|
"is_submit": self.context.get("is_submit", False)}
|
||||||
@ -63,7 +68,8 @@ class BaseFormNode(IFormNode):
|
|||||||
form = f'<form_rander>{json.dumps(form_setting)}</form_rander>'
|
form = f'<form_rander>{json.dumps(form_setting)}</form_rander>'
|
||||||
prompt_template = PromptTemplate.from_template(form_content_format, template_format='jinja2')
|
prompt_template = PromptTemplate.from_template(form_content_format, template_format='jinja2')
|
||||||
value = prompt_template.format(form=form)
|
value = prompt_template.format(form=form)
|
||||||
return value
|
return {'content': value, 'runtime_node_id': self.runtime_node_id,
|
||||||
|
'chat_record_id': self.workflow_params['chat_record_id']}
|
||||||
|
|
||||||
def get_details(self, index: int, **kwargs):
|
def get_details(self, index: int, **kwargs):
|
||||||
form_content_format = self.context.get('form_content_format')
|
form_content_format = self.context.get('form_content_format')
|
||||||
|
|||||||
@ -244,15 +244,15 @@ class WorkflowManage:
|
|||||||
base_to_response: BaseToResponse = SystemToResponse(), form_data=None, image_list=None,
|
base_to_response: BaseToResponse = SystemToResponse(), form_data=None, image_list=None,
|
||||||
document_list=None,
|
document_list=None,
|
||||||
start_node_id=None,
|
start_node_id=None,
|
||||||
start_node_data=None, chat_record=None):
|
start_node_data=None, chat_record=None, child_node=None):
|
||||||
if form_data is None:
|
if form_data is None:
|
||||||
form_data = {}
|
form_data = {}
|
||||||
if image_list is None:
|
if image_list is None:
|
||||||
image_list = []
|
image_list = []
|
||||||
if document_list is None:
|
if document_list is None:
|
||||||
document_list = []
|
document_list = []
|
||||||
|
self.start_node_id = start_node_id
|
||||||
self.start_node = None
|
self.start_node = None
|
||||||
self.start_node_result_future = None
|
|
||||||
self.form_data = form_data
|
self.form_data = form_data
|
||||||
self.image_list = image_list
|
self.image_list = image_list
|
||||||
self.document_list = document_list
|
self.document_list = document_list
|
||||||
@ -270,6 +270,7 @@ class WorkflowManage:
|
|||||||
self.base_to_response = base_to_response
|
self.base_to_response = base_to_response
|
||||||
self.chat_record = chat_record
|
self.chat_record = chat_record
|
||||||
self.await_future_map = {}
|
self.await_future_map = {}
|
||||||
|
self.child_node = child_node
|
||||||
if start_node_id is not None:
|
if start_node_id is not None:
|
||||||
self.load_node(chat_record, start_node_id, start_node_data)
|
self.load_node(chat_record, start_node_id, start_node_data)
|
||||||
else:
|
else:
|
||||||
@ -290,11 +291,17 @@ class WorkflowManage:
|
|||||||
for node_details in sorted(chat_record.details.values(), key=lambda d: d.get('index')):
|
for node_details in sorted(chat_record.details.values(), key=lambda d: d.get('index')):
|
||||||
node_id = node_details.get('node_id')
|
node_id = node_details.get('node_id')
|
||||||
if node_details.get('runtime_node_id') == start_node_id:
|
if node_details.get('runtime_node_id') == start_node_id:
|
||||||
self.start_node = self.get_node_cls_by_id(node_id, node_details.get('up_node_id_list'))
|
def get_node_params(n):
|
||||||
self.start_node.valid_args(self.start_node.node_params, self.start_node.workflow_params)
|
is_result = False
|
||||||
self.start_node.save_context(node_details, self)
|
if n.type == 'application-node':
|
||||||
node_result = NodeResult({**start_node_data, 'form_data': start_node_data, 'is_submit': True}, {})
|
is_result = True
|
||||||
self.start_node_result_future = NodeResultFuture(node_result, None)
|
return {**n.properties.get('node_data'), 'form_data': start_node_data, 'node_data': start_node_data,
|
||||||
|
'child_node': self.child_node, 'is_result': is_result}
|
||||||
|
|
||||||
|
self.start_node = self.get_node_cls_by_id(node_id, node_details.get('up_node_id_list'),
|
||||||
|
get_node_params=get_node_params)
|
||||||
|
self.start_node.valid_args(
|
||||||
|
{**self.start_node.node_params, 'form_data': start_node_data}, self.start_node.workflow_params)
|
||||||
self.node_context.append(self.start_node)
|
self.node_context.append(self.start_node)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -306,7 +313,7 @@ class WorkflowManage:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.params.get('stream'):
|
if self.params.get('stream'):
|
||||||
return self.run_stream(self.start_node, self.start_node_result_future)
|
return self.run_stream(self.start_node, None)
|
||||||
return self.run_block()
|
return self.run_block()
|
||||||
|
|
||||||
def run_block(self):
|
def run_block(self):
|
||||||
@ -429,22 +436,41 @@ class WorkflowManage:
|
|||||||
if result is not None:
|
if result is not None:
|
||||||
if self.is_result(current_node, current_result):
|
if self.is_result(current_node, current_result):
|
||||||
self.node_chunk_manage.add_node_chunk(node_chunk)
|
self.node_chunk_manage.add_node_chunk(node_chunk)
|
||||||
|
child_node = {}
|
||||||
|
real_node_id = current_node.runtime_node_id
|
||||||
for r in result:
|
for r in result:
|
||||||
|
content = r
|
||||||
|
child_node = {}
|
||||||
|
node_is_end = False
|
||||||
|
if isinstance(r, dict):
|
||||||
|
content = r.get('content')
|
||||||
|
child_node = {'runtime_node_id': r.get('runtime_node_id'),
|
||||||
|
'chat_record_id': r.get('chat_record_id')
|
||||||
|
, 'child_node': r.get('child_node')}
|
||||||
|
real_node_id = r.get('real_node_id')
|
||||||
|
node_is_end = r.get('node_is_end')
|
||||||
chunk = self.base_to_response.to_stream_chunk_response(self.params['chat_id'],
|
chunk = self.base_to_response.to_stream_chunk_response(self.params['chat_id'],
|
||||||
self.params['chat_record_id'],
|
self.params['chat_record_id'],
|
||||||
current_node.id,
|
current_node.id,
|
||||||
current_node.up_node_id_list,
|
current_node.up_node_id_list,
|
||||||
r, False, 0, 0,
|
content, False, 0, 0,
|
||||||
{'node_type': current_node.type,
|
{'node_type': current_node.type,
|
||||||
'view_type': current_node.view_type})
|
'runtime_node_id': current_node.runtime_node_id,
|
||||||
|
'view_type': current_node.view_type,
|
||||||
|
'child_node': child_node,
|
||||||
|
'node_is_end': node_is_end,
|
||||||
|
'real_node_id': real_node_id})
|
||||||
node_chunk.add_chunk(chunk)
|
node_chunk.add_chunk(chunk)
|
||||||
chunk = self.base_to_response.to_stream_chunk_response(self.params['chat_id'],
|
chunk = self.base_to_response.to_stream_chunk_response(self.params['chat_id'],
|
||||||
self.params['chat_record_id'],
|
self.params['chat_record_id'],
|
||||||
current_node.id,
|
current_node.id,
|
||||||
current_node.up_node_id_list,
|
current_node.up_node_id_list,
|
||||||
'', False, 0, 0, {'node_is_end': True,
|
'', False, 0, 0, {'node_is_end': True,
|
||||||
|
'runtime_node_id': current_node.runtime_node_id,
|
||||||
'node_type': current_node.type,
|
'node_type': current_node.type,
|
||||||
'view_type': current_node.view_type})
|
'view_type': current_node.view_type,
|
||||||
|
'child_node': child_node,
|
||||||
|
'real_node_id': real_node_id})
|
||||||
node_chunk.end(chunk)
|
node_chunk.end(chunk)
|
||||||
else:
|
else:
|
||||||
list(result)
|
list(result)
|
||||||
@ -554,9 +580,9 @@ class WorkflowManage:
|
|||||||
else:
|
else:
|
||||||
if len(result) > 0:
|
if len(result) > 0:
|
||||||
exec_index = len(result) - 1
|
exec_index = len(result) - 1
|
||||||
content = result[exec_index]
|
content = result[exec_index]['content']
|
||||||
result[exec_index] += answer_text if len(
|
result[exec_index]['content'] += answer_text['content'] if len(
|
||||||
content) == 0 else ('\n\n' + answer_text)
|
content) == 0 else ('\n\n' + answer_text['content'])
|
||||||
else:
|
else:
|
||||||
answer_text = node.get_answer_text()
|
answer_text = node.get_answer_text()
|
||||||
result.insert(0, answer_text)
|
result.insert(0, answer_text)
|
||||||
@ -613,8 +639,8 @@ class WorkflowManage:
|
|||||||
@param current_node_result: 当前可执行节点结果
|
@param current_node_result: 当前可执行节点结果
|
||||||
@return: 可执行节点列表
|
@return: 可执行节点列表
|
||||||
"""
|
"""
|
||||||
|
# 判断是否中断执行
|
||||||
if current_node.type == 'form-node' and 'form_data' not in current_node_result.node_variable:
|
if current_node_result.is_interrupt_exec(current_node):
|
||||||
return []
|
return []
|
||||||
node_list = []
|
node_list = []
|
||||||
if current_node_result is not None and current_node_result.is_assertion_result():
|
if current_node_result is not None and current_node_result.is_assertion_result():
|
||||||
@ -689,11 +715,12 @@ class WorkflowManage:
|
|||||||
base_node_list = [node for node in self.flow.nodes if node.type == 'base-node']
|
base_node_list = [node for node in self.flow.nodes if node.type == 'base-node']
|
||||||
return base_node_list[0]
|
return base_node_list[0]
|
||||||
|
|
||||||
def get_node_cls_by_id(self, node_id, up_node_id_list=None):
|
def get_node_cls_by_id(self, node_id, up_node_id_list=None,
|
||||||
|
get_node_params=lambda node: node.properties.get('node_data')):
|
||||||
for node in self.flow.nodes:
|
for node in self.flow.nodes:
|
||||||
if node.id == node_id:
|
if node.id == node_id:
|
||||||
node_instance = get_node(node.type)(node,
|
node_instance = get_node(node.type)(node,
|
||||||
self.params, self, up_node_id_list)
|
self.params, self, up_node_id_list, get_node_params)
|
||||||
return node_instance
|
return node_instance
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import django.contrib.postgres.fields
|
|||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
UPDATE "public".application_chat_record
|
UPDATE application_chat_record
|
||||||
SET "answer_text_list" = ARRAY[answer_text];
|
SET answer_text_list=ARRAY[jsonb_build_object('content',answer_text)]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@ -28,8 +28,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='chatrecord',
|
model_name='chatrecord',
|
||||||
name='answer_text_list',
|
name='answer_text_list',
|
||||||
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=40960), default=list,
|
field=django.contrib.postgres.fields.ArrayField(base_field=models.JSONField(), default=list, size=None, verbose_name='改进标注列表')
|
||||||
size=None, verbose_name='改进标注列表'),
|
|
||||||
),
|
),
|
||||||
migrations.RunSQL(sql)
|
migrations.RunSQL(sql)
|
||||||
]
|
]
|
||||||
|
|||||||
@ -69,7 +69,6 @@ class Application(AppModelMixin):
|
|||||||
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
|
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
|
||||||
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
|
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_default_model_prompt():
|
def get_default_model_prompt():
|
||||||
return ('已知信息:'
|
return ('已知信息:'
|
||||||
@ -148,7 +147,7 @@ class ChatRecord(AppModelMixin):
|
|||||||
problem_text = models.CharField(max_length=10240, verbose_name="问题")
|
problem_text = models.CharField(max_length=10240, verbose_name="问题")
|
||||||
answer_text = models.CharField(max_length=40960, verbose_name="答案")
|
answer_text = models.CharField(max_length=40960, verbose_name="答案")
|
||||||
answer_text_list = ArrayField(verbose_name="改进标注列表",
|
answer_text_list = ArrayField(verbose_name="改进标注列表",
|
||||||
base_field=models.CharField(max_length=40960)
|
base_field=models.JSONField()
|
||||||
, default=list)
|
, default=list)
|
||||||
message_tokens = models.IntegerField(verbose_name="请求token数量", default=0)
|
message_tokens = models.IntegerField(verbose_name="请求token数量", default=0)
|
||||||
answer_tokens = models.IntegerField(verbose_name="响应token数量", default=0)
|
answer_tokens = models.IntegerField(verbose_name="响应token数量", default=0)
|
||||||
|
|||||||
@ -238,13 +238,14 @@ class ChatMessageSerializer(serializers.Serializer):
|
|||||||
runtime_node_id = serializers.CharField(required=False, allow_null=True, allow_blank=True,
|
runtime_node_id = serializers.CharField(required=False, allow_null=True, allow_blank=True,
|
||||||
error_messages=ErrMessage.char("运行时节点id"))
|
error_messages=ErrMessage.char("运行时节点id"))
|
||||||
|
|
||||||
node_data = serializers.DictField(required=False, error_messages=ErrMessage.char("节点参数"))
|
node_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.char("节点参数"))
|
||||||
application_id = serializers.UUIDField(required=False, allow_null=True, error_messages=ErrMessage.uuid("应用id"))
|
application_id = serializers.UUIDField(required=False, allow_null=True, error_messages=ErrMessage.uuid("应用id"))
|
||||||
client_id = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端id"))
|
client_id = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端id"))
|
||||||
client_type = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端类型"))
|
client_type = serializers.CharField(required=True, error_messages=ErrMessage.char("客户端类型"))
|
||||||
form_data = serializers.DictField(required=False, error_messages=ErrMessage.char("全局变量"))
|
form_data = serializers.DictField(required=False, error_messages=ErrMessage.char("全局变量"))
|
||||||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
|
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list("图片"))
|
||||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
|
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list("文档"))
|
||||||
|
child_node = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict("子节点"))
|
||||||
|
|
||||||
def is_valid_application_workflow(self, *, raise_exception=False):
|
def is_valid_application_workflow(self, *, raise_exception=False):
|
||||||
self.is_valid_intraday_access_num()
|
self.is_valid_intraday_access_num()
|
||||||
@ -353,7 +354,7 @@ class ChatMessageSerializer(serializers.Serializer):
|
|||||||
'user_id': user_id}, WorkFlowPostHandler(chat_info, client_id, client_type),
|
'user_id': user_id}, WorkFlowPostHandler(chat_info, client_id, client_type),
|
||||||
base_to_response, form_data, image_list, document_list,
|
base_to_response, form_data, image_list, document_list,
|
||||||
self.data.get('runtime_node_id'),
|
self.data.get('runtime_node_id'),
|
||||||
self.data.get('node_data'), chat_record)
|
self.data.get('node_data'), chat_record, self.data.get('child_node'))
|
||||||
r = work_flow_manage.run()
|
r = work_flow_manage.run()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,8 @@ class ChatView(APIView):
|
|||||||
'node_id': request.data.get('node_id', None),
|
'node_id': request.data.get('node_id', None),
|
||||||
'runtime_node_id': request.data.get('runtime_node_id', None),
|
'runtime_node_id': request.data.get('runtime_node_id', None),
|
||||||
'node_data': request.data.get('node_data', {}),
|
'node_data': request.data.get('node_data', {}),
|
||||||
'chat_record_id': request.data.get('chat_record_id')}
|
'chat_record_id': request.data.get('chat_record_id'),
|
||||||
|
'child_node': request.data.get('child_node')}
|
||||||
).chat()
|
).chat()
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False)
|
@action(methods=['GET'], detail=False)
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class OpenaiToResponse(BaseToResponse):
|
|||||||
def to_stream_chunk_response(self, chat_id, chat_record_id, node_id, up_node_id_list, content, is_end, completion_tokens,
|
def to_stream_chunk_response(self, chat_id, chat_record_id, node_id, up_node_id_list, content, is_end, completion_tokens,
|
||||||
prompt_tokens, other_params: dict = None):
|
prompt_tokens, other_params: dict = None):
|
||||||
chunk = ChatCompletionChunk(id=chat_record_id, model='', object='chat.completion.chunk',
|
chunk = ChatCompletionChunk(id=chat_record_id, model='', object='chat.completion.chunk',
|
||||||
created=datetime.datetime.now().second, choices=[
|
created=datetime.datetime.now().second,choices=[
|
||||||
Choice(delta=ChoiceDelta(content=content, chat_id=chat_id), finish_reason='stop' if is_end else None,
|
Choice(delta=ChoiceDelta(content=content, chat_id=chat_id), finish_reason='stop' if is_end else None,
|
||||||
index=0)],
|
index=0)],
|
||||||
usage=CompletionUsage(completion_tokens=completion_tokens,
|
usage=CompletionUsage(completion_tokens=completion_tokens,
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class SystemToResponse(BaseToResponse):
|
|||||||
prompt_tokens, other_params: dict = None):
|
prompt_tokens, other_params: dict = None):
|
||||||
if other_params is None:
|
if other_params is None:
|
||||||
other_params = {}
|
other_params = {}
|
||||||
chunk = json.dumps({'chat_id': str(chat_id), 'id': str(chat_record_id), 'operate': True,
|
chunk = json.dumps({'chat_id': str(chat_id), 'chat_record_id': str(chat_record_id), 'operate': True,
|
||||||
'content': content, 'node_id': node_id, 'up_node_id_list': up_node_id_list, 'is_end': is_end,
|
'content': content, 'node_id': node_id, 'up_node_id_list': up_node_id_list, 'is_end': is_end,
|
||||||
'usage': {'completion_tokens': completion_tokens,
|
'usage': {'completion_tokens': completion_tokens,
|
||||||
'prompt_tokens': prompt_tokens,
|
'prompt_tokens': prompt_tokens,
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
@date:2024/8/19 14:13
|
@date:2024/8/19 14:13
|
||||||
@desc:
|
@desc:
|
||||||
"""
|
"""
|
||||||
import datetime
|
|
||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
from typing import List
|
from typing import List
|
||||||
@ -17,7 +16,7 @@ from django.db.models import QuerySet
|
|||||||
from common.config.embedding_config import ModelManage
|
from common.config.embedding_config import ModelManage
|
||||||
from common.event import ListenerManagement, UpdateProblemArgs, UpdateEmbeddingDatasetIdArgs, \
|
from common.event import ListenerManagement, UpdateProblemArgs, UpdateEmbeddingDatasetIdArgs, \
|
||||||
UpdateEmbeddingDocumentIdArgs
|
UpdateEmbeddingDocumentIdArgs
|
||||||
from dataset.models import Document, Status, TaskType, State
|
from dataset.models import Document, TaskType, State
|
||||||
from ops import celery_app
|
from ops import celery_app
|
||||||
from setting.models import Model
|
from setting.models import Model
|
||||||
from setting.models_provider import get_model
|
from setting.models_provider import get_model
|
||||||
|
|||||||
@ -23,8 +23,9 @@ interface ApplicationFormType {
|
|||||||
tts_type?: string
|
tts_type?: string
|
||||||
}
|
}
|
||||||
interface Chunk {
|
interface Chunk {
|
||||||
|
real_node_id: string
|
||||||
chat_id: string
|
chat_id: string
|
||||||
id: string
|
chat_record_id: string
|
||||||
content: string
|
content: string
|
||||||
node_id: string
|
node_id: string
|
||||||
up_node_id: string
|
up_node_id: string
|
||||||
@ -32,13 +33,20 @@ interface Chunk {
|
|||||||
node_is_end: boolean
|
node_is_end: boolean
|
||||||
node_type: string
|
node_type: string
|
||||||
view_type: string
|
view_type: string
|
||||||
|
runtime_node_id: string
|
||||||
|
child_node: any
|
||||||
}
|
}
|
||||||
interface chatType {
|
interface chatType {
|
||||||
id: string
|
id: string
|
||||||
problem_text: string
|
problem_text: string
|
||||||
answer_text: string
|
answer_text: string
|
||||||
buffer: Array<String>
|
buffer: Array<String>
|
||||||
answer_text_list: Array<string>
|
answer_text_list: Array<{
|
||||||
|
content: string
|
||||||
|
chat_record_id?: string
|
||||||
|
runtime_node_id?: string
|
||||||
|
child_node?: any
|
||||||
|
}>
|
||||||
/**
|
/**
|
||||||
* 是否写入结束
|
* 是否写入结束
|
||||||
*/
|
*/
|
||||||
@ -92,15 +100,24 @@ export class ChatRecordManage {
|
|||||||
this.write_ed = false
|
this.write_ed = false
|
||||||
this.node_list = []
|
this.node_list = []
|
||||||
}
|
}
|
||||||
append_answer(chunk_answer: string, index?: number) {
|
append_answer(
|
||||||
this.chat.answer_text_list[index != undefined ? index : this.chat.answer_text_list.length - 1] =
|
chunk_answer: string,
|
||||||
this.chat.answer_text_list[
|
index?: number,
|
||||||
index !== undefined ? index : this.chat.answer_text_list.length - 1
|
chat_record_id?: string,
|
||||||
]
|
runtime_node_id?: string,
|
||||||
? this.chat.answer_text_list[
|
child_node?: any
|
||||||
index !== undefined ? index : this.chat.answer_text_list.length - 1
|
) {
|
||||||
] + chunk_answer
|
const set_index = index != undefined ? index : this.chat.answer_text_list.length - 1
|
||||||
: chunk_answer
|
const content = this.chat.answer_text_list[set_index]
|
||||||
|
? this.chat.answer_text_list[set_index].content + chunk_answer
|
||||||
|
: chunk_answer
|
||||||
|
this.chat.answer_text_list[set_index] = {
|
||||||
|
content: content,
|
||||||
|
chat_record_id,
|
||||||
|
runtime_node_id,
|
||||||
|
child_node
|
||||||
|
}
|
||||||
|
|
||||||
this.chat.answer_text = this.chat.answer_text + chunk_answer
|
this.chat.answer_text = this.chat.answer_text + chunk_answer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,14 +144,22 @@ export class ChatRecordManage {
|
|||||||
run_node.view_type == 'single_view' ||
|
run_node.view_type == 'single_view' ||
|
||||||
(run_node.view_type == 'many_view' && current_up_node.view_type == 'single_view')
|
(run_node.view_type == 'many_view' && current_up_node.view_type == 'single_view')
|
||||||
) {
|
) {
|
||||||
const none_index = this.chat.answer_text_list.indexOf('')
|
const none_index = this.findIndex(
|
||||||
|
this.chat.answer_text_list,
|
||||||
|
(item) => item.content == '',
|
||||||
|
'index'
|
||||||
|
)
|
||||||
if (none_index > -1) {
|
if (none_index > -1) {
|
||||||
answer_text_list_index = none_index
|
answer_text_list_index = none_index
|
||||||
} else {
|
} else {
|
||||||
answer_text_list_index = this.chat.answer_text_list.length
|
answer_text_list_index = this.chat.answer_text_list.length
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const none_index = this.chat.answer_text_list.indexOf('')
|
const none_index = this.findIndex(
|
||||||
|
this.chat.answer_text_list,
|
||||||
|
(item) => item.content === '',
|
||||||
|
'index'
|
||||||
|
)
|
||||||
if (none_index > -1) {
|
if (none_index > -1) {
|
||||||
answer_text_list_index = none_index
|
answer_text_list_index = none_index
|
||||||
} else {
|
} else {
|
||||||
@ -152,6 +177,19 @@ export class ChatRecordManage {
|
|||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
findIndex<T>(array: Array<T>, find: (item: T) => boolean, type: 'last' | 'index') {
|
||||||
|
let set_index = -1
|
||||||
|
for (let index = 0; index < array.length; index++) {
|
||||||
|
const element = array[index]
|
||||||
|
if (find(element)) {
|
||||||
|
set_index = index
|
||||||
|
if (type == 'index') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set_index
|
||||||
|
}
|
||||||
closeInterval() {
|
closeInterval() {
|
||||||
this.chat.write_ed = true
|
this.chat.write_ed = true
|
||||||
this.write_ed = true
|
this.write_ed = true
|
||||||
@ -161,7 +199,11 @@ export class ChatRecordManage {
|
|||||||
if (this.id) {
|
if (this.id) {
|
||||||
clearInterval(this.id)
|
clearInterval(this.id)
|
||||||
}
|
}
|
||||||
const last_index = this.chat.answer_text_list.lastIndexOf('')
|
const last_index = this.findIndex(
|
||||||
|
this.chat.answer_text_list,
|
||||||
|
(item) => item.content == '',
|
||||||
|
'last'
|
||||||
|
)
|
||||||
if (last_index > 0) {
|
if (last_index > 0) {
|
||||||
this.chat.answer_text_list.splice(last_index, 1)
|
this.chat.answer_text_list.splice(last_index, 1)
|
||||||
}
|
}
|
||||||
@ -193,19 +235,29 @@ export class ChatRecordManage {
|
|||||||
)
|
)
|
||||||
this.append_answer(
|
this.append_answer(
|
||||||
(divider_content ? divider_content.splice(0).join('') : '') + context.join(''),
|
(divider_content ? divider_content.splice(0).join('') : '') + context.join(''),
|
||||||
answer_text_list_index
|
answer_text_list_index,
|
||||||
|
current_node.chat_record_id,
|
||||||
|
current_node.runtime_node_id,
|
||||||
|
current_node.child_node
|
||||||
)
|
)
|
||||||
} else if (this.is_close) {
|
} else if (this.is_close) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const node_info = this.get_run_node()
|
const node_info = this.get_run_node()
|
||||||
|
|
||||||
if (node_info == undefined) {
|
if (node_info == undefined) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
this.append_answer(
|
this.append_answer(
|
||||||
(node_info.divider_content ? node_info.divider_content.splice(0).join('') : '') +
|
(node_info.divider_content ? node_info.divider_content.splice(0).join('') : '') +
|
||||||
node_info.current_node.buffer.splice(0).join(''),
|
node_info.current_node.buffer.splice(0).join(''),
|
||||||
node_info.answer_text_list_index
|
node_info.answer_text_list_index,
|
||||||
|
current_node.chat_record_id,
|
||||||
|
current_node.runtime_node_id,
|
||||||
|
current_node.child_node
|
||||||
)
|
)
|
||||||
|
if (node_info.current_node.buffer.length == 0) {
|
||||||
|
node_info.current_node.is_end = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.closeInterval()
|
this.closeInterval()
|
||||||
} else {
|
} else {
|
||||||
@ -213,7 +265,10 @@ export class ChatRecordManage {
|
|||||||
if (s !== undefined) {
|
if (s !== undefined) {
|
||||||
this.append_answer(
|
this.append_answer(
|
||||||
(divider_content ? divider_content.splice(0).join('') : '') + s,
|
(divider_content ? divider_content.splice(0).join('') : '') + s,
|
||||||
answer_text_list_index
|
answer_text_list_index,
|
||||||
|
current_node.chat_record_id,
|
||||||
|
current_node.runtime_node_id,
|
||||||
|
current_node.child_node
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,16 +290,18 @@ export class ChatRecordManage {
|
|||||||
this.is_stop = false
|
this.is_stop = false
|
||||||
}
|
}
|
||||||
appendChunk(chunk: Chunk) {
|
appendChunk(chunk: Chunk) {
|
||||||
let n = this.node_list.find(
|
let n = this.node_list.find((item) => item.real_node_id == chunk.real_node_id)
|
||||||
(item) => item.node_id == chunk.node_id && item.up_node_id === chunk.up_node_id
|
|
||||||
)
|
|
||||||
if (n) {
|
if (n) {
|
||||||
n.buffer.push(...chunk.content)
|
n.buffer.push(...chunk.content)
|
||||||
} else {
|
} else {
|
||||||
n = {
|
n = {
|
||||||
buffer: [...chunk.content],
|
buffer: [...chunk.content],
|
||||||
|
real_node_id: chunk.real_node_id,
|
||||||
node_id: chunk.node_id,
|
node_id: chunk.node_id,
|
||||||
|
chat_record_id: chunk.chat_record_id,
|
||||||
up_node_id: chunk.up_node_id,
|
up_node_id: chunk.up_node_id,
|
||||||
|
runtime_node_id: chunk.runtime_node_id,
|
||||||
|
child_node: chunk.child_node,
|
||||||
node_type: chunk.node_type,
|
node_type: chunk.node_type,
|
||||||
index: this.node_list.length,
|
index: this.node_list.length,
|
||||||
view_type: chunk.view_type,
|
view_type: chunk.view_type,
|
||||||
@ -257,9 +314,12 @@ export class ChatRecordManage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
append(answer_text_block: string) {
|
append(answer_text_block: string) {
|
||||||
const index =this.chat.answer_text_list.indexOf("")
|
let set_index = this.findIndex(
|
||||||
this.chat.answer_text_list[index]=answer_text_block
|
this.chat.answer_text_list,
|
||||||
|
(item) => item.content == '',
|
||||||
|
'index'
|
||||||
|
)
|
||||||
|
this.chat.answer_text_list[set_index] = { content: answer_text_block }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="item-content mb-16 lighter">
|
<div class="item-content mb-16 lighter">
|
||||||
<template v-for="(answer_text, index) in chatRecord.answer_text_list" :key="index">
|
<template v-for="(answer_text, index) in answer_text_list" :key="index">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img v-if="application.avatar" :src="application.avatar" height="32px" width="32px" />
|
<img v-if="application.avatar" :src="application.avatar" height="32px" width="32px" />
|
||||||
<LogoIcon v-else height="32px" width="32px" />
|
<LogoIcon v-else height="32px" width="32px" />
|
||||||
@ -9,14 +9,18 @@
|
|||||||
<el-card shadow="always" class="dialog-card mb-8">
|
<el-card shadow="always" class="dialog-card mb-8">
|
||||||
<MdRenderer
|
<MdRenderer
|
||||||
v-if="
|
v-if="
|
||||||
(chatRecord.write_ed === undefined || chatRecord.write_ed === true) && !answer_text
|
(chatRecord.write_ed === undefined || chatRecord.write_ed === true) &&
|
||||||
|
!answer_text.content
|
||||||
"
|
"
|
||||||
source=" 抱歉,没有查找到相关内容,请重新描述您的问题或提供更多信息。"
|
source=" 抱歉,没有查找到相关内容,请重新描述您的问题或提供更多信息。"
|
||||||
></MdRenderer>
|
></MdRenderer>
|
||||||
<MdRenderer
|
<MdRenderer
|
||||||
|
:chat_record_id="answer_text.chat_record_id"
|
||||||
|
:child_node="answer_text.child_node"
|
||||||
|
:runtime_node_id="answer_text.runtime_node_id"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
v-else-if="answer_text"
|
v-else-if="answer_text.content"
|
||||||
:source="answer_text"
|
:source="answer_text.content"
|
||||||
:send-message="chatMessage"
|
:send-message="chatMessage"
|
||||||
></MdRenderer>
|
></MdRenderer>
|
||||||
<span v-else-if="chatRecord.is_stop" shadow="always" class="dialog-card">
|
<span v-else-if="chatRecord.is_stop" shadow="always" class="dialog-card">
|
||||||
@ -51,6 +55,7 @@ import KnowledgeSource from '@/components/ai-chat/KnowledgeSource.vue'
|
|||||||
import MdRenderer from '@/components/markdown/MdRenderer.vue'
|
import MdRenderer from '@/components/markdown/MdRenderer.vue'
|
||||||
import OperationButton from '@/components/ai-chat/component/operation-button/index.vue'
|
import OperationButton from '@/components/ai-chat/component/operation-button/index.vue'
|
||||||
import { type chatType } from '@/api/type/application'
|
import { type chatType } from '@/api/type/application'
|
||||||
|
import { computed } from 'vue'
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
chatRecord: chatType
|
chatRecord: chatType
|
||||||
application: any
|
application: any
|
||||||
@ -71,9 +76,17 @@ const chatMessage = (question: string, type: 'old' | 'new', other_params_data?:
|
|||||||
props.sendMessage(question, other_params_data)
|
props.sendMessage(question, other_params_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const add_answer_text_list = (answer_text_list: Array<string>) => {
|
const add_answer_text_list = (answer_text_list: Array<any>) => {
|
||||||
answer_text_list.push('')
|
answer_text_list.push({ content: '' })
|
||||||
}
|
}
|
||||||
|
const answer_text_list = computed(() => {
|
||||||
|
return props.chatRecord.answer_text_list.map((item) => {
|
||||||
|
if (typeof item == 'string') {
|
||||||
|
return { content: item }
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
function showSource(row: any) {
|
function showSource(row: any) {
|
||||||
if (props.type === 'log') {
|
if (props.type === 'log') {
|
||||||
|
|||||||
@ -222,7 +222,7 @@ const getWrite = (chat: any, reader: any, stream: boolean) => {
|
|||||||
for (const index in split) {
|
for (const index in split) {
|
||||||
const chunk = JSON?.parse(split[index].replace('data:', ''))
|
const chunk = JSON?.parse(split[index].replace('data:', ''))
|
||||||
chat.chat_id = chunk.chat_id
|
chat.chat_id = chunk.chat_id
|
||||||
chat.record_id = chunk.id
|
chat.record_id = chunk.chat_record_id
|
||||||
ChatManagement.appendChunk(chat.id, chunk)
|
ChatManagement.appendChunk(chat.id, chunk)
|
||||||
|
|
||||||
if (chunk.is_end) {
|
if (chunk.is_end) {
|
||||||
@ -278,7 +278,7 @@ function chatMessage(chat?: any, problem?: string, re_chat?: boolean, other_para
|
|||||||
id: randomId(),
|
id: randomId(),
|
||||||
problem_text: problem ? problem : inputValue.value.trim(),
|
problem_text: problem ? problem : inputValue.value.trim(),
|
||||||
answer_text: '',
|
answer_text: '',
|
||||||
answer_text_list: [''],
|
answer_text_list: [{ content: '' }],
|
||||||
buffer: [],
|
buffer: [],
|
||||||
write_ed: false,
|
write_ed: false,
|
||||||
is_stop: false,
|
is_stop: false,
|
||||||
|
|||||||
@ -10,7 +10,10 @@
|
|||||||
v-model="form_data"
|
v-model="form_data"
|
||||||
:model="form_data"
|
:model="form_data"
|
||||||
></DynamicsForm>
|
></DynamicsForm>
|
||||||
<el-button :type="is_submit ? 'info' : 'primary'" :disabled="is_submit||loading" @click="submit"
|
<el-button
|
||||||
|
:type="is_submit ? 'info' : 'primary'"
|
||||||
|
:disabled="is_submit || loading"
|
||||||
|
@click="submit"
|
||||||
>提交</el-button
|
>提交</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@ -18,13 +21,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
import DynamicsForm from '@/components/dynamics-form/index.vue'
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(
|
||||||
form_setting: string
|
defineProps<{
|
||||||
loading?:boolean
|
form_setting: string
|
||||||
sendMessage?: (question: string, type: 'old' | 'new', other_params_data?: any) => void
|
loading?: boolean
|
||||||
}>(),{
|
sendMessage?: (question: string, type: 'old' | 'new', other_params_data?: any) => void
|
||||||
loading:false
|
child_node?: any
|
||||||
})
|
chat_record_id?: string
|
||||||
|
runtime_node_id?: string
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
)
|
||||||
const form_setting_data = computed(() => {
|
const form_setting_data = computed(() => {
|
||||||
if (props.form_setting) {
|
if (props.form_setting) {
|
||||||
return JSON.parse(props.form_setting)
|
return JSON.parse(props.form_setting)
|
||||||
@ -69,11 +78,11 @@ const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
|
|||||||
const submit = () => {
|
const submit = () => {
|
||||||
dynamicsFormRef.value?.validate().then(() => {
|
dynamicsFormRef.value?.validate().then(() => {
|
||||||
_submit.value = true
|
_submit.value = true
|
||||||
const setting = JSON.parse(props.form_setting)
|
|
||||||
if (props.sendMessage) {
|
if (props.sendMessage) {
|
||||||
props.sendMessage('', 'old', {
|
props.sendMessage('', 'old', {
|
||||||
runtime_node_id: setting.runtime_node_id,
|
child_node: props.child_node,
|
||||||
chat_record_id: setting.chat_record_id,
|
runtime_node_id: props.runtime_node_id,
|
||||||
|
chat_record_id: props.chat_record_id,
|
||||||
node_data: form_data.value
|
node_data: form_data.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,9 @@
|
|||||||
:option="item.content"
|
:option="item.content"
|
||||||
></EchartsRander>
|
></EchartsRander>
|
||||||
<FormRander
|
<FormRander
|
||||||
|
:chat_record_id="chat_record_id"
|
||||||
|
:runtime_node_id="runtime_node_id"
|
||||||
|
:child_node="child_node"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:send-message="sendMessage"
|
:send-message="sendMessage"
|
||||||
v-else-if="item.type === 'form_rander'"
|
v-else-if="item.type === 'form_rander'"
|
||||||
@ -64,6 +67,9 @@ const props = withDefaults(
|
|||||||
source?: string
|
source?: string
|
||||||
inner_suffix?: boolean
|
inner_suffix?: boolean
|
||||||
sendMessage?: (question: string, type: 'old' | 'new', other_params_data?: any) => void
|
sendMessage?: (question: string, type: 'old' | 'new', other_params_data?: any) => void
|
||||||
|
child_node?: any
|
||||||
|
chat_record_id?: string
|
||||||
|
runtime_node_id?: string
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user