Skip to content

Commit bf4b77c

Browse files
committed
fix: Use a new structure to save association relationships
1 parent cc9a418 commit bf4b77c

File tree

7 files changed

+156
-150
lines changed

7 files changed

+156
-150
lines changed

apps/application/flow/tools.py

Lines changed: 24 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import queue
1212
import re
1313
import threading
14+
from functools import reduce
1415
from typing import Iterator
1516
from maxkb.const import CONFIG
1617
from django.http import StreamingHttpResponse
@@ -435,8 +436,8 @@ async def anext_async(agen):
435436

436437
target_source_node_mapping = {
437438
'TOOL': {'tool-lib-node': lambda n: [n.get('properties').get('node_data').get('tool_lib_id')],
438-
'ai-chat-node': lambda n: [...([n.get('properties').get('node_data').get('mcp_tool_ids')] or []),
439-
...([n.get('properties').get('node_data').get('tool_ids')] or [])]},
439+
'ai-chat-node': lambda n: [*([n.get('properties').get('node_data').get('mcp_tool_ids')] or []),
440+
*([n.get('properties').get('node_data').get('tool_ids')] or [])]},
440441
'MODEL': {'ai-chat-node': lambda n: [n.get('properties').get('node_data').get('model_id')],
441442
'question-node': lambda n: [n.get('properties').get('node_data').get('model_id')],
442443
'speech-to-text-node': lambda n: [n.get('properties').get('node_data').get('stt_model_id')],
@@ -488,14 +489,28 @@ def get_workflow_resource(workflow, node_handle):
488489
return []
489490

490491

491-
def get_instance_resource(instance, source_type, source_id, target_type, field_call_list):
492+
application_instance_field_call_dict = {
493+
'TOOL': [lambda instance: instance.mcp_tool_ids or [], lambda instance: instance.tool_ids or []],
494+
'MODEL': [lambda instance: [instance.model_id] if instance.model_id else [],
495+
lambda instance: [instance.tts_model_id] if instance.tts_model_id else [],
496+
lambda instance: [instance.stt_model_id] if instance.stt_model_id else []]
497+
}
498+
knowledge_instance_field_call_dict = {
499+
'MODEL': [lambda instance: [instance.model_id] if instance.model_id else [],
500+
lambda instance: [instance.tts_model_id] if instance.tts_model_id else [],
501+
lambda instance: [instance.stt_model_id] if instance.stt_model_id else []],
502+
}
503+
504+
505+
def get_instance_resource(instance, source_type, source_id, instance_field_call_dict):
492506
response = []
493507
from system_manage.models.resource_mapping import ResourceMapping
494-
for field_call in field_call_list:
495-
target_id = field_call(instance)
496-
if target_id:
497-
response.append(ResourceMapping(source_type=source_type, target_type=target_type, source_id=source_id,
498-
target_id=target_id))
508+
for target_type, call_list in instance_field_call_dict.items():
509+
target_id_list = reduce(lambda x, y: [*x, *y], [call(instance) for call in call_list], [])
510+
if target_id_list:
511+
for target_id in target_id_list:
512+
response.append(ResourceMapping(source_type=source_type, target_type=target_type, source_id=source_id,
513+
target_id=target_id))
499514
return response
500515

501516

@@ -508,85 +523,12 @@ def save_workflow_mapping(workflow, source_type, source_id, other_resource_mappi
508523
resource_mapping_list = get_workflow_resource(workflow,
509524
get_node_handle_callback(source_type,
510525
source_id))
526+
resource_mapping_list += other_resource_mapping
511527
if resource_mapping_list:
512-
resource_mapping_list += other_resource_mapping
513528
QuerySet(ResourceMapping).bulk_create(
514529
{(str(item.target_type) + str(item.target_id)): item for item in resource_mapping_list}.values())
515530

516531

517-
def save_simple_mapping(application, source_type, source_id):
518-
"""
519-
保存应用资源映射关系
520-
521-
Args:
522-
application: 应用对象
523-
source_type: 源类型
524-
source_id: 源ID
525-
"""
526-
from system_manage.models.resource_mapping import ResourceMapping
527-
from django.db.models import QuerySet
528-
from application.models import ApplicationKnowledgeMapping # 假设模型在此处定义
529-
from system_manage.models.resource_mapping import ResourceType
530-
# 删除原有映射关系
531-
QuerySet(ResourceMapping).filter(source_type=source_type, source_id=source_id).delete()
532-
533-
# 构建资源映射列表
534-
resource_mapping_list = []
535-
536-
# 定义模型ID字段映射
537-
model_fields = ['model_id', 'tts_model_id', 'stt_model_id']
538-
for field in model_fields:
539-
model_id = getattr(application, field, None)
540-
if model_id:
541-
resource_mapping_list.append(ResourceMapping(
542-
source_type=source_type,
543-
target_type=ResourceType.MODEL,
544-
source_id=source_id,
545-
target_id=model_id
546-
))
547-
548-
# 定义工具ID字段映射
549-
tool_fields = ['mcp_tool_ids', 'tool_ids']
550-
for field in tool_fields:
551-
tool_ids = getattr(application, field, []) or []
552-
resource_mapping_list.extend([
553-
ResourceMapping(
554-
source_type=source_type,
555-
target_type=ResourceType.TOOL,
556-
source_id=source_id,
557-
target_id=tool_id
558-
) for tool_id in tool_ids if tool_id
559-
])
560-
561-
# 处理知识库映射
562-
knowledge_mappings = ApplicationKnowledgeMapping.objects.filter(
563-
application_id=application.id
564-
)
565-
resource_mapping_list.extend([
566-
ResourceMapping(
567-
source_type=source_type,
568-
target_type=ResourceType.KNOWLEDGE,
569-
source_id=source_id,
570-
target_id=km.knowledge_id
571-
) for km in knowledge_mappings
572-
])
573-
574-
# 处理应用ID映射
575-
application_ids = getattr(application, 'application_ids', []) or []
576-
resource_mapping_list.extend([
577-
ResourceMapping(
578-
source_type=source_type,
579-
target_type=ResourceType.APPLICATION,
580-
source_id=source_id,
581-
target_id=app_id
582-
) for app_id in application_ids if app_id
583-
])
584-
585-
# 批量创建资源映射
586-
if resource_mapping_list:
587-
QuerySet(ResourceMapping).bulk_create(resource_mapping_list)
588-
589-
590532
def get_tool_id_list(workflow):
591533
_result = []
592534
for node in workflow.get('nodes', []):

apps/application/serializers/application.py

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from rest_framework.utils.formatting import lazy_format
3131

3232
from application.flow.common import Workflow
33-
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
33+
from application.models.application import Application, ApplicationTypeChoices, \
3434
ApplicationFolder, ApplicationVersion
3535
from application.models.application_access_token import ApplicationAccessToken
3636
from application.serializers.common import update_resource_mapping_by_application
@@ -541,7 +541,9 @@ def insert_workflow(self, instance: Dict):
541541

542542
@staticmethod
543543
def to_application_knowledge_mapping(application_id: str, knowledge_id: str):
544-
return ApplicationKnowledgeMapping(id=uuid.uuid7(), application_id=application_id, knowledge_id=knowledge_id)
544+
return ResourceMapping(id=uuid.uuid7(), source_id=application_id, target_id=knowledge_id,
545+
source_type="APPLICATION",
546+
target_type="KNOWLEDGE")
545547

546548
def insert_simple(self, instance: Dict):
547549
self.is_valid(raise_exception=True)
@@ -560,7 +562,7 @@ def insert_simple(self, instance: Dict):
560562
ApplicationAccessToken(application_id=application_model.id,
561563
access_token=hashlib.md5(str(uuid.uuid7()).encode()).hexdigest()[8:24]).save()
562564
# 插入关联数据
563-
QuerySet(ApplicationKnowledgeMapping).bulk_create(application_knowledge_mapping_model_list)
565+
QuerySet(ResourceMapping).bulk_create(application_knowledge_mapping_model_list)
564566
return ApplicationCreateSerializer.ApplicationResponse(application_model).data
565567

566568
@transaction.atomic
@@ -785,7 +787,6 @@ def delete(self, with_valid=True):
785787
self.is_valid()
786788
application_id = self.data.get('application_id')
787789
QuerySet(ApplicationVersion).filter(application_id=application_id).delete()
788-
QuerySet(ApplicationKnowledgeMapping).filter(application_id=application_id).delete()
789790
QuerySet(ResourceMapping).filter(
790791
Q(target_id=application_id) | Q(source_id=application_id)
791792
).delete()
@@ -884,7 +885,6 @@ def publish(self, instance, with_valid=True):
884885
application_access_token.save()
885886
else:
886887
access_token = application_access_token.access_token
887-
update_resource_mapping_by_application(self.data.get("application_id"))
888888
del_application_access_token(access_token)
889889
return self.one(with_valid=False)
890890

@@ -921,6 +921,19 @@ def update_work_flow_model(instance):
921921
if 'name' in node_data:
922922
instance['name'] = node_data['name']
923923
break
924+
knowledge_node_list = ApplicationOperateSerializer.get_search_node(instance.get('work_flow'))
925+
for knowledge_node in knowledge_node_list:
926+
node_data = knowledge_node.get('properties').get('node_data')
927+
# 全部知识库id
928+
all_knowledge_id_list = node_data.get('all_knowledge_id_list') or []
929+
# 用户修改的知识库id
930+
knowledge_id_list = node_data.get('knowledge_id_list') or []
931+
# 用户可以看到的知识库
932+
knowledge_list = node_data.get('knowledge_list') or []
933+
view_knowledge_id_list = [knowledge.get('id') for knowledge in knowledge_list]
934+
other_knowledge_id_list = [knowledge_id for knowledge_id in all_knowledge_id_list if
935+
not view_knowledge_id_list.__contains__(knowledge_id)]
936+
node_data['knowledge_id_list'] = other_knowledge_id_list + knowledge_id_list
924937

925938
@transaction.atomic
926939
def edit(self, instance: Dict, with_valid=True):
@@ -972,19 +985,25 @@ def edit(self, instance: Dict, with_valid=True):
972985
if update_key in instance and instance.get(update_key) is not None:
973986
application.__setattr__(update_key, instance.get(update_key))
974987
application.save()
975-
988+
# 当前用户可修改关联的知识库列表
989+
application_knowledge_id_list = [str(knowledge.get('id')) for knowledge in
990+
self.list_knowledge(with_valid=False)]
991+
knowledge_id_list = []
976992
if 'knowledge_id_list' in instance:
977-
knowledge_id_list = instance.get('knowledge_id_list')
978993
# 当前用户可修改关联的知识库列表
979994
application_knowledge_id_list = [str(knowledge.get('id')) for knowledge in
980995
self.list_knowledge(with_valid=False)]
996+
knowledge_id_list = instance.get('knowledge_id_list')
981997
for knowledge_id in knowledge_id_list:
982998
if not application_knowledge_id_list.__contains__(knowledge_id):
983999
message = lazy_format(_('Unknown knowledge base id {dataset_id}, unable to associate'),
9841000
dataset_id=knowledge_id)
9851001
raise AppApiException(500, str(message))
9861002

987-
self.save_application_knowledge_mapping(application_knowledge_id_list, knowledge_id_list, application_id)
1003+
update_resource_mapping_by_application(application_id,
1004+
self.get_application_knowledge_mapping(application_knowledge_id_list,
1005+
knowledge_id_list,
1006+
application_id))
9881007
return self.one(with_valid=False)
9891008

9901009
def update_template_workflow(self, instance: Dict, app: Application):
@@ -1074,9 +1093,11 @@ def one(self, with_valid=True):
10741093
knowledge_list = []
10751094
knowledge_id_list = []
10761095
if application.type == 'SIMPLE':
1077-
mapping_knowledge_list = QuerySet(ApplicationKnowledgeMapping).filter(application_id=application_id)
1078-
knowledge_list = [available_knowledge_dict.get(str(km.knowledge_id)) for km in mapping_knowledge_list if
1079-
available_knowledge_dict.__contains__(str(km.knowledge_id))]
1096+
mapping_knowledge_list = QuerySet(ResourceMapping).filter(source_id=application_id,
1097+
source_type="APPLICATION",
1098+
target_type="KNOWLEDGE")
1099+
knowledge_list = [available_knowledge_dict.get(str(km.target_id)) for km in mapping_knowledge_list if
1100+
available_knowledge_dict.__contains__(str(km.target_id))]
10801101
knowledge_id_list = [k.get('id') for k in knowledge_list]
10811102
else:
10821103
self.update_knowledge_node(application.work_flow, available_knowledge_dict)
@@ -1089,7 +1110,17 @@ def one(self, with_valid=True):
10891110
def get_search_node(work_flow):
10901111
if work_flow is None:
10911112
return []
1092-
return [node for node in work_flow.get('nodes', []) if node.get('type', '') == 'search-knowledge-node']
1113+
response = []
1114+
if 'nodes' in work_flow:
1115+
for node in work_flow.get('nodes'):
1116+
if node.get('type', '') == 'search-knowledge-node':
1117+
response.append(node)
1118+
if node.get('type') == 'loop-node':
1119+
r = ApplicationOperateSerializer.get_search_node(
1120+
node.get('properties', {}).get('node_data', {}).get('loop_body'))
1121+
for rn in r:
1122+
response.append(rn)
1123+
return response
10931124

10941125
def update_knowledge_node(self, workflow, available_knowledge_dict):
10951126
"""
@@ -1143,14 +1174,39 @@ def list_knowledge(self, with_valid=True):
11431174
def save_application_knowledge_mapping(application_knowledge_id_list, knowledge_id_list, application_id):
11441175
# 需要排除已删除的数据集
11451176
knowledge_id_list = [knowledge.id for knowledge in QuerySet(Knowledge).filter(id__in=knowledge_id_list)]
1177+
11461178
# 删除已经关联的id
1147-
QuerySet(ApplicationKnowledgeMapping).filter(knowledge_id__in=application_knowledge_id_list,
1148-
application_id=application_id).delete()
1179+
QuerySet(ResourceMapping).filter(target_id__in=application_knowledge_id_list,
1180+
source_id=application_id,
1181+
source_type='APPLICATION',
1182+
target_type="KNOWLEDGE").delete()
11491183
# 插入
1150-
QuerySet(ApplicationKnowledgeMapping).bulk_create(
1151-
[ApplicationKnowledgeMapping(application_id=application_id, knowledge_id=knowledge_id) for knowledge_id in
1184+
QuerySet(ResourceMapping).bulk_create(
1185+
[ResourceMapping(source_id=application_id, target_id=knowledge_id, source_type='APPLICATION',
1186+
target_type="KNOWLEDGE") for knowledge_id in
11521187
knowledge_id_list]) if len(knowledge_id_list) > 0 else None
11531188

1189+
@staticmethod
1190+
def get_application_knowledge_mapping(application_knowledge_id_list, knowledge_id_list, application_id):
1191+
"""
1192+
1193+
@param application_knowledge_id_list: 当前应用可修改的知识库列表
1194+
@param knowledge_id_list: 用户修改的知识库列表
1195+
@param application_id: 应用id
1196+
@return:
1197+
"""
1198+
# 当前知识库和应用已关联列表
1199+
knowledge_application_mapping_list = QuerySet(ResourceMapping).filter(source_id=application_id,
1200+
source_type='APPLICATION',
1201+
target_type="KNOWLEDGE",
1202+
).exclude(
1203+
target_id__in=application_knowledge_id_list)
1204+
edit_knowledge_list = [ResourceMapping(source_id=application_id, target_id=knowledge_id,
1205+
source_type='APPLICATION',
1206+
target_type="KNOWLEDGE")
1207+
for knowledge_id in knowledge_id_list]
1208+
return list(knowledge_application_mapping_list) + edit_knowledge_list
1209+
11541210
def speech_to_text(self, instance, debug=True, with_valid=True):
11551211
if with_valid:
11561212
self.is_valid(raise_exception=True)

0 commit comments

Comments
 (0)