66 @date:2025/5/26 17:03
77 @desc:
88"""
9+ import asyncio
910import datetime
1011import hashlib
12+ import json
1113import os
1214import pickle
1315import re
1921from django .db .models import QuerySet , Q
2022from django .http import HttpResponse
2123from django .utils .translation import gettext_lazy as _
24+ from langchain_mcp_adapters .client import MultiServerMCPClient
2225from rest_framework import serializers , status
2326from rest_framework .utils .formatting import lazy_format
2427
3639from knowledge .serializers .knowledge import KnowledgeSerializer , KnowledgeModelSerializer
3740from maxkb .conf import PROJECT_DIR
3841from models_provider .models import Model
42+ from models_provider .tools import get_model_instance_by_model_workspace_id
3943from system_manage .models import WorkspaceUserResourcePermission
4044from tools .models import Tool , ToolScope
4145from tools .serializers .tool import ToolModelSerializer
@@ -384,9 +388,9 @@ class ApplicationEditSerializer(serializers.Serializer):
384388 label = _ ("Historical chat records" ))
385389 prologue = serializers .CharField (required = False , allow_null = True , allow_blank = True , max_length = 102400 ,
386390 label = _ ("Opening remarks" ))
387- dataset_id_list = serializers .ListSerializer (required = False , child = serializers .UUIDField (required = True ),
388- label = _ ("Related Knowledge Base" )
389- )
391+ knowledge_id_list = serializers .ListSerializer (required = False , child = serializers .UUIDField (required = True ),
392+ label = _ ("Related Knowledge Base" )
393+ )
390394 # 数据集相关设置
391395 knowledge_setting = KnowledgeSettingSerializer (required = False , allow_null = True ,
392396 label = _ ("Dataset settings" ))
@@ -441,8 +445,8 @@ def insert_workflow(self, instance: Dict):
441445 return ApplicationCreateSerializer .ApplicationResponse (application_model ).data
442446
443447 @staticmethod
444- def to_application_knowledge_mapping (application_id : str , dataset_id : str ):
445- return ApplicationKnowledgeMapping (id = uuid .uuid7 (), application_id = application_id , dataset_id = dataset_id )
448+ def to_application_knowledge_mapping (application_id : str , knowledge_id : str ):
449+ return ApplicationKnowledgeMapping (id = uuid .uuid7 (), application_id = application_id , knowledge_id = knowledge_id )
446450
447451 def insert_simple (self , instance : Dict ):
448452 self .is_valid (raise_exception = True )
@@ -451,10 +455,10 @@ def insert_simple(self, instance: Dict):
451455 ApplicationCreateSerializer .SimplateRequest (data = instance ).is_valid (user_id = user_id , raise_exception = True )
452456 application_model = ApplicationCreateSerializer .SimplateRequest .to_application_model (user_id , workspace_id ,
453457 instance )
454- dataset_id_list = instance .get ('knowledge_id_list' , [])
458+ knowledge_id_list = instance .get ('knowledge_id_list' , [])
455459 application_knowledge_mapping_model_list = [
456- self .to_application_knowledge_mapping (application_model .id , dataset_id ) for
457- dataset_id in dataset_id_list ]
460+ self .to_application_knowledge_mapping (application_model .id , knowledge_id ) for
461+ knowledge_id in knowledge_id_list ]
458462 # 插入应用
459463 application_model .save ()
460464 # 插入认证信息
@@ -519,15 +523,15 @@ def to_tool(tool, workspace_id, user_id):
519523 def to_application (application , workspace_id , user_id ):
520524 work_flow = application .get ('work_flow' )
521525 for node in work_flow .get ('nodes' , []):
522- if node .get ('type' ) == 'search-dataset -node' :
523- node .get ('properties' , {}).get ('node_data' , {})['dataset_id_list ' ] = []
526+ if node .get ('type' ) == 'search-knowledge -node' :
527+ node .get ('properties' , {}).get ('node_data' , {})['knowledge_id_list ' ] = []
524528 return Application (id = uuid .uuid7 (),
525529 user_id = user_id ,
526530 name = application .get ('name' ),
527531 workspace_id = workspace_id ,
528532 desc = application .get ('desc' ),
529533 prologue = application .get ('prologue' ), dialogue_number = application .get ('dialogue_number' ),
530- dataset_setting = application .get ('dataset_setting ' ),
534+ knowledge_setting = application .get ('knowledge_setting ' ),
531535 model_setting = application .get ('model_setting' ),
532536 model_params_setting = application .get ('model_params_setting' ),
533537 tts_model_params_setting = application .get ('tts_model_params_setting' ),
@@ -545,6 +549,27 @@ def to_application(application, workspace_id, user_id):
545549 )
546550
547551
552+ class TextToSpeechRequest (serializers .Serializer ):
553+ text = serializers .CharField (required = True , label = _ ('Text' ))
554+
555+
556+ class SpeechToTextRequest (serializers .Serializer ):
557+ file = UploadedFileField (required = True , label = _ ("file" ))
558+
559+
560+ class PlayDemoTextRequest (serializers .Serializer ):
561+ tts_model_id = serializers .UUIDField (required = True , label = _ ('Text to speech model ID' ))
562+
563+
564+ async def get_mcp_tools (servers ):
565+ async with MultiServerMCPClient (servers ) as client :
566+ return client .get_tools ()
567+
568+
569+ class McpServersSerializer (serializers .Serializer ):
570+ mcp_servers = serializers .JSONField (required = True )
571+
572+
548573class ApplicationOperateSerializer (serializers .Serializer ):
549574 application_id = serializers .UUIDField (required = True , label = _ ("Application ID" ))
550575 user_id = serializers .UUIDField (required = True , label = _ ("User ID" ))
@@ -559,6 +584,23 @@ def is_valid(self, *, raise_exception=False):
559584 if not query_set .exists ():
560585 raise AppApiException (500 , _ ('Application id does not exist' ))
561586
587+ def get_mcp_servers (self , instance , with_valid = True ):
588+ if with_valid :
589+ self .is_valid (raise_exception = True )
590+ McpServersSerializer (data = instance ).is_valid (raise_exception = True )
591+ servers = json .loads (instance .get ('mcp_servers' ))
592+ tools = []
593+ for server in servers :
594+ tools += [
595+ {
596+ 'server' : server ,
597+ 'name' : tool .name ,
598+ 'description' : tool .description ,
599+ 'args_schema' : tool .args_schema ,
600+ }
601+ for tool in asyncio .run (get_mcp_tools ({server : servers [server ]}))]
602+ return tools
603+
562604 def delete (self , with_valid = True ):
563605 if with_valid :
564606 self .is_valid ()
@@ -691,7 +733,7 @@ def edit(self, instance: Dict, with_valid=True):
691733 if application .type == ApplicationTypeChoices .SIMPLE .value :
692734 application .is_publish = True
693735 update_keys = ['name' , 'desc' , 'model_id' , 'multiple_rounds_dialogue' , 'prologue' , 'status' ,
694- 'dataset_setting ' , 'model_setting' , 'problem_optimization' , 'dialogue_number' ,
736+ 'knowledge_setting ' , 'model_setting' , 'problem_optimization' , 'dialogue_number' ,
695737 'stt_model_id' , 'tts_model_id' , 'tts_model_enable' , 'stt_model_enable' , 'tts_type' ,
696738 'tts_autoplay' , 'stt_autosend' , 'file_upload_enable' , 'file_upload_setting' ,
697739 'api_key_is_active' , 'icon' , 'work_flow' , 'model_params_setting' , 'tts_model_params_setting' ,
@@ -746,7 +788,7 @@ def update_knowledge_node(self, workflow, available_knowledge_dict):
746788 """
747789 修改知识库检索节点 数据
748790 定义 all_knowledge_id_list: 所有的关联知识库
749- dataset_id_list : 当前用户可看到的关联知识库列表
791+ knowledge_id_list : 当前用户可看到的关联知识库列表
750792 knowledge_list: 用户
751793 @param workflow: 知识库
752794 @param available_knowledge_dict: 当前用户可用的知识库
@@ -802,3 +844,35 @@ def save_application_knowledge_mapping(application_knowledge_id_list, knowledge_
802844 QuerySet (ApplicationKnowledgeMapping ).bulk_create (
803845 [ApplicationKnowledgeMapping (application_id = application_id , knowledge_id = knowledge_id ) for knowledge_id in
804846 knowledge_id_list ]) if len (knowledge_id_list ) > 0 else None
847+
848+ def speech_to_text (self , instance , with_valid = True ):
849+ if with_valid :
850+ self .is_valid (raise_exception = True )
851+ SpeechToTextRequest (data = instance ).is_valid (raise_exception = True )
852+ application_id = self .data .get ('application_id' )
853+ application = QuerySet (Application ).filter (id = application_id ).first ()
854+ if application .stt_model_enable :
855+ model = get_model_instance_by_model_workspace_id (application .stt_model_id , application .workspace_id )
856+ text = model .speech_to_text (instance .get ('file' ))
857+ return text
858+
859+ def text_to_speech (self , instance , with_valid = True ):
860+ if with_valid :
861+ self .is_valid (raise_exception = True )
862+ TextToSpeechRequest (data = instance ).is_valid (raise_exception = True )
863+ application_id = self .data .get ('application_id' )
864+ application = QuerySet (Application ).filter (id = application_id ).first ()
865+ if application .tts_model_enable :
866+ model = get_model_instance_by_model_workspace_id (application .tts_model_id , application .workspace_id ,
867+ ** application .tts_model_params_setting )
868+
869+ return model .text_to_speech (instance .get ('text' ))
870+
871+ def play_demo_text (self , instance , with_valid = True ):
872+ text = '你好,这里是语音播放测试'
873+ if with_valid :
874+ self .is_valid (raise_exception = True )
875+ PlayDemoTextRequest (data = instance ).is_valid (raise_exception = True )
876+ tts_model_id = instance .pop ('tts_model_id' )
877+ model = get_model_instance_by_model_workspace_id (tts_model_id , self .data .get ('workspace_id' ), ** instance )
878+ return model .text_to_speech (text )
0 commit comments