Skip to content

Commit 1ac838b

Browse files
perf: Optimize performance by changing cyclic data retrieval to batch retrieval
1 parent d2e9ea4 commit 1ac838b

2 files changed

Lines changed: 74 additions & 33 deletions

File tree

apps/application/flow/common.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -248,33 +248,56 @@ def is_valid_start_node(self):
248248
def is_valid_model_params(self):
249249
node_list = [node for node in self.nodes if (
250250
node.type == 'ai-chat-node' or node.type == 'question-node' or node.type == 'parameter-extraction-node')]
251+
252+
model_ids = []
253+
nodes_requiring_validation = []
251254
for node in node_list:
252255
if (node.properties.get('node_data', {}).get('model_id_type') or 'custom') == 'reference':
253256
continue
254-
model = QuerySet(Model).filter(id=node.properties.get('node_data', {}).get('model_id')).first()
255-
if model is None:
256-
raise ValidationError(ErrorDetail(
257-
_('The node {node} model does not exist').format(node=node.properties.get("stepName"))))
258-
credential = get_model_credential(model.provider, model.model_type, model.model_name)
259-
model_params_setting = node.properties.get('node_data', {}).get('model_params_setting')
260-
model_params_setting_form = credential.get_model_params_setting_form(
261-
model.model_name)
262-
if model_params_setting is None:
263-
model_params_setting = model_params_setting_form.get_default_form_data()
264-
node.properties.get('node_data', {})['model_params_setting'] = model_params_setting
265-
if node.properties.get('status', 200) != 200:
266-
raise ValidationError(
267-
ErrorDetail(_("Node {node} is unavailable").format(node=node.properties.get("stepName"))))
257+
model_id = node.properties.get('node_data', {}).get('model_id')
258+
if model_id:
259+
model_ids.append(model_id)
260+
nodes_requiring_validation.append((node, model_id))
261+
if model_ids:
262+
# 先批量获取数据
263+
models_map = {str(model.id): model for model in QuerySet(Model).filter(id__in=model_ids)}
264+
# 再循环从map中取数据进行处理
265+
for node, model_id in nodes_requiring_validation:
266+
model = models_map.get(str(model_id))
267+
if model is None:
268+
raise ValidationError(ErrorDetail(
269+
_('The node {node} model does not exist').format(node=node.properties.get("stepName"))))
270+
credential = get_model_credential(model.provider, model.model_type, model.model_name)
271+
model_params_setting = node.properties.get('node_data', {}).get('model_params_setting')
272+
model_params_setting_form = credential.get_model_params_setting_form(
273+
model.model_name)
274+
if model_params_setting is None:
275+
model_params_setting = model_params_setting_form.get_default_form_data()
276+
node.properties.get('node_data', {})['model_params_setting'] = model_params_setting
277+
if node.properties.get('status', 200) != 200:
278+
raise ValidationError(
279+
ErrorDetail(_("Node {node} is unavailable").format(node=node.properties.get("stepName"))))
280+
268281
node_list = [node for node in self.nodes if (node.type == 'function-lib-node')]
282+
283+
function_lib_ids = []
284+
nodes_requiring_tool_validation = []
269285
for node in node_list:
270286
function_lib_id = node.properties.get('node_data', {}).get('function_lib_id')
271287
if function_lib_id is None:
272288
raise ValidationError(ErrorDetail(
273289
_('The library ID of node {node} cannot be empty').format(node=node.properties.get("stepName"))))
274-
f_lib = QuerySet(Tool).filter(id=function_lib_id).first()
275-
if f_lib is None:
276-
raise ValidationError(ErrorDetail(_("The function library for node {node} is not available").format(
277-
node=node.properties.get("stepName"))))
290+
function_lib_ids.append(function_lib_id)
291+
nodes_requiring_tool_validation.append((node, function_lib_id))
292+
if function_lib_ids:
293+
# 先批量获取数据
294+
tools_map = {str(tool.id): tool for tool in QuerySet(Tool).filter(id__in=function_lib_ids)}
295+
# 再循环从map中取数据进行处理
296+
for node, function_lib_id in nodes_requiring_tool_validation:
297+
f_lib = tools_map.get(str(function_lib_id))
298+
if f_lib is None:
299+
raise ValidationError(ErrorDetail(_("The function library for node {node} is not available").format(
300+
node=node.properties.get("stepName"))))
278301

279302
def is_valid_base_node(self):
280303
base_node_list = [node for node in self.nodes if node.id == 'base-node']

apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INo
6060
@param workflow: 工作流管理器
6161
"""
6262
response = node_variable.get("result")
63-
answer = ""
64-
reasoning_content = ""
63+
answer_chunks = []
64+
reasoning_content_chunks = []
6565
model_setting = node.context.get(
6666
"model_setting",
6767
{"reasoning_content_enable": False, "reasoning_content_end": "</think>", "reasoning_content_start": "<think>"},
@@ -81,10 +81,10 @@ def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INo
8181
reasoning_content_chunk = chunk.additional_kwargs.get("reasoning_content", "")
8282
else:
8383
reasoning_content_chunk = reasoning_chunk.get("reasoning_content")
84-
answer += content_chunk
84+
answer_chunks.append(content_chunk)
8585
if reasoning_content_chunk is None:
8686
reasoning_content_chunk = ""
87-
reasoning_content += reasoning_content_chunk
87+
reasoning_content_chunks.append(reasoning_content_chunk)
8888
yield {
8989
"content": content_chunk,
9090
"reasoning_content": reasoning_content_chunk
@@ -93,14 +93,16 @@ def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INo
9393
}
9494

9595
reasoning_chunk = reasoning.get_end_reasoning_content()
96-
answer += reasoning_chunk.get("content")
96+
answer_chunks.append(reasoning_chunk.get("content"))
9797
reasoning_content_chunk = ""
9898
if not response_reasoning_content:
9999
reasoning_content_chunk = reasoning_chunk.get("reasoning_content")
100100
yield {
101101
"content": reasoning_chunk.get("content"),
102102
"reasoning_content": reasoning_content_chunk if model_setting.get("reasoning_content_enable", False) else "",
103103
}
104+
answer = "".join(answer_chunks)
105+
reasoning_content = "".join(reasoning_content_chunks)
104106
_write_context(node_variable, workflow_variable, node, workflow, answer, reasoning_content)
105107

106108

@@ -525,12 +527,20 @@ def _process_videos(self, image, video_model):
525527
if isinstance(image, str) and image.startswith("http"):
526528
videos.append({"type": "video_url", "video_url": {"url": image}})
527529
elif image is not None and len(image) > 0:
530+
# 先批量获取数据
531+
file_ids = [img["file_id"] for img in image if "file_id" in img]
532+
if file_ids:
533+
files_map = {str(f.id): f for f in QuerySet(File).filter(id__in=file_ids)}
534+
else:
535+
files_map = {}
536+
# 再循环从map中取数据进行处理
528537
for img in image:
529538
if "file_id" in img:
530539
file_id = img["file_id"]
531-
file = QuerySet(File).filter(id=file_id).first()
532-
url = video_model.upload_file_and_get_url(file.get_bytes(), file.file_name)
533-
videos.append({"type": "video_url", "video_url": {"url": url}})
540+
file = files_map.get(str(file_id))
541+
if file:
542+
url = video_model.upload_file_and_get_url(file.get_bytes(), file.file_name)
543+
videos.append({"type": "video_url", "video_url": {"url": url}})
534544
elif "url" in img and img["url"].startswith("http"):
535545
videos.append({"type": "video_url", "video_url": {"url": img["url"]}})
536546
return videos
@@ -543,16 +553,24 @@ def _process_images(self, image):
543553
if isinstance(image, str) and image.startswith("http"):
544554
images.append({"type": "image_url", "image_url": {"url": image}})
545555
elif image is not None and len(image) > 0:
556+
# 先批量获取数据
557+
file_ids = [img["file_id"] for img in image if "file_id" in img]
558+
if file_ids:
559+
files_map = {str(f.id): f for f in QuerySet(File).filter(id__in=file_ids)}
560+
else:
561+
files_map = {}
562+
# 再循环从map中取数据进行处理
546563
for img in image:
547564
if "file_id" in img:
548565
file_id = img["file_id"]
549-
file = QuerySet(File).filter(id=file_id).first()
550-
image_bytes = file.get_bytes()
551-
base64_image = base64.b64encode(image_bytes).decode("utf-8")
552-
image_format = what(None, image_bytes)
553-
images.append(
554-
{"type": "image_url", "image_url": {"url": f"data:image/{image_format};base64,{base64_image}"}}
555-
)
566+
file = files_map.get(str(file_id))
567+
if file:
568+
image_bytes = file.get_bytes()
569+
base64_image = base64.b64encode(image_bytes).decode("utf-8")
570+
image_format = what(None, image_bytes)
571+
images.append(
572+
{"type": "image_url", "image_url": {"url": f"data:image/{image_format};base64,{base64_image}"}}
573+
)
556574
elif "url" in img and img["url"].startswith("http"):
557575
images.append({"type": "image_url", "image_url": {"url": img["url"]}})
558576
return images

0 commit comments

Comments
 (0)