feat: Simple application version (#3479)

This commit is contained in:
shaohuzhang1 2025-07-04 11:42:31 +08:00 committed by GitHub
parent 77d90e5b46
commit e21d53b746
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 282 additions and 103 deletions

View File

@ -55,7 +55,7 @@ class ApplicationVersionOperateAPI(APIMixin):
def get_parameters():
return [
OpenApiParameter(
name="work_flow_version_id",
name="application_version_id",
description="工作流版本id",
type=OpenApiTypes.STR,
location='path',

View File

@ -0,0 +1,66 @@
# Generated by Django 5.2.3 on 2025-07-04 03:18
import application.models.application
import django.db.models.deletion
import uuid_utils.compat
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('application', '0003_chat_asker_chat_meta_and_more'),
('users', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='application',
name='publish_time',
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='发布时间'),
),
migrations.CreateModel(
name='ApplicationVersion',
fields=[
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
('name', models.CharField(default='', max_length=128, verbose_name='版本名称')),
('publish_user_id', models.UUIDField(default=None, null=True, verbose_name='发布者id')),
('publish_user_name', models.CharField(default='', max_length=128, verbose_name='发布者名称')),
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
('application_name', models.CharField(max_length=128, verbose_name='应用名称')),
('desc', models.CharField(default='', max_length=512, verbose_name='引用描述')),
('prologue', models.CharField(default='', max_length=40960, verbose_name='开场白')),
('dialogue_number', models.IntegerField(default=0, verbose_name='会话数量')),
('model_id', models.UUIDField(blank=True, null=True, verbose_name='大语言模型')),
('knowledge_setting', models.JSONField(default=application.models.application.get_dataset_setting_dict, verbose_name='数据集参数设置')),
('model_setting', models.JSONField(default=application.models.application.get_model_setting_dict, verbose_name='模型参数相关设置')),
('model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
('tts_model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
('problem_optimization', models.BooleanField(default=False, verbose_name='问题优化')),
('icon', models.CharField(default='./favicon.ico', max_length=256, verbose_name='应用icon')),
('work_flow', models.JSONField(default=dict, verbose_name='工作流数据')),
('type', models.CharField(choices=[('SIMPLE', '简易'), ('WORK_FLOW', '工作流')], default='SIMPLE', max_length=256, verbose_name='应用类型')),
('problem_optimization_prompt', models.CharField(blank=True, default='()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中', max_length=102400, null=True, verbose_name='问题优化提示词')),
('tts_model_id', models.UUIDField(blank=True, null=True, verbose_name='文本转语音模型id')),
('stt_model_id', models.UUIDField(blank=True, null=True, verbose_name='语音转文本模型id')),
('tts_model_enable', models.BooleanField(default=False, verbose_name='语音合成模型是否启用')),
('stt_model_enable', models.BooleanField(default=False, verbose_name='语音识别模型是否启用')),
('tts_type', models.CharField(default='BROWSER', max_length=20, verbose_name='语音播放类型')),
('tts_autoplay', models.BooleanField(default=False, verbose_name='自动播放')),
('stt_autosend', models.BooleanField(default=False, verbose_name='自动发送')),
('clean_time', models.IntegerField(default=180, verbose_name='清理时间')),
('file_upload_enable', models.BooleanField(default=False, verbose_name='文件上传是否启用')),
('file_upload_setting', models.JSONField(default=dict, verbose_name='文件上传相关设置')),
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='application.application')),
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.user')),
],
options={
'db_table': 'application_version',
},
),
migrations.DeleteModel(
name='WorkFlowVersion',
),
]

View File

@ -90,6 +90,7 @@ class Application(AppModelMixin):
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
publish_time = models.DateTimeField(verbose_name="发布时间", default=None, null=True, blank=True)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
@ -120,14 +121,43 @@ class ApplicationKnowledgeMapping(AppModelMixin):
db_table = "application_knowledge_mapping"
class WorkFlowVersion(AppModelMixin):
class ApplicationVersion(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)
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="")
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
application_name = models.CharField(max_length=128, verbose_name="应用名称")
desc = models.CharField(max_length=512, verbose_name="引用描述", default="")
prologue = models.CharField(max_length=40960, verbose_name="开场白", default="")
dialogue_number = models.IntegerField(default=0, verbose_name="会话数量")
user = models.ForeignKey(User, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
model_id = models.UUIDField(verbose_name="大语言模型", blank=True, null=True)
knowledge_setting = models.JSONField(verbose_name="数据集参数设置", default=get_dataset_setting_dict)
model_setting = models.JSONField(verbose_name="模型参数相关设置", default=get_model_setting_dict)
model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
problem_optimization = models.BooleanField(verbose_name="问题优化", default=False)
icon = models.CharField(max_length=256, verbose_name="应用icon", default="./favicon.ico")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
type = models.CharField(verbose_name="应用类型", choices=ApplicationTypeChoices.choices,
default=ApplicationTypeChoices.SIMPLE, max_length=256)
problem_optimization_prompt = models.CharField(verbose_name="问题优化提示词", max_length=102400, blank=True,
null=True,
default="()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中")
tts_model_id = models.UUIDField(verbose_name="文本转语音模型id",
blank=True, null=True)
stt_model_id = models.UUIDField(verbose_name="语音转文本模型id",
blank=True, null=True)
tts_model_enable = models.BooleanField(verbose_name="语音合成模型是否启用", default=False)
stt_model_enable = models.BooleanField(verbose_name="语音识别模型是否启用", default=False)
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
class Meta:
db_table = "application_work_flow_version"
db_table = "application_version"

View File

@ -27,7 +27,7 @@ from rest_framework.utils.formatting import lazy_format
from application.flow.common import Workflow
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
ApplicationFolder, WorkFlowVersion
ApplicationFolder, ApplicationVersion
from application.models.application_access_token import ApplicationAccessToken
from common import result
from common.database_model_manage.database_model_manage import DatabaseModelManage
@ -614,6 +614,8 @@ class ApplicationOperateSerializer(serializers.Serializer):
def delete(self, with_valid=True):
if with_valid:
self.is_valid()
QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id')).delete()
QuerySet(ApplicationKnowledgeMapping).filter(application_id=self.data.get('application_id')).delete()
QuerySet(Application).filter(id=self.data.get('application_id')).delete()
return True
@ -644,6 +646,27 @@ class ApplicationOperateSerializer(serializers.Serializer):
except Exception as e:
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@staticmethod
def reset_application_version(application_version, application):
update_field_dict = {
'application_name': 'name', 'desc': 'desc', 'prologue': 'prologue', 'dialogue_number': 'dialogue_number',
'user_id': 'user_id', 'model_id': 'model_id', 'knowledge_setting': 'knowledge_setting',
'model_setting': 'model_setting', 'model_params_setting': 'model_params_setting',
'tts_model_params_setting': 'tts_model_params_setting',
'problem_optimization': 'problem_optimization', 'icon': 'icon', 'work_flow': 'work_flow',
'problem_optimization_prompt': 'problem_optimization_prompt', 'tts_model_id': 'tts_model_id',
'stt_model_id': 'stt_model_id', 'tts_model_enable': 'tts_model_enable',
'stt_model_enable': 'stt_model_enable', 'tts_type': 'tts_type',
'tts_autoplay': 'tts_autoplay', 'stt_autosend': 'stt_autosend', 'file_upload_enable': 'file_upload_enable',
'file_upload_setting': 'file_upload_setting',
'type': 'type'
}
for (version_field, app_field) in update_field_dict.items():
_v = getattr(application, app_field)
if _v:
setattr(application_version, version_field, _v)
@transaction.atomic
def publish(self, instance, with_valid=True):
if with_valid:
@ -653,25 +676,28 @@ class ApplicationOperateSerializer(serializers.Serializer):
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"))
Workflow.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
if application.type == ApplicationTypeChoices.WORK_FLOW:
work_flow = application.work_flow
if work_flow is None:
raise AppApiException(500, _("work_flow is a required field"))
Workflow.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.publish_time = datetime.datetime.now()
application.is_publish = True
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 = ApplicationVersion(work_flow=application.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)
self.reset_application_version(work_flow_version, application)
work_flow_version.save()
return self.one(with_valid=False)

View File

@ -12,7 +12,7 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.models import WorkFlowVersion, Application
from application.models import Application, ApplicationVersion
from common.db.search import page_search
from common.exception.app_exception import AppApiException
@ -25,7 +25,7 @@ class ApplicationVersionQuerySerializer(serializers.Serializer):
class ApplicationVersionModelSerializer(serializers.ModelSerializer):
class Meta:
model = WorkFlowVersion
model = ApplicationVersion
fields = ['id', 'name', 'workspace_id', 'application_id', 'work_flow', 'publish_user_id', 'publish_user_name',
'create_time',
'update_time']
@ -43,11 +43,11 @@ class ApplicationVersionSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
def get_query_set(self, query):
query_set = QuerySet(WorkFlowVersion).filter(application_id=query.get('application_id'))
query_set = QuerySet(ApplicationVersion).filter(application_id=query.get('application_id'))
if 'name' in query and query.get('name') is not None:
query_set = query_set.filter(name__contains=query.get('name'))
if 'workspace_id' in self.data and self.data.get('workspace_id') is not None:
query_set = query_set.filter(workspace_id=self.data.get('workspace_id').get('name'))
query_set = query_set.filter(workspace_id=self.data.get('workspace_id'))
return query_set.order_by("-create_time")
def list(self, query, with_valid=True):
@ -67,8 +67,8 @@ class ApplicationVersionSerializer(serializers.Serializer):
class Operate(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
work_flow_version_id = serializers.UUIDField(required=True,
label=_("Workflow version id"))
application_version_id = serializers.UUIDField(required=True,
label=_("Application version ID"))
def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True)
@ -82,10 +82,11 @@ class ApplicationVersionSerializer(serializers.Serializer):
def one(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get('work_flow_version_id')).first()
if work_flow_version is not None:
return ApplicationVersionModelSerializer(work_flow_version).data
application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get(
'application_version_id')).first()
if application_version is not None:
return ApplicationVersionModelSerializer(application_version).data
else:
raise AppApiException(500, _('Workflow version does not exist'))
@ -93,13 +94,14 @@ class ApplicationVersionSerializer(serializers.Serializer):
if with_valid:
self.is_valid(raise_exception=True)
ApplicationVersionEditSerializer(data=instance).is_valid(raise_exception=True)
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get('work_flow_version_id')).first()
if work_flow_version is not None:
application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get(
'application_version_id')).first()
if application_version is not None:
name = instance.get('name', None)
if name is not None and len(name) > 0:
work_flow_version.name = name
work_flow_version.save()
return ApplicationVersionModelSerializer(work_flow_version).data
application_version.name = name
application_version.save()
return ApplicationVersionModelSerializer(application_version).data
else:
raise AppApiException(500, _('Workflow version does not exist'))

View File

@ -14,8 +14,9 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
from application.chat_pipeline.step.chat_step.i_chat_step import PostResponseHandler
from application.models import Application, WorkFlowVersion, ChatRecord, Chat
from application.models import Application, ChatRecord, Chat, ApplicationVersion
from common.constants.cache_version import Cache_Version
from common.exception.app_exception import ChatException
from models_provider.models import Model
from models_provider.tools import get_model_credential
@ -28,8 +29,6 @@ class ChatInfo:
knowledge_id_list: List[str],
exclude_document_id_list: list[str],
application_id: str,
application: Application,
work_flow_version: WorkFlowVersion = None,
debug=False):
"""
:param chat_id: 对话id
@ -38,18 +37,16 @@ class ChatInfo:
:param knowledge_id_list: 知识库列表
:param exclude_document_id_list: 排除的文档
:param application_id 应用id
:param application: 应用信息
:param debug 是否是调试
"""
self.chat_id = chat_id
self.chat_user_id = chat_user_id
self.chat_user_type = chat_user_type
self.application = application
self.knowledge_id_list = knowledge_id_list
self.exclude_document_id_list = exclude_document_id_list
self.application_id = application_id
self.chat_record_list: List[ChatRecord] = []
self.work_flow_version = work_flow_version
self.application = None
self.debug = debug
@staticmethod
@ -63,10 +60,24 @@ class ChatInfo:
no_references_setting['value'] = no_references_prompt if len(no_references_prompt) > 0 else "{question}"
return no_references_setting
def get_application(self):
if self.debug:
application = QuerySet(Application).filter(id=self.application_id).first()
if not application:
raise ChatException(500, _('The application does not exist'))
else:
application = QuerySet(ApplicationVersion).filter(application_id=self.application_id).order_by(
'-create_time')[0:1].first()
if not application:
raise ChatException(500, _("The application has not been published. Please use it after publishing."))
self.application = application
return application
def to_base_pipeline_manage_params(self):
self.get_application()
knowledge_setting = self.application.knowledge_setting
model_setting = self.application.model_setting
model_id = self.application.model.id if self.application.model is not None else None
model_id = self.application.model_id
model_params_setting = None
if model_id is not None:
model = QuerySet(Model).filter(id=model_id).first()
@ -127,7 +138,7 @@ class ChatInfo:
self.chat_record_list.append(chat_record)
if not self.debug:
if not QuerySet(Chat).filter(id=self.chat_id).exists():
Chat(id=self.chat_id, application_id=self.application.id, abstract=chat_record.problem_text[0:1024],
Chat(id=self.chat_id, application_id=self.application_id, abstract=chat_record.problem_text[0:1024],
chat_user_id=self.chat_user_id, chat_user_type=self.chat_user_type).save()
else:
QuerySet(Chat).filter(id=self.chat_id).update(update_time=datetime.now())

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id",
"user"."nick_name" as "nick_name",
application."create_time",
application."update_time"
application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id
${application_custom_sql}
UNION
@ -25,6 +26,7 @@ from (select application."id"::text,
application_folder."user_id",
"user"."nick_name" as "nick_name",
application_folder."create_time",
application_folder."update_time"
application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set}

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id",
"user"."nick_name" as "nick_name",
application."create_time",
application."update_time"
application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id
where application."id" in (select target
from workspace_user_resource_permission
@ -28,6 +29,7 @@ from (select application."id"::text,
application_folder."user_id",
"user"."nick_name" as "nick_name",
application_folder."create_time",
application_folder."update_time"
application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set}

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id",
"user"."nick_name" as "nick_name",
application."create_time",
application."update_time"
application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id
where "application".id in (select target
from workspace_user_resource_permission
@ -41,6 +42,7 @@ from (select application."id"::text,
application_folder."user_id",
"user"."nick_name" as "nick_name",
application_folder."create_time",
application_folder."update_time"
application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set}

View File

@ -15,7 +15,7 @@ urlpatterns = [
path('workspace/<str:workspace_id>/application/<str:application_id>/application_stats', views.ApplicationStats.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key/<str:api_key_id>', views.ApplicationKey.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/export', views.ApplicationAPI.Export.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version', views.ApplicationVersionView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_version', views.ApplicationVersionView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/access_token', views.AccessToken.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/add_knowledge', views.ApplicationChatRecordAddKnowledge.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat', views.ApplicationChat.as_view()),
@ -27,8 +27,8 @@ urlpatterns = [
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/improve', views.ApplicationChatRecordImprove.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/improve', views.ApplicationChatRecordImproveParagraph.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/paragraph/<str:paragraph_id>/improve', views.ApplicationChatRecordImproveParagraph.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version/<int:current_page>/<int:page_size>', views.ApplicationVersionView.Page.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version/<str:work_flow_version_id>', views.ApplicationVersionView.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_version/<int:current_page>/<int:page_size>', views.ApplicationVersionView.Page.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_version/<str:application_version_id>', views.ApplicationVersionView.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/open', views.OpenView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/text_to_speech', views.TextToSpeech.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/speech_to_text', views.SpeechToText.as_view()),

View File

@ -132,7 +132,8 @@ class ApplicationAPI(APIView):
@has_permissions(PermissionConstants.APPLICATION_EXPORT.get_workspace_application_permission(),
PermissionConstants.APPLICATION_EXPORT.get_workspace_permission_workspace_manage_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.APPLICATION.get_workspace_application_permission()],CompareConstants.AND),
[PermissionConstants.APPLICATION.get_workspace_application_permission()],
CompareConstants.AND),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
@log(menu='Application', operate="Export Application",
get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')),
@ -227,7 +228,7 @@ class ApplicationAPI(APIView):
summary=_("Publishing an application"),
operation_id=_("Publishing an application"), # type: ignore
parameters=ApplicationOperateAPI.get_parameters(),
request=ApplicationEditAPI.get_request(),
request=None,
responses=result.DefaultResultSerializer,
tags=[_('Application')] # type: ignore
)

View File

@ -89,11 +89,11 @@ class ApplicationVersionView(APIView):
[PermissionConstants.APPLICATION.get_workspace_application_permission()],
CompareConstants.AND),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str):
def get(self, request: Request, workspace_id: str, application_id: str, application_version_id: str):
return result.success(
ApplicationVersionSerializer.Operate(
data={'user_id': request.user, 'workspace_id': workspace_id,
'application_id': application_id, 'work_flow_version_id': work_flow_version_id}).one())
'application_id': application_id, 'application_version_id': application_version_id}).one())
@extend_schema(
methods=['PUT'],
@ -114,10 +114,10 @@ class ApplicationVersionView(APIView):
@log(menu='Application', operate="Modify application version information",
get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')),
)
def put(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str):
def put(self, request: Request, workspace_id: str, application_id: str, application_version_id: str):
return result.success(
ApplicationVersionSerializer.Operate(
data={'application_id': application_id, 'workspace_id': workspace_id,
'work_flow_version_id': work_flow_version_id,
'application_version_id': application_version_id,
'user_id': request.user.id}).edit(
request.data))

View File

@ -25,8 +25,8 @@ from application.chat_pipeline.step.search_dataset_step.impl.base_search_dataset
from application.flow.common import Answer, Workflow
from application.flow.i_step_node import WorkFlowPostHandler
from application.flow.workflow_manage import WorkflowManage
from application.models import Application, ApplicationTypeChoices, WorkFlowVersion, ApplicationKnowledgeMapping, \
ChatUserType, ApplicationChatUserStats, ApplicationAccessToken, ChatRecord, Chat
from application.models import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
ChatUserType, ApplicationChatUserStats, ApplicationAccessToken, ChatRecord, Chat, ApplicationVersion
from application.serializers.application import ApplicationOperateSerializer
from application.serializers.common import ChatInfo
from common.exception.app_exception import AppApiException, AppChatNumOutOfBoundsFailed, ChatException
@ -124,7 +124,7 @@ class ChatSerializers(serializers.Serializer):
def is_valid_chat_id(self, chat_info: ChatInfo):
if self.data.get('application_id') is not None and self.data.get('application_id') != str(
chat_info.application.id):
chat_info.application_id):
raise ChatException(500, _("Conversation does not exist"))
def is_valid_intraday_access_num(self):
@ -148,10 +148,10 @@ class ChatSerializers(serializers.Serializer):
def is_valid_application_simple(self, *, chat_info: ChatInfo, raise_exception=False):
self.is_valid_intraday_access_num()
model = chat_info.application.model
if model is None:
model_id = chat_info.application.model_id
if model_id is None:
return chat_info
model = QuerySet(Model).filter(id=model.id).first()
model = QuerySet(Model).filter(id=model_id).first()
if model is None:
return chat_info
if model.status == Status.ERROR:
@ -226,10 +226,7 @@ class ChatSerializers(serializers.Serializer):
if chat_record_id is not None:
chat_record = self.get_chat_record(chat_info, chat_record_id)
history_chat_record = [r for r in chat_info.chat_record_list if str(r.id) != chat_record_id]
if not debug:
work_flow = chat_info.work_flow_version.work_flow
else:
work_flow = chat_info.application.work_flow
work_flow = chat_info.application.work_flow
work_flow_manage = WorkflowManage(Workflow.new_instance(work_flow),
{'history_chat_record': history_chat_record, 'question': message,
'chat_id': chat_info.chat_id, 'chat_record_id': str(
@ -252,6 +249,7 @@ class ChatSerializers(serializers.Serializer):
super().is_valid(raise_exception=True)
ChatMessageSerializers(data=instance).is_valid(raise_exception=True)
chat_info = self.get_chat_info()
chat_info.get_application()
self.is_valid_chat_id(chat_info)
if chat_info.application.type == ApplicationTypeChoices.SIMPLE:
self.is_valid_application_simple(raise_exception=True, chat_info=chat_info)
@ -301,14 +299,13 @@ class ChatSerializers(serializers.Serializer):
return chat_info
def re_open_chat_work_flow(self, chat_id, application):
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application.id).order_by(
application_version = QuerySet(ApplicationVersion).filter(application_id=application.id).order_by(
'-create_time')[0:1].first()
if work_flow_version is None:
if application_version is None:
raise ChatException(500, _("The application has not been published. Please use it after publishing."))
chat_info = ChatInfo(chat_id, self.data.get('chat_user_id'), self.data.get('chat_user_type'), [], [],
application.id,
application, work_flow_version)
application.id)
chat_record_list = list(QuerySet(ChatRecord).filter(chat_id=chat_id).order_by('-create_time')[0:5])
chat_record_list.sort(key=lambda r: r.create_time)
for chat_record in chat_record_list:
@ -349,18 +346,16 @@ class OpenChatSerializers(serializers.Serializer):
chat_user_type = self.data.get("chat_user_type")
debug = self.data.get("debug")
chat_id = str(uuid.uuid7())
work_flow_version = None
if not debug:
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application_id).order_by(
application_version = QuerySet(ApplicationVersion).filter(application_id=application_id).order_by(
'-create_time')[0:1].first()
if work_flow_version is None:
if application_version is None:
raise AppApiException(500,
gettext(
"The application has not been published. Please use it after publishing."))
ChatInfo(chat_id, chat_user_id, chat_user_type, [],
[],
application_id,
application, work_flow_version, debug).set_cache()
application_id, debug).set_cache()
return chat_id
def open_simple(self, application):
@ -378,7 +373,7 @@ class OpenChatSerializers(serializers.Serializer):
knowledge_id__in=knowledge_id_list,
is_active=False)],
application_id,
application, debug=debug).set_cache()
debug=debug).set_cache()
return chat_id

View File

@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from application.models import ApplicationAccessToken, ChatUserType, Application, ApplicationTypeChoices, \
WorkFlowVersion
ApplicationVersion
from application.serializers.application import ApplicationSerializerModel
from common.auth.common import ChatUserToken, ChatAuthentication
from common.constants.authentication_type import AuthenticationType
@ -79,6 +79,25 @@ class AuthProfileSerializer(serializers.Serializer):
class ApplicationProfileSerializer(serializers.Serializer):
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
@staticmethod
def reset_application(application, application_version):
update_field_dict = {
'application_name': 'name', 'desc': 'desc', 'prologue': 'prologue', 'dialogue_number': 'dialogue_number',
'user_id': 'user_id', 'model_id': 'model_id', 'knowledge_setting': 'knowledge_setting',
'model_setting': 'model_setting', 'model_params_setting': 'model_params_setting',
'tts_model_params_setting': 'tts_model_params_setting',
'problem_optimization': 'problem_optimization', 'icon': 'icon', 'work_flow': 'work_flow',
'problem_optimization_prompt': 'problem_optimization_prompt', 'tts_model_id': 'tts_model_id',
'stt_model_id': 'stt_model_id', 'tts_model_enable': 'tts_model_enable',
'stt_model_enable': 'stt_model_enable', 'tts_type': 'tts_type',
'tts_autoplay': 'tts_autoplay', 'stt_autosend': 'stt_autosend', 'file_upload_enable': 'file_upload_enable',
'file_upload_setting': 'file_upload_setting'
}
for (version_field, app_field) in update_field_dict.items():
_v = getattr(application_version, version_field)
if _v:
setattr(application, app_field, _v)
def profile(self, with_valid=True):
if with_valid:
self.is_valid()
@ -88,12 +107,10 @@ class ApplicationProfileSerializer(serializers.Serializer):
if application_access_token is None:
raise AppUnauthorizedFailed(500, _("Illegal User"))
application_setting_model = DatabaseModelManage.get_model('application_setting')
if application.type == ApplicationTypeChoices.WORK_FLOW:
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application.id).order_by(
'-create_time')[0:1].first()
if work_flow_version is not None:
application.work_flow = work_flow_version.work_flow
application_version = QuerySet(ApplicationVersion).filter(application_id=application.id).order_by(
'-create_time')[0:1].first()
if application_version is not None:
self.reset_application(application, application_version)
license_is_valid = cache.get(Cache_Version.SYSTEM.get_key(key='license_is_valid'),
version=Cache_Version.SYSTEM.get_version())
application_setting_dict = {}

View File

@ -18,7 +18,7 @@ const getWorkFlowVersion: (
application_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, loading) => {
return get(`${prefix.value}/${application_id}/work_flow_version`, undefined, loading)
return get(`${prefix.value}/${application_id}/application_version`, undefined, loading)
}
/**
@ -30,7 +30,7 @@ const getWorkFlowVersionDetail: (
loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, application_version_id, loading) => {
return get(
`${prefix.value}/${application_id}/work_flow_version/${application_version_id}`,
`${prefix.value}/${application_id}/application_version/${application_version_id}`,
undefined,
loading,
)
@ -45,7 +45,7 @@ const putWorkFlowVersion: (
loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, application_version_id, data, loading) => {
return put(
`${prefix.value}/${application_id}/work_flow_version/${application_version_id}`,
`${prefix.value}/${application_id}/application_version/${application_version_id}`,
data,
undefined,
loading,

View File

@ -114,7 +114,8 @@ export default {
},
},
buttons: {
publish: '保存并发布',
save: '保存',
publish: '发布',
addModel: '添加模型',
},

View File

@ -281,7 +281,10 @@ const publish = () => {
return
}
applicationApi
.publish(id, { work_flow: workflow }, loading)
.putApplication(id, { work_flow: workflow }, loading)
.then((ok) => {
return applicationApi.publish(id, {}, loading)
})
.then((ok: any) => {
detail.value.name = ok.data.name
MsgSuccess(t('views.applicationWorkflow.tip.publicSuccess'))

View File

@ -4,14 +4,24 @@
<h3>
{{ $t('common.setting') }}
</h3>
<el-button
type="primary"
@click="submit(applicationFormRef)"
:disabled="loading"
v-if="permissionPrecise.edit(id)"
>
{{ $t('views.application.buttons.publish') }}
</el-button>
<div>
<el-button
type="primary"
@click="submit(applicationFormRef)"
:disabled="loading"
v-if="permissionPrecise.edit(id)"
>
{{ $t('views.application.buttons.save') }}
</el-button>
<el-button
type="primary"
@click="publish(applicationFormRef)"
:disabled="loading"
v-if="permissionPrecise.edit(id)"
>
{{ $t('views.application.buttons.publish') }}
</el-button>
</div>
</div>
<el-card style="--el-card-padding: 0">
<el-row v-loading="loading">
@ -444,7 +454,7 @@ import { t } from '@/locales'
import TTSModeParamSettingDialog from './component/TTSModeParamSettingDialog.vue'
import ReasoningParamSettingDialog from './component/ReasoningParamSettingDialog.vue'
import permissionMap from '@/permission'
import ApplicationAPI from '@/api/application/application'
const route = useRoute()
const apiType = computed<'workspace'>(() => {
@ -549,7 +559,18 @@ function submitReasoningDialog(val: any) {
...val,
}
}
const publish = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate().then(() => {
return ApplicationAPI.putApplication(id, applicationForm.value, loading)
.then((ok) => {
return ApplicationAPI.publish(id, {}, loading)
})
.then((res) => {
MsgSuccess(t('common.saveSuccess'))
})
})
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {