feat: application operate api (#3176)
This commit is contained in:
parent
b16353fbe8
commit
43654bddaf
@ -12,9 +12,9 @@ from drf_spectacular.utils import OpenApiParameter
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.serializers.application import ApplicationCreateSerializer, ApplicationListResponse, \
|
from application.serializers.application import ApplicationCreateSerializer, ApplicationListResponse, \
|
||||||
ApplicationQueryRequest
|
ApplicationImportRequest, ApplicationEditSerializer
|
||||||
from common.mixins.api_mixin import APIMixin
|
from common.mixins.api_mixin import APIMixin
|
||||||
from common.result import ResultSerializer, ResultPageSerializer
|
from common.result import ResultSerializer, ResultPageSerializer, DefaultResultSerializer
|
||||||
|
|
||||||
|
|
||||||
class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest):
|
class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest):
|
||||||
@ -120,3 +120,50 @@ class ApplicationCreateAPI(APIMixin):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_response():
|
def get_response():
|
||||||
return ApplicationCreateResponse
|
return ApplicationCreateResponse
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationImportAPI(APIMixin):
|
||||||
|
@staticmethod
|
||||||
|
def get_parameters():
|
||||||
|
ApplicationCreateAPI.get_parameters()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_request():
|
||||||
|
return ApplicationImportRequest
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationOperateAPI(APIMixin):
|
||||||
|
@staticmethod
|
||||||
|
def get_parameters():
|
||||||
|
return [
|
||||||
|
OpenApiParameter(
|
||||||
|
name="workspace_id",
|
||||||
|
description="工作空间id",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location='path',
|
||||||
|
required=True,
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="application_id",
|
||||||
|
description="应用id",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location='path',
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationExportAPI(APIMixin):
|
||||||
|
@staticmethod
|
||||||
|
def get_parameters():
|
||||||
|
return ApplicationOperateAPI.get_parameters()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_response():
|
||||||
|
return DefaultResultSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationEditAPI(APIMixin):
|
||||||
|
@staticmethod
|
||||||
|
def get_request():
|
||||||
|
return ApplicationEditSerializer
|
||||||
|
|||||||
@ -8,3 +8,5 @@
|
|||||||
"""
|
"""
|
||||||
from .application import *
|
from .application import *
|
||||||
from .application_access_token import *
|
from .application_access_token import *
|
||||||
|
from .application_chat import *
|
||||||
|
from .application_api_key import *
|
||||||
|
|||||||
@ -117,3 +117,16 @@ class ApplicationKnowledgeMapping(AppModelMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "application_knowledge_mapping"
|
db_table = "application_knowledge_mapping"
|
||||||
|
|
||||||
|
|
||||||
|
class WorkFlowVersion(AppModelMixin):
|
||||||
|
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
|
||||||
|
application = models.ForeignKey(Application, on_delete=models.CASCADE)
|
||||||
|
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
|
||||||
|
name = models.CharField(verbose_name="版本名称", max_length=128, default="")
|
||||||
|
publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True)
|
||||||
|
publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="")
|
||||||
|
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "application_work_flow_version"
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
@ -6,7 +5,6 @@ from django.db import models
|
|||||||
|
|
||||||
from application.models import Application
|
from application.models import Application
|
||||||
from common.mixins.app_model_mixin import AppModelMixin
|
from common.mixins.app_model_mixin import AppModelMixin
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
@ -23,4 +21,19 @@ class ApplicationApiKey(AppModelMixin):
|
|||||||
, default=list)
|
, default=list)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "application_api_key"
|
db_table = "application_api_key"
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationPublicAccessClient(AppModelMixin):
|
||||||
|
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
|
||||||
|
client_id = models.UUIDField(max_length=128, default=uuid.uuid1, verbose_name="公共访问链接客户端id")
|
||||||
|
client_type = models.CharField(max_length=64, verbose_name="客户端类型")
|
||||||
|
application = models.ForeignKey(Application, on_delete=models.CASCADE, verbose_name="应用id")
|
||||||
|
access_num = models.IntegerField(default=0, verbose_name="访问总次数次数")
|
||||||
|
intraday_access_num = models.IntegerField(default=0, verbose_name="当日访问次数")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "application_public_access_client"
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=['application_id', 'client_id']),
|
||||||
|
]
|
||||||
|
|||||||
83
apps/application/models/application_chat.py
Normal file
83
apps/application/models/application_chat.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""
|
||||||
|
@project: MaxKB
|
||||||
|
@Author:虎虎
|
||||||
|
@file: application_chat_log.py
|
||||||
|
@date:2025/5/29 17:12
|
||||||
|
@desc:
|
||||||
|
"""
|
||||||
|
import uuid_utils.compat as uuid
|
||||||
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from langchain_core.messages import HumanMessage, AIMessage
|
||||||
|
|
||||||
|
from application.models import Application
|
||||||
|
from common.encoder.encoder import SystemEncoder
|
||||||
|
from common.mixins.app_model_mixin import AppModelMixin
|
||||||
|
|
||||||
|
|
||||||
|
def default_asker():
|
||||||
|
return {'user_name': '游客'}
|
||||||
|
|
||||||
|
|
||||||
|
class Chat(AppModelMixin):
|
||||||
|
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7(), editable=False, verbose_name="主键id")
|
||||||
|
application = models.ForeignKey(Application, on_delete=models.CASCADE)
|
||||||
|
abstract = models.CharField(max_length=1024, verbose_name="摘要")
|
||||||
|
asker = models.JSONField(verbose_name="访问者", default=default_asker, encoder=SystemEncoder)
|
||||||
|
client_id = models.UUIDField(verbose_name="客户端id", default=None, null=True)
|
||||||
|
is_deleted = models.BooleanField(verbose_name="", default=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "application_chat"
|
||||||
|
|
||||||
|
|
||||||
|
class VoteChoices(models.TextChoices):
|
||||||
|
"""订单类型"""
|
||||||
|
UN_VOTE = "-1", '未投票'
|
||||||
|
STAR = "0", '赞同'
|
||||||
|
TRAMPLE = "1", '反对'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ChatRecord(AppModelMixin):
|
||||||
|
"""
|
||||||
|
对话日志 详情
|
||||||
|
"""
|
||||||
|
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
|
||||||
|
chat = models.ForeignKey(Chat, on_delete=models.CASCADE)
|
||||||
|
vote_status = models.CharField(verbose_name='投票', max_length=10, choices=VoteChoices.choices,
|
||||||
|
default=VoteChoices.UN_VOTE)
|
||||||
|
problem_text = models.CharField(max_length=10240, verbose_name="问题")
|
||||||
|
answer_text = models.CharField(max_length=40960, verbose_name="答案")
|
||||||
|
answer_text_list = ArrayField(verbose_name="改进标注列表",
|
||||||
|
base_field=models.JSONField()
|
||||||
|
, default=list)
|
||||||
|
message_tokens = models.IntegerField(verbose_name="请求token数量", default=0)
|
||||||
|
answer_tokens = models.IntegerField(verbose_name="响应token数量", default=0)
|
||||||
|
const = models.IntegerField(verbose_name="总费用", default=0)
|
||||||
|
details = models.JSONField(verbose_name="对话详情", default=dict, encoder=SystemEncoder)
|
||||||
|
improve_paragraph_id_list = ArrayField(verbose_name="改进标注列表",
|
||||||
|
base_field=models.UUIDField(max_length=128, blank=True)
|
||||||
|
, default=list)
|
||||||
|
run_time = models.FloatField(verbose_name="运行时长", default=0)
|
||||||
|
index = models.IntegerField(verbose_name="对话下标")
|
||||||
|
|
||||||
|
def get_human_message(self):
|
||||||
|
if 'problem_padding' in self.details:
|
||||||
|
return HumanMessage(content=self.details.get('problem_padding').get('padding_problem_text'))
|
||||||
|
return HumanMessage(content=self.problem_text)
|
||||||
|
|
||||||
|
def get_ai_message(self):
|
||||||
|
answer_text = self.answer_text
|
||||||
|
if answer_text is None or len(str(answer_text).strip()) == 0:
|
||||||
|
answer_text = _(
|
||||||
|
'Sorry, no relevant content was found. Please re-describe your problem or provide more information. ')
|
||||||
|
return AIMessage(content=answer_text)
|
||||||
|
|
||||||
|
def get_node_details_runtime_node_id(self, runtime_node_id):
|
||||||
|
return self.details.get(runtime_node_id, None)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "application_chat_record"
|
||||||
@ -6,28 +6,64 @@
|
|||||||
@date:2025/5/26 17:03
|
@date:2025/5/26 17:03
|
||||||
@desc:
|
@desc:
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
import pickle
|
||||||
import re
|
import re
|
||||||
from typing import Dict
|
from typing import Dict, List
|
||||||
|
|
||||||
import uuid_utils.compat as uuid
|
import uuid_utils.compat as uuid
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
from django.http import HttpResponse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers, status
|
||||||
|
from rest_framework.utils.formatting import lazy_format
|
||||||
|
|
||||||
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
|
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
|
||||||
ApplicationFolder
|
ApplicationFolder, WorkFlowVersion
|
||||||
from application.models.application_access_token import ApplicationAccessToken
|
from application.models.application_access_token import ApplicationAccessToken
|
||||||
|
from chat.flow.workflow_manage import Flow
|
||||||
|
from common import result
|
||||||
from common.database_model_manage.database_model_manage import DatabaseModelManage
|
from common.database_model_manage.database_model_manage import DatabaseModelManage
|
||||||
from common.db.search import native_search, native_page_search
|
from common.db.search import native_search, native_page_search
|
||||||
from common.exception.app_exception import AppApiException
|
from common.exception.app_exception import AppApiException
|
||||||
from common.utils.common import get_file_content
|
from common.field.common import UploadedFileField
|
||||||
|
from common.utils.common import get_file_content, valid_license, restricted_loads
|
||||||
from knowledge.models import Knowledge
|
from knowledge.models import Knowledge
|
||||||
from maxkb.conf import PROJECT_DIR
|
from maxkb.conf import PROJECT_DIR
|
||||||
from models_provider.models import Model
|
from models_provider.models import Model
|
||||||
|
from tools.models import Tool, ToolScope
|
||||||
|
from tools.serializers.tool import ToolModelSerializer
|
||||||
|
from users.models import User
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_node_work_flow(work_flow):
|
||||||
|
node_list = work_flow.get('nodes')
|
||||||
|
base_node_list = [node for node in node_list if node.get('id') == 'base-node']
|
||||||
|
if len(base_node_list) > 0:
|
||||||
|
return base_node_list[-1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class MKInstance:
|
||||||
|
|
||||||
|
def __init__(self, application: dict, function_lib_list: List[dict], version: str, tool_list: List[dict]):
|
||||||
|
self.application = application
|
||||||
|
self.function_lib_list = function_lib_list
|
||||||
|
self.version = version
|
||||||
|
self.tool_list = tool_list
|
||||||
|
|
||||||
|
def get_tool_list(self):
|
||||||
|
return [*(self.tool_list or []), *(self.function_lib_list or [])]
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationSerializerModel(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Application
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class NoReferencesChoices(models.TextChoices):
|
class NoReferencesChoices(models.TextChoices):
|
||||||
@ -307,6 +343,55 @@ class Query(serializers.Serializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationImportRequest(serializers.Serializer):
|
||||||
|
file = UploadedFileField(required=True, label=_("file"))
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationEditSerializer(serializers.Serializer):
|
||||||
|
name = serializers.CharField(required=False, max_length=64, min_length=1,
|
||||||
|
label=_("Application Name"))
|
||||||
|
desc = serializers.CharField(required=False, max_length=256, min_length=1, allow_null=True, allow_blank=True,
|
||||||
|
label=_("Application Description"))
|
||||||
|
model_id = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||||
|
label=_("Model"))
|
||||||
|
dialogue_number = serializers.IntegerField(required=False,
|
||||||
|
min_value=0,
|
||||||
|
max_value=1024,
|
||||||
|
label=_("Historical chat records"))
|
||||||
|
prologue = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=102400,
|
||||||
|
label=_("Opening remarks"))
|
||||||
|
dataset_id_list = serializers.ListSerializer(required=False, child=serializers.UUIDField(required=True),
|
||||||
|
label=_("Related Knowledge Base")
|
||||||
|
)
|
||||||
|
# 数据集相关设置
|
||||||
|
knowledge_setting = KnowledgeSettingSerializer(required=False, allow_null=True,
|
||||||
|
label=_("Dataset settings"))
|
||||||
|
# 模型相关设置
|
||||||
|
model_setting = ModelSettingSerializer(required=False, allow_null=True,
|
||||||
|
label=_("Model setup"))
|
||||||
|
# 问题补全
|
||||||
|
problem_optimization = serializers.BooleanField(required=False, allow_null=True,
|
||||||
|
label=_("Question completion"))
|
||||||
|
icon = serializers.CharField(required=False, allow_null=True, label=_("Icon"))
|
||||||
|
|
||||||
|
model_params_setting = serializers.DictField(required=False,
|
||||||
|
label=_('Model parameters'))
|
||||||
|
|
||||||
|
tts_model_enable = serializers.BooleanField(required=False, label=_('Voice playback enabled'))
|
||||||
|
|
||||||
|
tts_model_id = serializers.UUIDField(required=False, allow_null=True, label=_("Voice playback model ID"))
|
||||||
|
|
||||||
|
tts_type = serializers.CharField(required=False, label=_('Voice playback type'))
|
||||||
|
|
||||||
|
tts_autoplay = serializers.BooleanField(required=False, label=_('Voice playback autoplay'))
|
||||||
|
|
||||||
|
stt_model_enable = serializers.BooleanField(required=False, label=_('Voice recognition enabled'))
|
||||||
|
|
||||||
|
stt_model_id = serializers.UUIDField(required=False, allow_null=True, label=_('Speech recognition model ID'))
|
||||||
|
|
||||||
|
stt_autosend = serializers.BooleanField(required=False, label=_('Voice recognition automatic transmission'))
|
||||||
|
|
||||||
|
|
||||||
class ApplicationSerializer(serializers.Serializer):
|
class ApplicationSerializer(serializers.Serializer):
|
||||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||||
user_id = serializers.UUIDField(required=True, label=_("User ID"))
|
user_id = serializers.UUIDField(required=True, label=_("User ID"))
|
||||||
@ -352,3 +437,281 @@ class ApplicationSerializer(serializers.Serializer):
|
|||||||
# 插入关联数据
|
# 插入关联数据
|
||||||
QuerySet(ApplicationKnowledgeMapping).bulk_create(application_knowledge_mapping_model_list)
|
QuerySet(ApplicationKnowledgeMapping).bulk_create(application_knowledge_mapping_model_list)
|
||||||
return ApplicationCreateSerializer.ApplicationResponse(application_model).data
|
return ApplicationCreateSerializer.ApplicationResponse(application_model).data
|
||||||
|
|
||||||
|
@valid_license(model=Application, count=5,
|
||||||
|
message=_(
|
||||||
|
'The community version supports up to 5 applications. If you need more applications, please contact us (https://fit2cloud.com/).'))
|
||||||
|
@transaction.atomic
|
||||||
|
def import_(self, instance: dict, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
ApplicationImportRequest(data=instance).is_valid(raise_exception=True)
|
||||||
|
user_id = self.data.get('user_id')
|
||||||
|
workspace_id = self.data.get("workspace_id")
|
||||||
|
mk_instance_bytes = instance.get('file').read()
|
||||||
|
try:
|
||||||
|
mk_instance = restricted_loads(mk_instance_bytes)
|
||||||
|
except Exception as e:
|
||||||
|
raise AppApiException(1001, _("Unsupported file format"))
|
||||||
|
application = mk_instance.application
|
||||||
|
|
||||||
|
tool_list = mk_instance.get_tool_list()
|
||||||
|
if len(tool_list) > 0:
|
||||||
|
tool_id_list = [tool.get('id') for tool in tool_list]
|
||||||
|
exits_tool_id_list = [str(tool.id) for tool in
|
||||||
|
QuerySet(Tool).filter(id__in=tool_id_list)]
|
||||||
|
# 获取到需要插入的函数
|
||||||
|
tool_list = [tool for tool in tool_id_list if
|
||||||
|
not exits_tool_id_list.__contains__(tool.get('id'))]
|
||||||
|
application_model = self.to_application(application, workspace_id, user_id)
|
||||||
|
tool_model_list = [self.to_tool(f, workspace_id, user_id) for f in tool_list]
|
||||||
|
application_model.save()
|
||||||
|
# 插入认证信息
|
||||||
|
ApplicationAccessToken(application_id=application_model.id,
|
||||||
|
access_token=hashlib.md5(str(uuid.uuid1()).encode()).hexdigest()[8:24]).save()
|
||||||
|
QuerySet(Tool).bulk_create(tool_model_list) if len(tool_model_list) > 0 else None
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_tool(tool, workspace_id, user_id):
|
||||||
|
"""
|
||||||
|
@param workspace_id:
|
||||||
|
@param user_id: 用户id
|
||||||
|
@param tool: 工具
|
||||||
|
@return:
|
||||||
|
"""
|
||||||
|
return Tool(id=tool.get('id'),
|
||||||
|
user_id=user_id,
|
||||||
|
name=tool.get('name'),
|
||||||
|
code=tool.get('code'),
|
||||||
|
input_field_list=tool.get('input_field_list'),
|
||||||
|
is_active=tool.get('is_active'),
|
||||||
|
scope=ToolScope.WORKSPACE,
|
||||||
|
workspace_id=workspace_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_application(application, workspace_id, user_id):
|
||||||
|
work_flow = application.get('work_flow')
|
||||||
|
for node in work_flow.get('nodes', []):
|
||||||
|
if node.get('type') == 'search-dataset-node':
|
||||||
|
node.get('properties', {}).get('node_data', {})['dataset_id_list'] = []
|
||||||
|
return Application(id=uuid.uuid1(),
|
||||||
|
user_id=user_id,
|
||||||
|
name=application.get('name'),
|
||||||
|
workspace_id=workspace_id,
|
||||||
|
desc=application.get('desc'),
|
||||||
|
prologue=application.get('prologue'), dialogue_number=application.get('dialogue_number'),
|
||||||
|
dataset_setting=application.get('dataset_setting'),
|
||||||
|
model_setting=application.get('model_setting'),
|
||||||
|
model_params_setting=application.get('model_params_setting'),
|
||||||
|
tts_model_params_setting=application.get('tts_model_params_setting'),
|
||||||
|
problem_optimization=application.get('problem_optimization'),
|
||||||
|
icon="/ui/favicon.ico",
|
||||||
|
work_flow=work_flow,
|
||||||
|
type=application.get('type'),
|
||||||
|
problem_optimization_prompt=application.get('problem_optimization_prompt'),
|
||||||
|
tts_model_enable=application.get('tts_model_enable'),
|
||||||
|
stt_model_enable=application.get('stt_model_enable'),
|
||||||
|
tts_type=application.get('tts_type'),
|
||||||
|
clean_time=application.get('clean_time'),
|
||||||
|
file_upload_enable=application.get('file_upload_enable'),
|
||||||
|
file_upload_setting=application.get('file_upload_setting'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationOperateSerializer(serializers.Serializer):
|
||||||
|
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
|
||||||
|
user_id = serializers.UUIDField(required=True, label=_("User ID"))
|
||||||
|
|
||||||
|
def is_valid(self, *, raise_exception=False):
|
||||||
|
super().is_valid(raise_exception=True)
|
||||||
|
if not QuerySet(Application).filter(id=self.data.get('application_id')).exists():
|
||||||
|
raise AppApiException(500, _('Application id does not exist'))
|
||||||
|
|
||||||
|
def delete(self, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
QuerySet(Application).filter(id=self.data.get('application_id')).delete()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def export(self, with_valid=True):
|
||||||
|
try:
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
application_id = self.data.get('application_id')
|
||||||
|
application = QuerySet(Application).filter(id=application_id).first()
|
||||||
|
tool_id_list = [node.get('properties', {}).get('node_data', {}).get('tool_id') for node
|
||||||
|
in
|
||||||
|
application.work_flow.get('nodes', []) if
|
||||||
|
node.get('type') == 'tool-node']
|
||||||
|
tool_list = []
|
||||||
|
if len(tool_id_list) > 0:
|
||||||
|
tool_list = QuerySet(Tool).filter(id__in=tool_id_list)
|
||||||
|
application_dict = ApplicationSerializerModel(application).data
|
||||||
|
|
||||||
|
mk_instance = MKInstance(application_dict,
|
||||||
|
[],
|
||||||
|
'v2',
|
||||||
|
[ToolModelSerializer(tool).data for tool in
|
||||||
|
tool_list])
|
||||||
|
application_pickle = pickle.dumps(mk_instance)
|
||||||
|
response = HttpResponse(content_type='text/plain', content=application_pickle)
|
||||||
|
response['Content-Disposition'] = f'attachment; filename="{application.name}.mk"'
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def publish(self, instance, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
user_id = self.data.get('user_id')
|
||||||
|
workspace_id = self.data.get("workspace_id")
|
||||||
|
user = QuerySet(User).filter(id=user_id).first()
|
||||||
|
application = QuerySet(Application).filter(id=self.data.get("application_id"),
|
||||||
|
workspace_id=workspace_id).first()
|
||||||
|
work_flow = instance.get('work_flow')
|
||||||
|
if work_flow is None:
|
||||||
|
raise AppApiException(500, _("work_flow is a required field"))
|
||||||
|
Flow.new_instance(work_flow).is_valid()
|
||||||
|
base_node = get_base_node_work_flow(work_flow)
|
||||||
|
if base_node is not None:
|
||||||
|
node_data = base_node.get('properties').get('node_data')
|
||||||
|
if node_data is not None:
|
||||||
|
application.name = node_data.get('name')
|
||||||
|
application.desc = node_data.get('desc')
|
||||||
|
application.prologue = node_data.get('prologue')
|
||||||
|
application.work_flow = work_flow
|
||||||
|
application.save()
|
||||||
|
work_flow_version = WorkFlowVersion(work_flow=work_flow, application=application,
|
||||||
|
name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
publish_user_id=user_id,
|
||||||
|
publish_user_name=user.username,
|
||||||
|
workspace_id=workspace_id)
|
||||||
|
work_flow_version.save()
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_work_flow_model(instance):
|
||||||
|
if 'nodes' not in instance.get('work_flow'):
|
||||||
|
return
|
||||||
|
nodes = instance.get('work_flow')['nodes']
|
||||||
|
for node in nodes:
|
||||||
|
if node['id'] == 'base-node':
|
||||||
|
node_data = node['properties']['node_data']
|
||||||
|
if 'stt_model_id' in node_data:
|
||||||
|
instance['stt_model_id'] = node_data['stt_model_id']
|
||||||
|
if 'tts_model_id' in node_data:
|
||||||
|
instance['tts_model_id'] = node_data['tts_model_id']
|
||||||
|
if 'stt_model_enable' in node_data:
|
||||||
|
instance['stt_model_enable'] = node_data['stt_model_enable']
|
||||||
|
if 'tts_model_enable' in node_data:
|
||||||
|
instance['tts_model_enable'] = node_data['tts_model_enable']
|
||||||
|
if 'tts_type' in node_data:
|
||||||
|
instance['tts_type'] = node_data['tts_type']
|
||||||
|
if 'tts_autoplay' in node_data:
|
||||||
|
instance['tts_autoplay'] = node_data['tts_autoplay']
|
||||||
|
if 'stt_autosend' in node_data:
|
||||||
|
instance['stt_autosend'] = node_data['stt_autosend']
|
||||||
|
if 'tts_model_params_setting' in node_data:
|
||||||
|
instance['tts_model_params_setting'] = node_data['tts_model_params_setting']
|
||||||
|
if 'file_upload_enable' in node_data:
|
||||||
|
instance['file_upload_enable'] = node_data['file_upload_enable']
|
||||||
|
if 'file_upload_setting' in node_data:
|
||||||
|
instance['file_upload_setting'] = node_data['file_upload_setting']
|
||||||
|
if 'name' in node_data:
|
||||||
|
instance['name'] = node_data['name']
|
||||||
|
break
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def edit(self, instance: Dict, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
ApplicationEditSerializer(data=instance).is_valid(
|
||||||
|
raise_exception=True)
|
||||||
|
application_id = self.data.get("application_id")
|
||||||
|
|
||||||
|
application = QuerySet(Application).get(id=application_id)
|
||||||
|
if instance.get('model_id') is None or len(instance.get('model_id')) == 0:
|
||||||
|
application.model_id = None
|
||||||
|
else:
|
||||||
|
model = QuerySet(Model).filter(
|
||||||
|
id=instance.get('model_id')).first()
|
||||||
|
if model is None:
|
||||||
|
raise AppApiException(500, _("Model does not exist"))
|
||||||
|
if instance.get('stt_model_id') is None or len(instance.get('stt_model_id')) == 0:
|
||||||
|
application.stt_model_id = None
|
||||||
|
else:
|
||||||
|
model = QuerySet(Model).filter(
|
||||||
|
id=instance.get('stt_model_id')).first()
|
||||||
|
if model is None:
|
||||||
|
raise AppApiException(500, _("Model does not exist"))
|
||||||
|
if instance.get('tts_model_id') is None or len(instance.get('tts_model_id')) == 0:
|
||||||
|
application.tts_model_id = None
|
||||||
|
else:
|
||||||
|
model = QuerySet(Model).filter(
|
||||||
|
id=instance.get('tts_model_id')).first()
|
||||||
|
if model is None:
|
||||||
|
raise AppApiException(500, _("Model does not exist"))
|
||||||
|
if 'work_flow' in instance:
|
||||||
|
# 修改语音配置相关
|
||||||
|
self.update_work_flow_model(instance)
|
||||||
|
|
||||||
|
update_keys = ['name', 'desc', 'model_id', 'multiple_rounds_dialogue', 'prologue', 'status',
|
||||||
|
'dataset_setting', 'model_setting', 'problem_optimization', 'dialogue_number',
|
||||||
|
'stt_model_id', 'tts_model_id', 'tts_model_enable', 'stt_model_enable', 'tts_type',
|
||||||
|
'tts_autoplay', 'stt_autosend', 'file_upload_enable', 'file_upload_setting',
|
||||||
|
'api_key_is_active', 'icon', 'work_flow', 'model_params_setting', 'tts_model_params_setting',
|
||||||
|
'problem_optimization_prompt', 'clean_time']
|
||||||
|
for update_key in update_keys:
|
||||||
|
if update_key in instance and instance.get(update_key) is not None:
|
||||||
|
application.__setattr__(update_key, instance.get(update_key))
|
||||||
|
print(application.name)
|
||||||
|
application.save()
|
||||||
|
|
||||||
|
if 'knowledge_id_list' in instance:
|
||||||
|
knowledge_id_list = instance.get('knowledge_id_list')
|
||||||
|
# 当前用户可修改关联的知识库列表
|
||||||
|
application_knowledge_id_list = [str(knowledge.id) for knowledge in
|
||||||
|
self.list_knowledge(with_valid=False)]
|
||||||
|
for dataset_id in knowledge_id_list:
|
||||||
|
if not application_knowledge_id_list.__contains__(dataset_id):
|
||||||
|
message = lazy_format(_('Unknown knowledge base id {dataset_id}, unable to associate'),
|
||||||
|
dataset_id=dataset_id)
|
||||||
|
raise AppApiException(500, message)
|
||||||
|
|
||||||
|
self.save_application_knowledge_mapping(application_knowledge_id_list, knowledge_id_list, application_id)
|
||||||
|
return self.one(with_valid=False)
|
||||||
|
|
||||||
|
def one(self, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid()
|
||||||
|
application_id = self.data.get("application_id")
|
||||||
|
application = QuerySet(Application).get(id=application_id)
|
||||||
|
dataset_list = self.list_knowledge(with_valid=False)
|
||||||
|
mapping_knowledge_id_list = [akm.knowledge_id for akm in
|
||||||
|
QuerySet(ApplicationKnowledgeMapping).filter(application_id=application_id)]
|
||||||
|
knowledge_id_list = [d.get('id') for d in
|
||||||
|
list(filter(lambda row: mapping_knowledge_id_list.__contains__(row.get('id')),
|
||||||
|
dataset_list))]
|
||||||
|
return {**ApplicationSerializerModel(application).data,
|
||||||
|
'dataset_id_list': knowledge_id_list}
|
||||||
|
|
||||||
|
def list_knowledge(self, with_valid=True):
|
||||||
|
if with_valid:
|
||||||
|
self.is_valid(raise_exception=True)
|
||||||
|
workspace_id = self.data.get("workspace_id")
|
||||||
|
knowledge_list = QuerySet(Knowledge).filter(workspace_id=workspace_id)
|
||||||
|
return knowledge_list
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_application_knowledge_mapping(application_knowledge_id_list, knowledge_id_list, application_id):
|
||||||
|
# 需要排除已删除的数据集
|
||||||
|
knowledge_id_list = [knowledge.id for knowledge in QuerySet(Knowledge).filter(id__in=knowledge_id_list)]
|
||||||
|
# 删除已经关联的id
|
||||||
|
QuerySet(ApplicationKnowledgeMapping).filter(knowledge_id__in=application_knowledge_id_list,
|
||||||
|
application_id=application_id).delete()
|
||||||
|
# 插入
|
||||||
|
QuerySet(ApplicationKnowledgeMapping).bulk_create(
|
||||||
|
[ApplicationKnowledgeMapping(application_id=application_id, dataset_id=dataset_id) for dataset_id in
|
||||||
|
knowledge_id_list]) if len(knowledge_id_list) > 0 else None
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import uuid_utils.compat as uuid
|
|
||||||
from baidubce.services.bmr.bmr_client import application
|
|
||||||
|
|
||||||
|
import uuid_utils.compat as uuid
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from rest_framework import serializers
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.models import Application
|
from application.models import Application
|
||||||
from application.models.application_api_key import ApplicationApiKey
|
from application.models.application_api_key import ApplicationApiKey
|
||||||
@ -16,6 +15,7 @@ class ApplicationKeySerializerModel(serializers.ModelSerializer):
|
|||||||
model = ApplicationApiKey
|
model = ApplicationApiKey
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class Edit(serializers.Serializer):
|
class Edit(serializers.Serializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -25,10 +25,6 @@ class ApplicationKeySerializer(serializers.Serializer):
|
|||||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||||
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
application_id = self.data.get("application_id")
|
application_id = self.data.get("application_id")
|
||||||
@ -49,21 +45,18 @@ class ApplicationKeySerializer(serializers.Serializer):
|
|||||||
application_api_key.save()
|
application_api_key.save()
|
||||||
return ApplicationKeySerializerModel(application_api_key).data
|
return ApplicationKeySerializerModel(application_api_key).data
|
||||||
|
|
||||||
def list(self,with_valid=True):
|
def list(self, with_valid=True):
|
||||||
if with_valid:
|
if with_valid:
|
||||||
self.is_valid(raise_exception=True)
|
self.is_valid(raise_exception=True)
|
||||||
application_id = self.data.get("application_id")
|
application_id = self.data.get("application_id")
|
||||||
return [ApplicationKeySerializerModel(application_api_key).data for application_api_key in
|
return [ApplicationKeySerializerModel(application_api_key).data for application_api_key in
|
||||||
QuerySet(ApplicationApiKey).filter(application_id = application_id)]
|
QuerySet(ApplicationApiKey).filter(application_id=application_id)]
|
||||||
|
|
||||||
class Operate(serializers.Serializer):
|
class Operate(serializers.Serializer):
|
||||||
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
||||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||||
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def edit(self, instance, with_valid=True):
|
def edit(self, instance, with_valid=True):
|
||||||
if with_valid:
|
if with_valid:
|
||||||
self.is_valid(raise_exception=True)
|
self.is_valid(raise_exception=True)
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,12 @@ from . import views
|
|||||||
app_name = 'application'
|
app_name = 'application'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
path('workspace/<str:workspace_id>/application', views.Application.as_view(), name='application'),
|
path('workspace/<str:workspace_id>/application', views.Application.as_view(), name='application'),
|
||||||
|
path('workspace/<str:workspace_id>/application/import', views.Application.Import.as_view()),
|
||||||
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>',
|
path('workspace/<str:workspace_id>/application/<int:current_page>/<int:page_size>',
|
||||||
views.Application.Page.as_view(), name='application_page'),
|
views.Application.Page.as_view(), name='application_page'),
|
||||||
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key',
|
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key',
|
||||||
views.ApplicationKey.as_view())]
|
views.ApplicationKey.as_view()),
|
||||||
|
path('workspace/<str:workspace_id>/application/<str:application_id>/export', views.Application.Export.as_view()),
|
||||||
|
]
|
||||||
|
|||||||
@ -8,11 +8,14 @@
|
|||||||
"""
|
"""
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import extend_schema
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.parsers import MultiPartParser
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI
|
from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI, ApplicationImportAPI, \
|
||||||
from application.serializers.application import ApplicationSerializer, Query
|
ApplicationExportAPI, ApplicationOperateAPI, ApplicationEditAPI
|
||||||
|
from application.serializers.application import ApplicationSerializer, Query, ApplicationOperateSerializer
|
||||||
from common import result
|
from common import result
|
||||||
from common.auth import TokenAuth
|
from common.auth import TokenAuth
|
||||||
from common.auth.authentication import has_permissions
|
from common.auth.authentication import has_permissions
|
||||||
@ -67,3 +70,92 @@ class Application(APIView):
|
|||||||
return result.success(
|
return result.success(
|
||||||
Query(data={'workspace_id': workspace_id, 'user_id': request.user.id}).page(current_page, page_size,
|
Query(data={'workspace_id': workspace_id, 'user_id': request.user.id}).page(current_page, page_size,
|
||||||
request.query_params))
|
request.query_params))
|
||||||
|
|
||||||
|
class Import(APIView):
|
||||||
|
authentication_classes = [TokenAuth]
|
||||||
|
parser_classes = [MultiPartParser]
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
methods=['POST'],
|
||||||
|
description=_('Import Application'),
|
||||||
|
summary=_('Import Application'),
|
||||||
|
operation_id=_('Import Application'), # type: ignore
|
||||||
|
parameters=ApplicationImportAPI.get_parameters(),
|
||||||
|
request=ApplicationImportAPI.get_request(),
|
||||||
|
responses=result.DefaultResultSerializer,
|
||||||
|
tags=[_('Application')] # type: ignore
|
||||||
|
)
|
||||||
|
@has_permissions(PermissionConstants.APPLICATION_READ)
|
||||||
|
def post(self, request: Request, workspace_id: str):
|
||||||
|
return result.success(ApplicationSerializer(
|
||||||
|
data={'user_id': request.user.id, 'workspace_id': workspace_id,
|
||||||
|
}).import_({'file': request.FILES.get('file')}))
|
||||||
|
|
||||||
|
class Export(APIView):
|
||||||
|
authentication_classes = [TokenAuth]
|
||||||
|
|
||||||
|
@action(methods=['POST'], detail=False)
|
||||||
|
@extend_schema(
|
||||||
|
methods=['POST'],
|
||||||
|
description=_('Export conversation'),
|
||||||
|
summary=_('Export conversation'),
|
||||||
|
operation_id=_('Export conversation'), # type: ignore
|
||||||
|
parameters=ApplicationExportAPI.get_parameters(),
|
||||||
|
responses=ApplicationExportAPI.get_response(),
|
||||||
|
tags=[_('Application')] # type: ignore
|
||||||
|
)
|
||||||
|
@has_permissions(PermissionConstants.APPLICATION_EXPORT.get_workspace_application_permission())
|
||||||
|
def post(self, request: Request, workspace_id: str, application_id: str):
|
||||||
|
return ApplicationOperateSerializer(
|
||||||
|
data={'application_id': application_id,
|
||||||
|
'user_id': request.user.id}).export(request.data)
|
||||||
|
|
||||||
|
class Operate(APIView):
|
||||||
|
authentication_classes = [TokenAuth]
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
methods=['DELETE'],
|
||||||
|
description=_('Deleting application'),
|
||||||
|
summary=_('Deleting application'),
|
||||||
|
operation_id=_('Deleting application'), # type: ignore
|
||||||
|
parameters=ApplicationOperateAPI.get_parameters(),
|
||||||
|
responses=result.DefaultResultSerializer,
|
||||||
|
tags=[_('Application')] # type: ignore
|
||||||
|
)
|
||||||
|
@has_permissions(PermissionConstants.APPLICATION_DELETE.get_workspace_application_permission())
|
||||||
|
def delete(self, request: Request, application_id: str):
|
||||||
|
return result.success(ApplicationOperateSerializer(
|
||||||
|
data={'application_id': application_id, 'user_id': request.user.id}).delete(
|
||||||
|
with_valid=True))
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
methods=['PUT'],
|
||||||
|
description=_('Modify the application'),
|
||||||
|
summary=_('Modify the application'),
|
||||||
|
operation_id=_('Modify the application'), # type: ignore
|
||||||
|
parameters=ApplicationOperateAPI.get_parameters(),
|
||||||
|
request=ApplicationEditAPI.get_request(),
|
||||||
|
responses=ApplicationCreateAPI.get_response(),
|
||||||
|
tags=[_('Application')] # type: ignore
|
||||||
|
)
|
||||||
|
@has_permissions(PermissionConstants.APPLICATION_EDIT.get_workspace_application_permission())
|
||||||
|
def put(self, request: Request, application_id: str):
|
||||||
|
return result.success(
|
||||||
|
ApplicationOperateSerializer(
|
||||||
|
data={'application_id': application_id, 'user_id': request.user.id}).edit(
|
||||||
|
request.data))
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
methods=['PUT'],
|
||||||
|
description=_('Get application details'),
|
||||||
|
summary=_('Get application details'),
|
||||||
|
operation_id=_('Get application details'), # type: ignore
|
||||||
|
parameters=ApplicationOperateAPI.get_parameters(),
|
||||||
|
request=ApplicationEditAPI.get_request(),
|
||||||
|
responses=result.DefaultResultSerializer,
|
||||||
|
tags=[_('Application')] # type: ignore
|
||||||
|
)
|
||||||
|
@has_permissions(PermissionConstants.WORKSPACE_READ.get_workspace_application_permission())
|
||||||
|
def get(self, request: Request, application_id: str):
|
||||||
|
return result.success(ApplicationOperateSerializer(
|
||||||
|
data={'application_id': application_id, 'user_id': request.user.id}).one())
|
||||||
|
|||||||
0
apps/chat/__init__.py
Normal file
0
apps/chat/__init__.py
Normal file
3
apps/chat/admin.py
Normal file
3
apps/chat/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
47
apps/chat/api/chat_embed_api.py
Normal file
47
apps/chat/api/chat_embed_api.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""
|
||||||
|
@project: MaxKB
|
||||||
|
@Author:虎虎
|
||||||
|
@file: chat_embed_api.py
|
||||||
|
@date:2025/5/30 15:25
|
||||||
|
@desc:
|
||||||
|
"""
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import OpenApiParameter
|
||||||
|
|
||||||
|
from common.mixins.api_mixin import APIMixin
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from common.result import DefaultResultSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ChatEmbedAPI(APIMixin):
|
||||||
|
@staticmethod
|
||||||
|
def get_parameters():
|
||||||
|
return [
|
||||||
|
OpenApiParameter(
|
||||||
|
name="host",
|
||||||
|
description=_("host"),
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location='query',
|
||||||
|
required=False,
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="protocol",
|
||||||
|
description=_("protocol"),
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location='query',
|
||||||
|
required=False,
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="token",
|
||||||
|
description=_("token"),
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location='query',
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_response():
|
||||||
|
return DefaultResultSerializer
|
||||||
6
apps/chat/apps.py
Normal file
6
apps/chat/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ChatConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'chat'
|
||||||
@ -25,9 +25,9 @@ from application.chat_pipeline.I_base_chat_pipeline import ParagraphPipelineMode
|
|||||||
from application.chat_pipeline.pipeline_manage import PipelineManage
|
from application.chat_pipeline.pipeline_manage import PipelineManage
|
||||||
from application.chat_pipeline.step.chat_step.i_chat_step import IChatStep, PostResponseHandler
|
from application.chat_pipeline.step.chat_step.i_chat_step import IChatStep, PostResponseHandler
|
||||||
from application.flow.tools import Reasoning
|
from application.flow.tools import Reasoning
|
||||||
from application.models.api_key_model import ApplicationPublicAccessClient
|
from application.models.application_api_key import ApplicationPublicAccessClient
|
||||||
from common.constants.authentication_type import AuthenticationType
|
from common.constants.authentication_type import AuthenticationType
|
||||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
from models_provider.tools import get_model_instance_by_model_user_id
|
||||||
|
|
||||||
|
|
||||||
def add_access_num(client_id=None, client_type=None, application_id=None):
|
def add_access_num(client_id=None, client_type=None, application_id=None):
|
||||||
@ -17,14 +17,13 @@ from django.db.models import QuerySet
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError, ErrorDetail
|
from rest_framework.exceptions import ValidationError, ErrorDetail
|
||||||
|
|
||||||
from application.flow.common import Answer, NodeChunk
|
from chat.flow.common import Answer, NodeChunk
|
||||||
from application.models import ChatRecord
|
from application.models import ChatRecord
|
||||||
from application.models.api_key_model import ApplicationPublicAccessClient
|
from application.models import ApplicationPublicAccessClient
|
||||||
from common.constants.authentication_type import AuthenticationType
|
from common.constants.authentication_type import AuthenticationType
|
||||||
from common.field.common import InstanceField
|
from common.field.common import InstanceField
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
|
|
||||||
chat_cache = cache.caches['chat_cache']
|
chat_cache = cache
|
||||||
|
|
||||||
|
|
||||||
def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
|
def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
|
||||||
@ -123,31 +122,31 @@ class NodeResult:
|
|||||||
|
|
||||||
|
|
||||||
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, label="节点id")
|
||||||
fields = serializers.ListField(
|
fields = serializers.ListField(
|
||||||
child=serializers.CharField(required=True, error_messages=ErrMessage.char("节点字段")), required=True,
|
child=serializers.CharField(required=True, label="节点字段"), required=True,
|
||||||
error_messages=ErrMessage.list("节点字段数组"))
|
label="节点字段数组")
|
||||||
|
|
||||||
|
|
||||||
class FlowParamsSerializer(serializers.Serializer):
|
class FlowParamsSerializer(serializers.Serializer):
|
||||||
# 历史对答
|
# 历史对答
|
||||||
history_chat_record = serializers.ListField(child=InstanceField(model_type=ChatRecord, required=True),
|
history_chat_record = serializers.ListField(child=InstanceField(model_type=ChatRecord, required=True),
|
||||||
error_messages=ErrMessage.list("历史对答"))
|
label="历史对答")
|
||||||
|
|
||||||
question = serializers.CharField(required=True, error_messages=ErrMessage.list("用户问题"))
|
question = serializers.CharField(required=True, label="用户问题")
|
||||||
|
|
||||||
chat_id = serializers.CharField(required=True, error_messages=ErrMessage.list("对话id"))
|
chat_id = serializers.CharField(required=True, label="对话id")
|
||||||
|
|
||||||
chat_record_id = serializers.CharField(required=True, error_messages=ErrMessage.char("对话记录id"))
|
chat_record_id = serializers.CharField(required=True, label="对话记录id")
|
||||||
|
|
||||||
stream = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("流式输出"))
|
stream = serializers.BooleanField(required=True, label="流式输出")
|
||||||
|
|
||||||
client_id = serializers.CharField(required=False, error_messages=ErrMessage.char("客户端id"))
|
client_id = serializers.CharField(required=False, label="客户端id")
|
||||||
|
|
||||||
client_type = serializers.CharField(required=False, error_messages=ErrMessage.char("客户端类型"))
|
client_type = serializers.CharField(required=False, label="客户端类型")
|
||||||
|
|
||||||
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))
|
user_id = serializers.UUIDField(required=True, label="用户id")
|
||||||
re_chat = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("换个答案"))
|
re_chat = serializers.BooleanField(required=True, label="换个答案")
|
||||||
|
|
||||||
|
|
||||||
class INode:
|
class INode:
|
||||||
@ -11,31 +11,29 @@ from typing import Type
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
|
|
||||||
|
|
||||||
class ChatNodeSerializer(serializers.Serializer):
|
class ChatNodeSerializer(serializers.Serializer):
|
||||||
model_id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Model id")))
|
model_id = serializers.CharField(required=True, label=_("Model id"))
|
||||||
system = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
system = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||||
error_messages=ErrMessage.char(_("Role Setting")))
|
label=_("Role Setting"))
|
||||||
prompt = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Prompt word")))
|
prompt = serializers.CharField(required=True, label=_("Prompt word"))
|
||||||
# 多轮对话数量
|
# 多轮对话数量
|
||||||
dialogue_number = serializers.IntegerField(required=True, error_messages=ErrMessage.integer(
|
dialogue_number = serializers.IntegerField(required=True, label=_("Number of multi-round conversations"))
|
||||||
_("Number of multi-round conversations")))
|
|
||||||
|
|
||||||
is_result = serializers.BooleanField(required=False,
|
is_result = serializers.BooleanField(required=False,
|
||||||
error_messages=ErrMessage.boolean(_('Whether to return content')))
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
model_params_setting = serializers.DictField(required=False,
|
model_params_setting = serializers.DictField(required=False,
|
||||||
error_messages=ErrMessage.dict(_("Model parameter settings")))
|
label=_("Model parameter settings"))
|
||||||
model_setting = serializers.DictField(required=False,
|
model_setting = serializers.DictField(required=False,
|
||||||
error_messages=ErrMessage.dict('Model settings'))
|
label='Model settings')
|
||||||
dialogue_type = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
dialogue_type = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||||
error_messages=ErrMessage.char(_("Context Type")))
|
label=_("Context Type"))
|
||||||
mcp_enable = serializers.BooleanField(required=False,
|
mcp_enable = serializers.BooleanField(required=False,
|
||||||
error_messages=ErrMessage.boolean(_("Whether to enable MCP")))
|
label=_("Whether to enable MCP"))
|
||||||
mcp_servers = serializers.JSONField(required=False, error_messages=ErrMessage.list(_("MCP Server")))
|
mcp_servers = serializers.JSONField(required=False, label=_("MCP Server"))
|
||||||
|
|
||||||
|
|
||||||
class IChatNode(INode):
|
class IChatNode(INode):
|
||||||
@ -20,12 +20,11 @@ from langchain_core.messages import BaseMessage, AIMessage, AIMessageChunk, Tool
|
|||||||
from langchain_mcp_adapters.client import MultiServerMCPClient
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||||
from langgraph.prebuilt import create_react_agent
|
from langgraph.prebuilt import create_react_agent
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult, INode
|
from chat.flow.i_step_node import NodeResult, INode
|
||||||
from application.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
|
from chat.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
|
||||||
from application.flow.tools import Reasoning
|
from chat.flow.tools import Reasoning
|
||||||
from setting.models import Model
|
from models_provider.models import Model
|
||||||
from setting.models_provider import get_model_credential
|
from models_provider.tools import get_model_credential, get_model_instance_by_model_user_id
|
||||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
|
||||||
|
|
||||||
tool_message_template = """
|
tool_message_template = """
|
||||||
<details>
|
<details>
|
||||||
@ -3,25 +3,24 @@ from typing import Type
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ApplicationNodeSerializer(serializers.Serializer):
|
class ApplicationNodeSerializer(serializers.Serializer):
|
||||||
application_id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Application ID")))
|
application_id = serializers.CharField(required=True, label=_("Application ID"))
|
||||||
question_reference_address = serializers.ListField(required=True,
|
question_reference_address = serializers.ListField(required=True,
|
||||||
error_messages=ErrMessage.list(_("User Questions")))
|
label=_("User Questions"))
|
||||||
api_input_field_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("API Input Fields")))
|
api_input_field_list = serializers.ListField(required=False, label=_("API Input Fields"))
|
||||||
user_input_field_list = serializers.ListField(required=False,
|
user_input_field_list = serializers.ListField(required=False,
|
||||||
error_messages=ErrMessage.uuid(_("User Input Fields")))
|
label=_("User Input Fields"))
|
||||||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("picture")))
|
image_list = serializers.ListField(required=False, label=_("picture"))
|
||||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("document")))
|
document_list = serializers.ListField(required=False, label=_("document"))
|
||||||
audio_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Audio")))
|
audio_list = serializers.ListField(required=False, label=_("Audio"))
|
||||||
child_node = serializers.DictField(required=False, allow_null=True,
|
child_node = serializers.DictField(required=False, allow_null=True,
|
||||||
error_messages=ErrMessage.dict(_("Child Nodes")))
|
label=_("Child Nodes"))
|
||||||
node_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict(_("Form Data")))
|
node_data = serializers.DictField(required=False, allow_null=True, label=_("Form Data"))
|
||||||
|
|
||||||
|
|
||||||
class IApplicationNode(INode):
|
class IApplicationNode(INode):
|
||||||
@ -5,9 +5,9 @@ import time
|
|||||||
import uuid
|
import uuid
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from application.flow.common import Answer
|
from chat.flow.common import Answer
|
||||||
from application.flow.i_step_node import NodeResult, INode
|
from chat.flow.i_step_node import NodeResult, INode
|
||||||
from application.flow.step_node.application_node.i_application_node import IApplicationNode
|
from chat.flow.step_node.application_node.i_application_node import IApplicationNode
|
||||||
from application.models import Chat
|
from application.models import Chat
|
||||||
|
|
||||||
|
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class ContainCompare(Compare):
|
class ContainCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class EqualCompare(Compare):
|
class EqualCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class GECompare(Compare):
|
class GECompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class GTCompare(Compare):
|
class GTCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare import Compare
|
from chat.flow.step_node.condition_node.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class IsNotNullCompare(Compare):
|
class IsNotNullCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare import Compare
|
from chat.flow.step_node.condition_node.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class IsNotTrueCompare(Compare):
|
class IsNotTrueCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare import Compare
|
from chat.flow.step_node.condition_node.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class IsNullCompare(Compare):
|
class IsNullCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare import Compare
|
from chat.flow.step_node.condition_node.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class IsTrueCompare(Compare):
|
class IsTrueCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LECompare(Compare):
|
class LECompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LenEqualCompare(Compare):
|
class LenEqualCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LenGECompare(Compare):
|
class LenGECompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LenGTCompare(Compare):
|
class LenGTCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LenLECompare(Compare):
|
class LenLECompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LenLTCompare(Compare):
|
class LenLTCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class LTCompare(Compare):
|
class LTCompare(Compare):
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.step_node.condition_node.compare.compare import Compare
|
from chat.flow.step_node.condition_node.compare.compare import Compare
|
||||||
|
|
||||||
|
|
||||||
class NotContainCompare(Compare):
|
class NotContainCompare(Compare):
|
||||||
@ -11,20 +11,19 @@ from typing import Type
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode
|
from chat.flow.i_step_node import INode
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
|
|
||||||
|
|
||||||
class ConditionSerializer(serializers.Serializer):
|
class ConditionSerializer(serializers.Serializer):
|
||||||
compare = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Comparator")))
|
compare = serializers.CharField(required=True, label=_("Comparator"))
|
||||||
value = serializers.CharField(required=True, error_messages=ErrMessage.char(_("value")))
|
value = serializers.CharField(required=True, label=_("value"))
|
||||||
field = serializers.ListField(required=True, error_messages=ErrMessage.char(_("Fields")))
|
field = serializers.ListField(required=True, label=_("Fields"))
|
||||||
|
|
||||||
|
|
||||||
class ConditionBranchSerializer(serializers.Serializer):
|
class ConditionBranchSerializer(serializers.Serializer):
|
||||||
id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Branch id")))
|
id = serializers.CharField(required=True, label=_("Branch id"))
|
||||||
type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Branch Type")))
|
type = serializers.CharField(required=True, label=_("Branch Type"))
|
||||||
condition = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Condition or|and")))
|
condition = serializers.CharField(required=True, label=_("Condition or|and"))
|
||||||
conditions = ConditionSerializer(many=True)
|
conditions = ConditionSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
@ -8,9 +8,9 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.condition_node.compare import compare_handle_list
|
from chat.flow.step_node.condition_node.compare import compare_handle_list
|
||||||
from application.flow.step_node.condition_node.i_condition_node import IConditionNode
|
from chat.flow.step_node.condition_node.i_condition_node import IConditionNode
|
||||||
|
|
||||||
|
|
||||||
class BaseConditionNode(IConditionNode):
|
class BaseConditionNode(IConditionNode):
|
||||||
@ -10,18 +10,19 @@ from typing import Type
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.exception.app_exception import AppApiException
|
from common.exception.app_exception import AppApiException
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ReplyNodeParamsSerializer(serializers.Serializer):
|
class ReplyNodeParamsSerializer(serializers.Serializer):
|
||||||
reply_type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Response Type")))
|
reply_type = serializers.CharField(required=True, label=_("Response Type"))
|
||||||
fields = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Reference Field")))
|
fields = serializers.ListField(required=False, label=_("Reference Field"))
|
||||||
content = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
content = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||||
error_messages=ErrMessage.char(_("Direct answer content")))
|
label=_("Direct answer content"))
|
||||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
is_result = serializers.BooleanField(required=False,
|
||||||
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
@ -8,8 +8,8 @@
|
|||||||
"""
|
"""
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.direct_reply_node.i_reply_node import IReplyNode
|
from chat.flow.step_node.direct_reply_node.i_reply_node import IReplyNode
|
||||||
|
|
||||||
|
|
||||||
class BaseReplyNode(IReplyNode):
|
class BaseReplyNode(IReplyNode):
|
||||||
@ -5,12 +5,11 @@ from typing import Type
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentExtractNodeSerializer(serializers.Serializer):
|
class DocumentExtractNodeSerializer(serializers.Serializer):
|
||||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("document")))
|
document_list = serializers.ListField(required=False, label=_("document"))
|
||||||
|
|
||||||
|
|
||||||
class IDocumentExtractNode(INode):
|
class IDocumentExtractNode(INode):
|
||||||
@ -5,11 +5,11 @@ import mimetypes
|
|||||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.document_extract_node.i_document_extract_node import IDocumentExtractNode
|
from chat.flow.step_node.document_extract_node.i_document_extract_node import IDocumentExtractNode
|
||||||
from dataset.models import File
|
from knowledge.models import File
|
||||||
from dataset.serializers.document_serializers import split_handles, parse_table_handle_list, FileBufferHandle
|
from knowledge.serializers.document import split_handles, parse_table_handle_list, FileBufferHandle
|
||||||
from dataset.serializers.file_serializers import FileSerializer
|
from knowledge.serializers.file import FileSerializer
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_uploaded_file(file_bytes, file_name="file.txt"):
|
def bytes_to_uploaded_file(file_bytes, file_name="file.txt"):
|
||||||
@ -37,11 +37,11 @@ def bytes_to_uploaded_file(file_bytes, file_name="file.txt"):
|
|||||||
|
|
||||||
splitter = '\n`-----------------------------------`\n'
|
splitter = '\n`-----------------------------------`\n'
|
||||||
|
|
||||||
|
|
||||||
class BaseDocumentExtractNode(IDocumentExtractNode):
|
class BaseDocumentExtractNode(IDocumentExtractNode):
|
||||||
def save_context(self, details, workflow_manage):
|
def save_context(self, details, workflow_manage):
|
||||||
self.context['content'] = details.get('content')
|
self.context['content'] = details.get('content')
|
||||||
|
|
||||||
|
|
||||||
def execute(self, document, chat_id, **kwargs):
|
def execute(self, document, chat_id, **kwargs):
|
||||||
get_buffer = FileBufferHandle().get_buffer
|
get_buffer = FileBufferHandle().get_buffer
|
||||||
|
|
||||||
@ -10,15 +10,15 @@ from typing import Type
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class FormNodeParamsSerializer(serializers.Serializer):
|
class FormNodeParamsSerializer(serializers.Serializer):
|
||||||
form_field_list = serializers.ListField(required=True, error_messages=ErrMessage.list(_("Form Configuration")))
|
form_field_list = serializers.ListField(required=True, label=_("Form Configuration"))
|
||||||
form_content_format = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Form output content')))
|
form_content_format = serializers.CharField(required=True, label=_('Form output content'))
|
||||||
form_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict(_("Form Data")))
|
form_data = serializers.DictField(required=False, allow_null=True, label=_("Form Data"))
|
||||||
|
|
||||||
|
|
||||||
class IFormNode(INode):
|
class IFormNode(INode):
|
||||||
@ -12,9 +12,9 @@ from typing import Dict, List
|
|||||||
|
|
||||||
from langchain_core.prompts import PromptTemplate
|
from langchain_core.prompts import PromptTemplate
|
||||||
|
|
||||||
from application.flow.common import Answer
|
from chat.flow.common import Answer
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.form_node.i_form_node import IFormNode
|
from chat.flow.step_node.form_node.i_form_node import IFormNode
|
||||||
|
|
||||||
|
|
||||||
def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
|
def write_context(step_variable: Dict, global_variable: Dict, node, workflow):
|
||||||
@ -11,26 +11,27 @@ from typing import Type
|
|||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.field.common import ObjectField
|
from common.field.common import ObjectField
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from function_lib.models.function import FunctionLib
|
from tools.models.tool import Tool
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class InputField(serializers.Serializer):
|
class InputField(serializers.Serializer):
|
||||||
name = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Variable Name')))
|
name = serializers.CharField(required=True, label=_('Variable Name'))
|
||||||
value = ObjectField(required=True, error_messages=ErrMessage.char(_("Variable Value")), model_type_list=[str, list])
|
value = ObjectField(required=True, label=_("Variable Value"), model_type_list=[str, list])
|
||||||
|
|
||||||
|
|
||||||
class FunctionLibNodeParamsSerializer(serializers.Serializer):
|
class FunctionLibNodeParamsSerializer(serializers.Serializer):
|
||||||
function_lib_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid(_('Library ID')))
|
tool_id = serializers.UUIDField(required=True, label=_('Library ID'))
|
||||||
input_field_list = InputField(required=True, many=True)
|
input_field_list = InputField(required=True, many=True)
|
||||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
is_result = serializers.BooleanField(required=False,
|
||||||
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
f_lib = QuerySet(FunctionLib).filter(id=self.data.get('function_lib_id')).first()
|
f_lib = QuerySet(Tool).filter(id=self.data.get('tool_id')).first()
|
||||||
if f_lib is None:
|
if f_lib is None:
|
||||||
raise Exception(_('The function has been deleted'))
|
raise Exception(_('The function has been deleted'))
|
||||||
|
|
||||||
@ -13,13 +13,13 @@ from typing import Dict
|
|||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.function_lib_node.i_function_lib_node import IFunctionLibNode
|
from chat.flow.step_node.function_lib_node.i_function_lib_node import IFunctionLibNode
|
||||||
from common.exception.app_exception import AppApiException
|
from common.exception.app_exception import AppApiException
|
||||||
from common.util.function_code import FunctionExecutor
|
from common.utils.function_code import FunctionExecutor
|
||||||
from common.util.rsa_util import rsa_long_decrypt
|
from common.utils.rsa_util import rsa_long_decrypt
|
||||||
from function_lib.models.function import FunctionLib
|
from maxkb.const import CONFIG
|
||||||
from smartdoc.const import CONFIG
|
from tools.models import Tool
|
||||||
|
|
||||||
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ class BaseFunctionLibNodeNode(IFunctionLibNode):
|
|||||||
self.answer_text = str(details.get('result'))
|
self.answer_text = str(details.get('result'))
|
||||||
|
|
||||||
def execute(self, function_lib_id, input_field_list, **kwargs) -> NodeResult:
|
def execute(self, function_lib_id, input_field_list, **kwargs) -> NodeResult:
|
||||||
function_lib = QuerySet(FunctionLib).filter(id=function_lib_id).first()
|
function_lib = QuerySet(Tool).filter(id=function_lib_id).first()
|
||||||
valid_function(function_lib, self.flow_params_serializer.data.get('user_id'))
|
valid_function(function_lib, self.flow_params_serializer.data.get('user_id'))
|
||||||
params = {field.get('name'): convert_value(field.get('name'), field.get('value'), field.get('type'),
|
params = {field.get('name'): convert_value(field.get('name'), field.get('value'), field.get('type'),
|
||||||
field.get('is_required'),
|
field.get('is_required'),
|
||||||
@ -12,26 +12,26 @@ from typing import Type
|
|||||||
from django.core import validators
|
from django.core import validators
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.exception.app_exception import AppApiException
|
from common.exception.app_exception import AppApiException
|
||||||
from common.field.common import ObjectField
|
from common.field.common import ObjectField
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.utils.formatting import lazy_format
|
from rest_framework.utils.formatting import lazy_format
|
||||||
|
|
||||||
|
|
||||||
class InputField(serializers.Serializer):
|
class InputField(serializers.Serializer):
|
||||||
name = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Variable Name')))
|
name = serializers.CharField(required=True, label=_('Variable Name'))
|
||||||
is_required = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean(_("Is this field required")))
|
is_required = serializers.BooleanField(required=True, label=_("Is this field required"))
|
||||||
type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("type")), validators=[
|
type = serializers.CharField(required=True, label=_("type"), validators=[
|
||||||
validators.RegexValidator(regex=re.compile("^string|int|dict|array|float$"),
|
validators.RegexValidator(regex=re.compile("^string|int|dict|array|float$"),
|
||||||
message=_("The field only supports string|int|dict|array|float"), code=500)
|
message=_("The field only supports string|int|dict|array|float"), code=500)
|
||||||
])
|
])
|
||||||
source = serializers.CharField(required=True, error_messages=ErrMessage.char(_("source")), validators=[
|
source = serializers.CharField(required=True, label=_("source"), validators=[
|
||||||
validators.RegexValidator(regex=re.compile("^custom|reference$"),
|
validators.RegexValidator(regex=re.compile("^custom|reference$"),
|
||||||
message=_("The field only supports custom|reference"), code=500)
|
message=_("The field only supports custom|reference"), code=500)
|
||||||
])
|
])
|
||||||
value = ObjectField(required=True, error_messages=ErrMessage.char(_("Variable Value")), model_type_list=[str, list])
|
value = ObjectField(required=True, label=_("Variable Value"), model_type_list=[str, list])
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
@ -43,8 +43,9 @@ class InputField(serializers.Serializer):
|
|||||||
|
|
||||||
class FunctionNodeParamsSerializer(serializers.Serializer):
|
class FunctionNodeParamsSerializer(serializers.Serializer):
|
||||||
input_field_list = InputField(required=True, many=True)
|
input_field_list = InputField(required=True, many=True)
|
||||||
code = serializers.CharField(required=True, error_messages=ErrMessage.char(_("function")))
|
code = serializers.CharField(required=True, label=_("function"))
|
||||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
is_result = serializers.BooleanField(required=False,
|
||||||
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
def is_valid(self, *, raise_exception=False):
|
def is_valid(self, *, raise_exception=False):
|
||||||
super().is_valid(raise_exception=True)
|
super().is_valid(raise_exception=True)
|
||||||
@ -8,14 +8,12 @@
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.function_node.i_function_node import IFunctionNode
|
from chat.flow.step_node.function_node.i_function_node import IFunctionNode
|
||||||
from common.exception.app_exception import AppApiException
|
from common.utils.function_code import FunctionExecutor
|
||||||
from common.util.function_code import FunctionExecutor
|
from maxkb.const import CONFIG
|
||||||
from smartdoc.const import CONFIG
|
|
||||||
|
|
||||||
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
||||||
|
|
||||||
@ -2,31 +2,31 @@
|
|||||||
|
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class ImageGenerateNodeSerializer(serializers.Serializer):
|
class ImageGenerateNodeSerializer(serializers.Serializer):
|
||||||
model_id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Model id")))
|
model_id = serializers.CharField(required=True, label=_("Model id"))
|
||||||
|
|
||||||
prompt = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Prompt word (positive)")))
|
prompt = serializers.CharField(required=True, label=_("Prompt word (positive)"))
|
||||||
|
|
||||||
negative_prompt = serializers.CharField(required=False, error_messages=ErrMessage.char(_("Prompt word (negative)")),
|
negative_prompt = serializers.CharField(required=False, label=_("Prompt word (negative)"),
|
||||||
allow_null=True, allow_blank=True, )
|
allow_null=True, allow_blank=True, )
|
||||||
# 多轮对话数量
|
# 多轮对话数量
|
||||||
dialogue_number = serializers.IntegerField(required=False, default=0,
|
dialogue_number = serializers.IntegerField(required=False, default=0,
|
||||||
error_messages=ErrMessage.integer(_("Number of multi-round conversations")))
|
label=_("Number of multi-round conversations"))
|
||||||
|
|
||||||
dialogue_type = serializers.CharField(required=False, default='NODE',
|
dialogue_type = serializers.CharField(required=False, default='NODE',
|
||||||
error_messages=ErrMessage.char(_("Conversation storage type")))
|
label=_("Conversation storage type"))
|
||||||
|
|
||||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
is_result = serializers.BooleanField(required=False,
|
||||||
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
model_params_setting = serializers.JSONField(required=False, default=dict,
|
model_params_setting = serializers.JSONField(required=False, default=dict,
|
||||||
error_messages=ErrMessage.json(_("Model parameter settings")))
|
label=_("Model parameter settings"))
|
||||||
|
|
||||||
|
|
||||||
class IImageGenerateNode(INode):
|
class IImageGenerateNode(INode):
|
||||||
@ -5,11 +5,11 @@ from typing import List
|
|||||||
import requests
|
import requests
|
||||||
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
|
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.image_generate_step_node.i_image_generate_node import IImageGenerateNode
|
from chat.flow.step_node.image_generate_step_node.i_image_generate_node import IImageGenerateNode
|
||||||
from common.util.common import bytes_to_uploaded_file
|
from common.utils.common import bytes_to_uploaded_file
|
||||||
from dataset.serializers.file_serializers import FileSerializer
|
from knowledge.serializers.file import FileSerializer
|
||||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
from models_provider.tools import get_model_instance_by_model_user_id
|
||||||
|
|
||||||
|
|
||||||
class BaseImageGenerateNode(IImageGenerateNode):
|
class BaseImageGenerateNode(IImageGenerateNode):
|
||||||
@ -4,27 +4,28 @@ from typing import Type
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ImageUnderstandNodeSerializer(serializers.Serializer):
|
class ImageUnderstandNodeSerializer(serializers.Serializer):
|
||||||
model_id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Model id")))
|
model_id = serializers.CharField(required=True, label=_("Model id"))
|
||||||
system = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
system = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||||
error_messages=ErrMessage.char(_("Role Setting")))
|
label=_("Role Setting"))
|
||||||
prompt = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Prompt word")))
|
prompt = serializers.CharField(required=True, label=_("Prompt word"))
|
||||||
# 多轮对话数量
|
# 多轮对话数量
|
||||||
dialogue_number = serializers.IntegerField(required=True, error_messages=ErrMessage.integer(_("Number of multi-round conversations")))
|
dialogue_number = serializers.IntegerField(required=True, label=_("Number of multi-round conversations"))
|
||||||
|
|
||||||
dialogue_type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Conversation storage type")))
|
dialogue_type = serializers.CharField(required=True, label=_("Conversation storage type"))
|
||||||
|
|
||||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
is_result = serializers.BooleanField(required=False,
|
||||||
|
label=_('Whether to return content'))
|
||||||
|
|
||||||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("picture")))
|
image_list = serializers.ListField(required=False, label=_("picture"))
|
||||||
|
|
||||||
model_params_setting = serializers.JSONField(required=False, default=dict,
|
model_params_setting = serializers.JSONField(required=False, default=dict,
|
||||||
error_messages=ErrMessage.json(_("Model parameter settings")))
|
label=_("Model parameter settings"))
|
||||||
|
|
||||||
|
|
||||||
class IImageUnderstandNode(INode):
|
class IImageUnderstandNode(INode):
|
||||||
@ -1,18 +1,17 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
import base64
|
import base64
|
||||||
import os
|
|
||||||
import time
|
import time
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
from imghdr import what
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage
|
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult, INode
|
from chat.flow.i_step_node import NodeResult, INode
|
||||||
from application.flow.step_node.image_understand_step_node.i_image_understand_node import IImageUnderstandNode
|
from chat.flow.step_node.image_understand_step_node.i_image_understand_node import IImageUnderstandNode
|
||||||
from dataset.models import File
|
from knowledge.models import File
|
||||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
from models_provider.tools import get_model_instance_by_model_user_id
|
||||||
from imghdr import what
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
@ -81,7 +80,8 @@ class BaseImageUnderstandNode(IImageUnderstandNode):
|
|||||||
if image is None or not isinstance(image, list):
|
if image is None or not isinstance(image, list):
|
||||||
image = []
|
image = []
|
||||||
print(model_params_setting)
|
print(model_params_setting)
|
||||||
image_model = get_model_instance_by_model_user_id(model_id, self.flow_params_serializer.data.get('user_id'), **model_params_setting)
|
image_model = get_model_instance_by_model_user_id(model_id, self.flow_params_serializer.data.get('user_id'),
|
||||||
|
**model_params_setting)
|
||||||
# 执行详情中的历史消息不需要图片内容
|
# 执行详情中的历史消息不需要图片内容
|
||||||
history_message = self.get_history_message_for_details(history_chat_record, dialogue_number)
|
history_message = self.get_history_message_for_details(history_chat_record, dialogue_number)
|
||||||
self.context['history_message'] = history_message
|
self.context['history_message'] = history_message
|
||||||
@ -155,7 +155,8 @@ class BaseImageUnderstandNode(IImageUnderstandNode):
|
|||||||
return HumanMessage(
|
return HumanMessage(
|
||||||
content=[
|
content=[
|
||||||
{'type': 'text', 'text': data['question']},
|
{'type': 'text', 'text': data['question']},
|
||||||
*[{'type': 'image_url', 'image_url': {'url': f'data:image/{base64_image[1]};base64,{base64_image[0]}'}} for
|
*[{'type': 'image_url',
|
||||||
|
'image_url': {'url': f'data:image/{base64_image[1]};base64,{base64_image[0]}'}} for
|
||||||
base64_image in image_base64_list]
|
base64_image in image_base64_list]
|
||||||
])
|
])
|
||||||
return HumanMessage(content=chat_record.problem_text)
|
return HumanMessage(content=chat_record.problem_text)
|
||||||
@ -173,7 +174,8 @@ class BaseImageUnderstandNode(IImageUnderstandNode):
|
|||||||
image_bytes = file.get_byte()
|
image_bytes = file.get_byte()
|
||||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||||
image_format = what(None, image_bytes.tobytes())
|
image_format = what(None, image_bytes.tobytes())
|
||||||
images.append({'type': 'image_url', 'image_url': {'url': f'data:image/{image_format};base64,{base64_image}'}})
|
images.append(
|
||||||
|
{'type': 'image_url', 'image_url': {'url': f'data:image/{image_format};base64,{base64_image}'}})
|
||||||
messages = [HumanMessage(
|
messages = [HumanMessage(
|
||||||
content=[
|
content=[
|
||||||
{'type': 'text', 'text': self.workflow_manage.generate_prompt(prompt)},
|
{'type': 'text', 'text': self.workflow_manage.generate_prompt(prompt)},
|
||||||
@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from application.flow.i_step_node import INode, NodeResult
|
from chat.flow.i_step_node import INode, NodeResult
|
||||||
from common.util.field_message import ErrMessage
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class McpNodeSerializer(serializers.Serializer):
|
class McpNodeSerializer(serializers.Serializer):
|
||||||
mcp_servers = serializers.JSONField(required=True,
|
mcp_servers = serializers.JSONField(required=True,
|
||||||
error_messages=ErrMessage.char(_("Mcp servers")))
|
label=_("Mcp servers"))
|
||||||
|
|
||||||
mcp_server = serializers.CharField(required=True,
|
mcp_server = serializers.CharField(required=True,
|
||||||
error_messages=ErrMessage.char(_("Mcp server")))
|
label=_("Mcp server"))
|
||||||
|
|
||||||
mcp_tool = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Mcp tool")))
|
mcp_tool = serializers.CharField(required=True, label=_("Mcp tool"))
|
||||||
|
|
||||||
tool_params = serializers.DictField(required=True,
|
tool_params = serializers.DictField(required=True,
|
||||||
error_messages=ErrMessage.char(_("Tool parameters")))
|
label=_("Tool parameters"))
|
||||||
|
|
||||||
|
|
||||||
class IMcpNode(INode):
|
class IMcpNode(INode):
|
||||||
@ -5,8 +5,8 @@ from typing import List
|
|||||||
|
|
||||||
from langchain_mcp_adapters.client import MultiServerMCPClient
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||||
|
|
||||||
from application.flow.i_step_node import NodeResult
|
from chat.flow.i_step_node import NodeResult
|
||||||
from application.flow.step_node.mcp_node.i_mcp_node import IMcpNode
|
from chat.flow.step_node.mcp_node.i_mcp_node import IMcpNode
|
||||||
|
|
||||||
|
|
||||||
class BaseMcpNode(IMcpNode):
|
class BaseMcpNode(IMcpNode):
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user