mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: application operate api (#3176)
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
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 application.serializers.application import ApplicationCreateSerializer, ApplicationListResponse, \
|
||||
ApplicationQueryRequest
|
||||
ApplicationImportRequest, ApplicationEditSerializer
|
||||
from common.mixins.api_mixin import APIMixin
|
||||
from common.result import ResultSerializer, ResultPageSerializer
|
||||
from common.result import ResultSerializer, ResultPageSerializer, DefaultResultSerializer
|
||||
|
||||
|
||||
class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest):
|
||||
|
|
@ -120,3 +120,50 @@ class ApplicationCreateAPI(APIMixin):
|
|||
@staticmethod
|
||||
def get_response():
|
||||
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_access_token import *
|
||||
from .application_chat import *
|
||||
from .application_api_key import *
|
||||
|
|
|
|||
|
|
@ -117,3 +117,16 @@ class ApplicationKnowledgeMapping(AppModelMixin):
|
|||
|
||||
class Meta:
|
||||
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
|
||||
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
|
@ -6,7 +5,6 @@ from django.db import models
|
|||
|
||||
from application.models import Application
|
||||
from common.mixins.app_model_mixin import AppModelMixin
|
||||
|
||||
from users.models import User
|
||||
|
||||
|
||||
|
|
@ -23,4 +21,19 @@ class ApplicationApiKey(AppModelMixin):
|
|||
, default=list)
|
||||
|
||||
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']),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
@desc:
|
||||
"""
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
from typing import Dict
|
||||
from typing import Dict, List
|
||||
|
||||
import uuid_utils.compat as uuid
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpResponse
|
||||
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, \
|
||||
ApplicationFolder
|
||||
ApplicationFolder, WorkFlowVersion
|
||||
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.db.search import native_search, native_page_search
|
||||
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 maxkb.conf import PROJECT_DIR
|
||||
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):
|
||||
|
|
@ -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):
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace 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)
|
||||
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 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 rest_framework import serializers
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.models import Application
|
||||
from application.models.application_api_key import ApplicationApiKey
|
||||
|
|
@ -16,6 +15,7 @@ class ApplicationKeySerializerModel(serializers.ModelSerializer):
|
|||
model = ApplicationApiKey
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class Edit(serializers.Serializer):
|
||||
pass
|
||||
|
||||
|
|
@ -25,10 +25,6 @@ class ApplicationKeySerializer(serializers.Serializer):
|
|||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def is_valid(self, *, raise_exception=False):
|
||||
super().is_valid(raise_exception=True)
|
||||
application_id = self.data.get("application_id")
|
||||
|
|
@ -49,21 +45,18 @@ class ApplicationKeySerializer(serializers.Serializer):
|
|||
application_api_key.save()
|
||||
return ApplicationKeySerializerModel(application_api_key).data
|
||||
|
||||
def list(self,with_valid=True):
|
||||
def list(self, with_valid=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
application_id = self.data.get("application_id")
|
||||
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):
|
||||
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
||||
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
|
||||
application_id = serializers.UUIDField(required=True, label=_('application id'))
|
||||
|
||||
|
||||
|
||||
def edit(self, instance, with_valid=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ from . import views
|
|||
app_name = 'application'
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
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>',
|
||||
views.Application.Page.as_view(), name='application_page'),
|
||||
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 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.views import APIView
|
||||
|
||||
from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI
|
||||
from application.serializers.application import ApplicationSerializer, Query
|
||||
from application.api.application_api import ApplicationCreateAPI, ApplicationQueryAPI, ApplicationImportAPI, \
|
||||
ApplicationExportAPI, ApplicationOperateAPI, ApplicationEditAPI
|
||||
from application.serializers.application import ApplicationSerializer, Query, ApplicationOperateSerializer
|
||||
from common import result
|
||||
from common.auth import TokenAuth
|
||||
from common.auth.authentication import has_permissions
|
||||
|
|
@ -67,3 +70,92 @@ class Application(APIView):
|
|||
return result.success(
|
||||
Query(data={'workspace_id': workspace_id, 'user_id': request.user.id}).page(current_page, page_size,
|
||||
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,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
|
|
@ -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
|
||||
|
|
@ -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.step.chat_step.i_chat_step import IChatStep, PostResponseHandler
|
||||
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 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):
|
||||
|
|
@ -17,14 +17,13 @@ from django.db.models import QuerySet
|
|||
from rest_framework import serializers
|
||||
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.api_key_model import ApplicationPublicAccessClient
|
||||
from application.models import ApplicationPublicAccessClient
|
||||
from common.constants.authentication_type import AuthenticationType
|
||||
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):
|
||||
|
|
@ -123,31 +122,31 @@ class NodeResult:
|
|||
|
||||
|
||||
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(
|
||||
child=serializers.CharField(required=True, error_messages=ErrMessage.char("节点字段")), required=True,
|
||||
error_messages=ErrMessage.list("节点字段数组"))
|
||||
child=serializers.CharField(required=True, label="节点字段"), required=True,
|
||||
label="节点字段数组")
|
||||
|
||||
|
||||
class FlowParamsSerializer(serializers.Serializer):
|
||||
# 历史对答
|
||||
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"))
|
||||
re_chat = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean("换个答案"))
|
||||
user_id = serializers.UUIDField(required=True, label="用户id")
|
||||
re_chat = serializers.BooleanField(required=True, label="换个答案")
|
||||
|
||||
|
||||
class INode:
|
||||
|
|
@ -11,31 +11,29 @@ from typing import Type
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
|
||||
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,
|
||||
error_messages=ErrMessage.char(_("Role Setting")))
|
||||
prompt = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Prompt word")))
|
||||
label=_("Role Setting"))
|
||||
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"))
|
||||
|
||||
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,
|
||||
error_messages=ErrMessage.dict(_("Model parameter settings")))
|
||||
label=_("Model parameter settings"))
|
||||
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,
|
||||
error_messages=ErrMessage.char(_("Context Type")))
|
||||
label=_("Context Type"))
|
||||
mcp_enable = serializers.BooleanField(required=False,
|
||||
error_messages=ErrMessage.boolean(_("Whether to enable MCP")))
|
||||
mcp_servers = serializers.JSONField(required=False, error_messages=ErrMessage.list(_("MCP Server")))
|
||||
label=_("Whether to enable MCP"))
|
||||
mcp_servers = serializers.JSONField(required=False, label=_("MCP Server"))
|
||||
|
||||
|
||||
class IChatNode(INode):
|
||||
|
|
@ -20,12 +20,11 @@ from langchain_core.messages import BaseMessage, AIMessage, AIMessageChunk, Tool
|
|||
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
from application.flow.i_step_node import NodeResult, INode
|
||||
from application.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
|
||||
from application.flow.tools import Reasoning
|
||||
from setting.models import Model
|
||||
from setting.models_provider import get_model_credential
|
||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
||||
from chat.flow.i_step_node import NodeResult, INode
|
||||
from chat.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
|
||||
from chat.flow.tools import Reasoning
|
||||
from models_provider.models import Model
|
||||
from models_provider.tools import get_model_credential, get_model_instance_by_model_user_id
|
||||
|
||||
tool_message_template = """
|
||||
<details>
|
||||
|
|
@ -3,25 +3,24 @@ from typing import Type
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
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,
|
||||
error_messages=ErrMessage.list(_("User Questions")))
|
||||
api_input_field_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("API Input Fields")))
|
||||
label=_("User Questions"))
|
||||
api_input_field_list = serializers.ListField(required=False, label=_("API Input Fields"))
|
||||
user_input_field_list = serializers.ListField(required=False,
|
||||
error_messages=ErrMessage.uuid(_("User Input Fields")))
|
||||
image_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("picture")))
|
||||
document_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("document")))
|
||||
audio_list = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Audio")))
|
||||
label=_("User Input Fields"))
|
||||
image_list = serializers.ListField(required=False, label=_("picture"))
|
||||
document_list = serializers.ListField(required=False, label=_("document"))
|
||||
audio_list = serializers.ListField(required=False, label=_("Audio"))
|
||||
child_node = serializers.DictField(required=False, allow_null=True,
|
||||
error_messages=ErrMessage.dict(_("Child Nodes")))
|
||||
node_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict(_("Form Data")))
|
||||
label=_("Child Nodes"))
|
||||
node_data = serializers.DictField(required=False, allow_null=True, label=_("Form Data"))
|
||||
|
||||
|
||||
class IApplicationNode(INode):
|
||||
|
|
@ -5,9 +5,9 @@ import time
|
|||
import uuid
|
||||
from typing import Dict, List
|
||||
|
||||
from application.flow.common import Answer
|
||||
from application.flow.i_step_node import NodeResult, INode
|
||||
from application.flow.step_node.application_node.i_application_node import IApplicationNode
|
||||
from chat.flow.common import Answer
|
||||
from chat.flow.i_step_node import NodeResult, INode
|
||||
from chat.flow.step_node.application_node.i_application_node import IApplicationNode
|
||||
from application.models import Chat
|
||||
|
||||
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
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):
|
||||
|
|
@ -11,20 +11,19 @@ from typing import Type
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode
|
||||
|
||||
|
||||
class ConditionSerializer(serializers.Serializer):
|
||||
compare = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Comparator")))
|
||||
value = serializers.CharField(required=True, error_messages=ErrMessage.char(_("value")))
|
||||
field = serializers.ListField(required=True, error_messages=ErrMessage.char(_("Fields")))
|
||||
compare = serializers.CharField(required=True, label=_("Comparator"))
|
||||
value = serializers.CharField(required=True, label=_("value"))
|
||||
field = serializers.ListField(required=True, label=_("Fields"))
|
||||
|
||||
|
||||
class ConditionBranchSerializer(serializers.Serializer):
|
||||
id = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Branch id")))
|
||||
type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Branch Type")))
|
||||
condition = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Condition or|and")))
|
||||
id = serializers.CharField(required=True, label=_("Branch id"))
|
||||
type = serializers.CharField(required=True, label=_("Branch Type"))
|
||||
condition = serializers.CharField(required=True, label=_("Condition or|and"))
|
||||
conditions = ConditionSerializer(many=True)
|
||||
|
||||
|
||||
|
|
@ -8,9 +8,9 @@
|
|||
"""
|
||||
from typing import List
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.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.i_step_node import NodeResult
|
||||
from chat.flow.step_node.condition_node.compare import compare_handle_list
|
||||
from chat.flow.step_node.condition_node.i_condition_node import IConditionNode
|
||||
|
||||
|
||||
class BaseConditionNode(IConditionNode):
|
||||
|
|
@ -10,18 +10,19 @@ from typing import Type
|
|||
|
||||
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.util.field_message import ErrMessage
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class ReplyNodeParamsSerializer(serializers.Serializer):
|
||||
reply_type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Response Type")))
|
||||
fields = serializers.ListField(required=False, error_messages=ErrMessage.list(_("Reference Field")))
|
||||
reply_type = serializers.CharField(required=True, label=_("Response Type"))
|
||||
fields = serializers.ListField(required=False, label=_("Reference Field"))
|
||||
content = serializers.CharField(required=False, allow_blank=True, allow_null=True,
|
||||
error_messages=ErrMessage.char(_("Direct answer content")))
|
||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
||||
label=_("Direct answer content"))
|
||||
is_result = serializers.BooleanField(required=False,
|
||||
label=_('Whether to return content'))
|
||||
|
||||
def is_valid(self, *, raise_exception=False):
|
||||
super().is_valid(raise_exception=True)
|
||||
|
|
@ -8,8 +8,8 @@
|
|||
"""
|
||||
from typing import List
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.direct_reply_node.i_reply_node import IReplyNode
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.direct_reply_node.i_reply_node import IReplyNode
|
||||
|
||||
|
||||
class BaseReplyNode(IReplyNode):
|
||||
|
|
@ -5,12 +5,11 @@ from typing import Type
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
|
||||
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):
|
||||
|
|
@ -5,11 +5,11 @@ import mimetypes
|
|||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.document_extract_node.i_document_extract_node import IDocumentExtractNode
|
||||
from dataset.models import File
|
||||
from dataset.serializers.document_serializers import split_handles, parse_table_handle_list, FileBufferHandle
|
||||
from dataset.serializers.file_serializers import FileSerializer
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.document_extract_node.i_document_extract_node import IDocumentExtractNode
|
||||
from knowledge.models import File
|
||||
from knowledge.serializers.document import split_handles, parse_table_handle_list, FileBufferHandle
|
||||
from knowledge.serializers.file import FileSerializer
|
||||
|
||||
|
||||
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'
|
||||
|
||||
|
||||
class BaseDocumentExtractNode(IDocumentExtractNode):
|
||||
def save_context(self, details, workflow_manage):
|
||||
self.context['content'] = details.get('content')
|
||||
|
||||
|
||||
def execute(self, document, chat_id, **kwargs):
|
||||
get_buffer = FileBufferHandle().get_buffer
|
||||
|
||||
|
|
@ -10,15 +10,15 @@ from typing import Type
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class FormNodeParamsSerializer(serializers.Serializer):
|
||||
form_field_list = serializers.ListField(required=True, error_messages=ErrMessage.list(_("Form Configuration")))
|
||||
form_content_format = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Form output content')))
|
||||
form_data = serializers.DictField(required=False, allow_null=True, error_messages=ErrMessage.dict(_("Form Data")))
|
||||
form_field_list = serializers.ListField(required=True, label=_("Form Configuration"))
|
||||
form_content_format = serializers.CharField(required=True, label=_('Form output content'))
|
||||
form_data = serializers.DictField(required=False, allow_null=True, label=_("Form Data"))
|
||||
|
||||
|
||||
class IFormNode(INode):
|
||||
|
|
@ -12,9 +12,9 @@ from typing import Dict, List
|
|||
|
||||
from langchain_core.prompts import PromptTemplate
|
||||
|
||||
from application.flow.common import Answer
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.form_node.i_form_node import IFormNode
|
||||
from chat.flow.common import Answer
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.form_node.i_form_node import IFormNode
|
||||
|
||||
|
||||
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 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.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 _
|
||||
|
||||
|
||||
class InputField(serializers.Serializer):
|
||||
name = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Variable Name')))
|
||||
value = ObjectField(required=True, error_messages=ErrMessage.char(_("Variable Value")), model_type_list=[str, list])
|
||||
name = serializers.CharField(required=True, label=_('Variable Name'))
|
||||
value = ObjectField(required=True, label=_("Variable Value"), model_type_list=[str, list])
|
||||
|
||||
|
||||
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)
|
||||
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):
|
||||
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:
|
||||
raise Exception(_('The function has been deleted'))
|
||||
|
||||
|
|
@ -13,13 +13,13 @@ from typing import Dict
|
|||
from django.db.models import QuerySet
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.function_lib_node.i_function_lib_node import IFunctionLibNode
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.function_lib_node.i_function_lib_node import IFunctionLibNode
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.util.function_code import FunctionExecutor
|
||||
from common.util.rsa_util import rsa_long_decrypt
|
||||
from function_lib.models.function import FunctionLib
|
||||
from smartdoc.const import CONFIG
|
||||
from common.utils.function_code import FunctionExecutor
|
||||
from common.utils.rsa_util import rsa_long_decrypt
|
||||
from maxkb.const import CONFIG
|
||||
from tools.models import Tool
|
||||
|
||||
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ class BaseFunctionLibNodeNode(IFunctionLibNode):
|
|||
self.answer_text = str(details.get('result'))
|
||||
|
||||
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'))
|
||||
params = {field.get('name'): convert_value(field.get('name'), field.get('value'), field.get('type'),
|
||||
field.get('is_required'),
|
||||
|
|
@ -12,26 +12,26 @@ from typing import Type
|
|||
from django.core import validators
|
||||
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.field.common import ObjectField
|
||||
from common.util.field_message import ErrMessage
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework.utils.formatting import lazy_format
|
||||
|
||||
|
||||
class InputField(serializers.Serializer):
|
||||
name = serializers.CharField(required=True, error_messages=ErrMessage.char(_('Variable Name')))
|
||||
is_required = serializers.BooleanField(required=True, error_messages=ErrMessage.boolean(_("Is this field required")))
|
||||
type = serializers.CharField(required=True, error_messages=ErrMessage.char(_("type")), validators=[
|
||||
name = serializers.CharField(required=True, label=_('Variable Name'))
|
||||
is_required = serializers.BooleanField(required=True, label=_("Is this field required"))
|
||||
type = serializers.CharField(required=True, label=_("type"), validators=[
|
||||
validators.RegexValidator(regex=re.compile("^string|int|dict|array|float$"),
|
||||
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$"),
|
||||
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):
|
||||
super().is_valid(raise_exception=True)
|
||||
|
|
@ -43,8 +43,9 @@ class InputField(serializers.Serializer):
|
|||
|
||||
class FunctionNodeParamsSerializer(serializers.Serializer):
|
||||
input_field_list = InputField(required=True, many=True)
|
||||
code = serializers.CharField(required=True, error_messages=ErrMessage.char(_("function")))
|
||||
is_result = serializers.BooleanField(required=False, error_messages=ErrMessage.boolean(_('Whether to return content')))
|
||||
code = serializers.CharField(required=True, label=_("function"))
|
||||
is_result = serializers.BooleanField(required=False,
|
||||
label=_('Whether to return content'))
|
||||
|
||||
def is_valid(self, *, raise_exception=False):
|
||||
super().is_valid(raise_exception=True)
|
||||
|
|
@ -8,14 +8,12 @@
|
|||
"""
|
||||
import json
|
||||
import time
|
||||
|
||||
from typing import Dict
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.function_node.i_function_node import IFunctionNode
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.util.function_code import FunctionExecutor
|
||||
from smartdoc.const import CONFIG
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.function_node.i_function_node import IFunctionNode
|
||||
from common.utils.function_code import FunctionExecutor
|
||||
from maxkb.const import CONFIG
|
||||
|
||||
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
|
||||
|
||||
|
|
@ -2,31 +2,31 @@
|
|||
|
||||
from typing import Type
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
|
||||
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, )
|
||||
# 多轮对话数量
|
||||
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',
|
||||
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,
|
||||
error_messages=ErrMessage.json(_("Model parameter settings")))
|
||||
label=_("Model parameter settings"))
|
||||
|
||||
|
||||
class IImageGenerateNode(INode):
|
||||
|
|
@ -5,11 +5,11 @@ from typing import List
|
|||
import requests
|
||||
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.image_generate_step_node.i_image_generate_node import IImageGenerateNode
|
||||
from common.util.common import bytes_to_uploaded_file
|
||||
from dataset.serializers.file_serializers import FileSerializer
|
||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.image_generate_step_node.i_image_generate_node import IImageGenerateNode
|
||||
from common.utils.common import bytes_to_uploaded_file
|
||||
from knowledge.serializers.file import FileSerializer
|
||||
from models_provider.tools import get_model_instance_by_model_user_id
|
||||
|
||||
|
||||
class BaseImageGenerateNode(IImageGenerateNode):
|
||||
|
|
@ -4,27 +4,28 @@ from typing import Type
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
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,
|
||||
error_messages=ErrMessage.char(_("Role Setting")))
|
||||
prompt = serializers.CharField(required=True, error_messages=ErrMessage.char(_("Prompt word")))
|
||||
label=_("Role Setting"))
|
||||
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,
|
||||
error_messages=ErrMessage.json(_("Model parameter settings")))
|
||||
label=_("Model parameter settings"))
|
||||
|
||||
|
||||
class IImageUnderstandNode(INode):
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
# coding=utf-8
|
||||
import base64
|
||||
import os
|
||||
import time
|
||||
from functools import reduce
|
||||
from imghdr import what
|
||||
from typing import List, Dict
|
||||
|
||||
from django.db.models import QuerySet
|
||||
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage, AIMessage
|
||||
|
||||
from application.flow.i_step_node import NodeResult, INode
|
||||
from application.flow.step_node.image_understand_step_node.i_image_understand_node import IImageUnderstandNode
|
||||
from dataset.models import File
|
||||
from setting.models_provider.tools import get_model_instance_by_model_user_id
|
||||
from imghdr import what
|
||||
from chat.flow.i_step_node import NodeResult, INode
|
||||
from chat.flow.step_node.image_understand_step_node.i_image_understand_node import IImageUnderstandNode
|
||||
from knowledge.models import File
|
||||
from models_provider.tools import get_model_instance_by_model_user_id
|
||||
|
||||
|
||||
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):
|
||||
image = []
|
||||
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)
|
||||
self.context['history_message'] = history_message
|
||||
|
|
@ -155,7 +155,8 @@ class BaseImageUnderstandNode(IImageUnderstandNode):
|
|||
return HumanMessage(
|
||||
content=[
|
||||
{'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]
|
||||
])
|
||||
return HumanMessage(content=chat_record.problem_text)
|
||||
|
|
@ -173,7 +174,8 @@ class BaseImageUnderstandNode(IImageUnderstandNode):
|
|||
image_bytes = file.get_byte()
|
||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||
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(
|
||||
content=[
|
||||
{'type': 'text', 'text': self.workflow_manage.generate_prompt(prompt)},
|
||||
|
|
@ -2,24 +2,23 @@
|
|||
|
||||
from typing import Type
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from application.flow.i_step_node import INode, NodeResult
|
||||
from common.util.field_message import ErrMessage
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from chat.flow.i_step_node import INode, NodeResult
|
||||
|
||||
|
||||
class McpNodeSerializer(serializers.Serializer):
|
||||
mcp_servers = serializers.JSONField(required=True,
|
||||
error_messages=ErrMessage.char(_("Mcp servers")))
|
||||
label=_("Mcp servers"))
|
||||
|
||||
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,
|
||||
error_messages=ErrMessage.char(_("Tool parameters")))
|
||||
label=_("Tool parameters"))
|
||||
|
||||
|
||||
class IMcpNode(INode):
|
||||
|
|
@ -5,8 +5,8 @@ from typing import List
|
|||
|
||||
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||
|
||||
from application.flow.i_step_node import NodeResult
|
||||
from application.flow.step_node.mcp_node.i_mcp_node import IMcpNode
|
||||
from chat.flow.i_step_node import NodeResult
|
||||
from chat.flow.step_node.mcp_node.i_mcp_node import 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