Skip to content

Commit d2ed736

Browse files
committed
feat: Simple application version
1 parent 23b835f commit d2ed736

File tree

18 files changed

+282
-103
lines changed

18 files changed

+282
-103
lines changed

apps/application/api/application_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class ApplicationVersionOperateAPI(APIMixin):
5555
def get_parameters():
5656
return [
5757
OpenApiParameter(
58-
name="work_flow_version_id",
58+
name="application_version_id",
5959
description="工作流版本id",
6060
type=OpenApiTypes.STR,
6161
location='path',
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Generated by Django 5.2.3 on 2025-07-04 03:18
2+
3+
import application.models.application
4+
import django.db.models.deletion
5+
import uuid_utils.compat
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('application', '0003_chat_asker_chat_meta_and_more'),
13+
('users', '0001_initial'),
14+
]
15+
16+
operations = [
17+
migrations.AddField(
18+
model_name='application',
19+
name='publish_time',
20+
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='发布时间'),
21+
),
22+
migrations.CreateModel(
23+
name='ApplicationVersion',
24+
fields=[
25+
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
26+
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
27+
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
28+
('name', models.CharField(default='', max_length=128, verbose_name='版本名称')),
29+
('publish_user_id', models.UUIDField(default=None, null=True, verbose_name='发布者id')),
30+
('publish_user_name', models.CharField(default='', max_length=128, verbose_name='发布者名称')),
31+
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
32+
('application_name', models.CharField(max_length=128, verbose_name='应用名称')),
33+
('desc', models.CharField(default='', max_length=512, verbose_name='引用描述')),
34+
('prologue', models.CharField(default='', max_length=40960, verbose_name='开场白')),
35+
('dialogue_number', models.IntegerField(default=0, verbose_name='会话数量')),
36+
('model_id', models.UUIDField(blank=True, null=True, verbose_name='大语言模型')),
37+
('knowledge_setting', models.JSONField(default=application.models.application.get_dataset_setting_dict, verbose_name='数据集参数设置')),
38+
('model_setting', models.JSONField(default=application.models.application.get_model_setting_dict, verbose_name='模型参数相关设置')),
39+
('model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
40+
('tts_model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
41+
('problem_optimization', models.BooleanField(default=False, verbose_name='问题优化')),
42+
('icon', models.CharField(default='./favicon.ico', max_length=256, verbose_name='应用icon')),
43+
('work_flow', models.JSONField(default=dict, verbose_name='工作流数据')),
44+
('type', models.CharField(choices=[('SIMPLE', '简易'), ('WORK_FLOW', '工作流')], default='SIMPLE', max_length=256, verbose_name='应用类型')),
45+
('problem_optimization_prompt', models.CharField(blank=True, default='()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中', max_length=102400, null=True, verbose_name='问题优化提示词')),
46+
('tts_model_id', models.UUIDField(blank=True, null=True, verbose_name='文本转语音模型id')),
47+
('stt_model_id', models.UUIDField(blank=True, null=True, verbose_name='语音转文本模型id')),
48+
('tts_model_enable', models.BooleanField(default=False, verbose_name='语音合成模型是否启用')),
49+
('stt_model_enable', models.BooleanField(default=False, verbose_name='语音识别模型是否启用')),
50+
('tts_type', models.CharField(default='BROWSER', max_length=20, verbose_name='语音播放类型')),
51+
('tts_autoplay', models.BooleanField(default=False, verbose_name='自动播放')),
52+
('stt_autosend', models.BooleanField(default=False, verbose_name='自动发送')),
53+
('clean_time', models.IntegerField(default=180, verbose_name='清理时间')),
54+
('file_upload_enable', models.BooleanField(default=False, verbose_name='文件上传是否启用')),
55+
('file_upload_setting', models.JSONField(default=dict, verbose_name='文件上传相关设置')),
56+
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='application.application')),
57+
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.user')),
58+
],
59+
options={
60+
'db_table': 'application_version',
61+
},
62+
),
63+
migrations.DeleteModel(
64+
name='WorkFlowVersion',
65+
),
66+
]

apps/application/models/application.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class Application(AppModelMixin):
9090
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
9191
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
9292
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
93+
publish_time = models.DateTimeField(verbose_name="发布时间", default=None, null=True, blank=True)
9394
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
9495
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
9596

@@ -120,14 +121,43 @@ class Meta:
120121
db_table = "application_knowledge_mapping"
121122

122123

123-
class WorkFlowVersion(AppModelMixin):
124+
class ApplicationVersion(AppModelMixin):
124125
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
125126
application = models.ForeignKey(Application, on_delete=models.CASCADE)
126-
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
127127
name = models.CharField(verbose_name="版本名称", max_length=128, default="")
128128
publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True)
129129
publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="")
130+
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
131+
application_name = models.CharField(max_length=128, verbose_name="应用名称")
132+
desc = models.CharField(max_length=512, verbose_name="引用描述", default="")
133+
prologue = models.CharField(max_length=40960, verbose_name="开场白", default="")
134+
dialogue_number = models.IntegerField(default=0, verbose_name="会话数量")
135+
user = models.ForeignKey(User, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
136+
model_id = models.UUIDField(verbose_name="大语言模型", blank=True, null=True)
137+
knowledge_setting = models.JSONField(verbose_name="数据集参数设置", default=get_dataset_setting_dict)
138+
model_setting = models.JSONField(verbose_name="模型参数相关设置", default=get_model_setting_dict)
139+
model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
140+
tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
141+
problem_optimization = models.BooleanField(verbose_name="问题优化", default=False)
142+
icon = models.CharField(max_length=256, verbose_name="应用icon", default="./favicon.ico")
130143
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
144+
type = models.CharField(verbose_name="应用类型", choices=ApplicationTypeChoices.choices,
145+
default=ApplicationTypeChoices.SIMPLE, max_length=256)
146+
problem_optimization_prompt = models.CharField(verbose_name="问题优化提示词", max_length=102400, blank=True,
147+
null=True,
148+
default="()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中")
149+
tts_model_id = models.UUIDField(verbose_name="文本转语音模型id",
150+
blank=True, null=True)
151+
stt_model_id = models.UUIDField(verbose_name="语音转文本模型id",
152+
blank=True, null=True)
153+
tts_model_enable = models.BooleanField(verbose_name="语音合成模型是否启用", default=False)
154+
stt_model_enable = models.BooleanField(verbose_name="语音识别模型是否启用", default=False)
155+
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")
156+
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
157+
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
158+
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
159+
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
160+
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
131161

132162
class Meta:
133-
db_table = "application_work_flow_version"
163+
db_table = "application_version"

apps/application/serializers/application.py

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from application.flow.common import Workflow
2929
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
30-
ApplicationFolder, WorkFlowVersion
30+
ApplicationFolder, ApplicationVersion
3131
from application.models.application_access_token import ApplicationAccessToken
3232
from common import result
3333
from common.database_model_manage.database_model_manage import DatabaseModelManage
@@ -614,6 +614,8 @@ def get_mcp_servers(self, instance, with_valid=True):
614614
def delete(self, with_valid=True):
615615
if with_valid:
616616
self.is_valid()
617+
QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id')).delete()
618+
QuerySet(ApplicationKnowledgeMapping).filter(application_id=self.data.get('application_id')).delete()
617619
QuerySet(Application).filter(id=self.data.get('application_id')).delete()
618620
return True
619621

@@ -644,6 +646,27 @@ def export(self, with_valid=True):
644646
except Exception as e:
645647
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
646648

649+
@staticmethod
650+
def reset_application_version(application_version, application):
651+
update_field_dict = {
652+
'application_name': 'name', 'desc': 'desc', 'prologue': 'prologue', 'dialogue_number': 'dialogue_number',
653+
'user_id': 'user_id', 'model_id': 'model_id', 'knowledge_setting': 'knowledge_setting',
654+
'model_setting': 'model_setting', 'model_params_setting': 'model_params_setting',
655+
'tts_model_params_setting': 'tts_model_params_setting',
656+
'problem_optimization': 'problem_optimization', 'icon': 'icon', 'work_flow': 'work_flow',
657+
'problem_optimization_prompt': 'problem_optimization_prompt', 'tts_model_id': 'tts_model_id',
658+
'stt_model_id': 'stt_model_id', 'tts_model_enable': 'tts_model_enable',
659+
'stt_model_enable': 'stt_model_enable', 'tts_type': 'tts_type',
660+
'tts_autoplay': 'tts_autoplay', 'stt_autosend': 'stt_autosend', 'file_upload_enable': 'file_upload_enable',
661+
'file_upload_setting': 'file_upload_setting',
662+
'type': 'type'
663+
}
664+
665+
for (version_field, app_field) in update_field_dict.items():
666+
_v = getattr(application, app_field)
667+
if _v:
668+
setattr(application_version, version_field, _v)
669+
647670
@transaction.atomic
648671
def publish(self, instance, with_valid=True):
649672
if with_valid:
@@ -653,25 +676,28 @@ def publish(self, instance, with_valid=True):
653676
user = QuerySet(User).filter(id=user_id).first()
654677
application = QuerySet(Application).filter(id=self.data.get("application_id"),
655678
workspace_id=workspace_id).first()
656-
work_flow = instance.get('work_flow')
657-
if work_flow is None:
658-
raise AppApiException(500, _("work_flow is a required field"))
659-
Workflow.new_instance(work_flow).is_valid()
660-
base_node = get_base_node_work_flow(work_flow)
661-
if base_node is not None:
662-
node_data = base_node.get('properties').get('node_data')
663-
if node_data is not None:
664-
application.name = node_data.get('name')
665-
application.desc = node_data.get('desc')
666-
application.prologue = node_data.get('prologue')
667-
application.work_flow = work_flow
679+
if application.type == ApplicationTypeChoices.WORK_FLOW:
680+
work_flow = application.work_flow
681+
if work_flow is None:
682+
raise AppApiException(500, _("work_flow is a required field"))
683+
Workflow.new_instance(work_flow).is_valid()
684+
base_node = get_base_node_work_flow(work_flow)
685+
if base_node is not None:
686+
node_data = base_node.get('properties').get('node_data')
687+
if node_data is not None:
688+
application.name = node_data.get('name')
689+
application.desc = node_data.get('desc')
690+
application.prologue = node_data.get('prologue')
691+
application.work_flow = work_flow
692+
application.publish_time = datetime.datetime.now()
668693
application.is_publish = True
669694
application.save()
670-
work_flow_version = WorkFlowVersion(work_flow=work_flow, application=application,
671-
name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
672-
publish_user_id=user_id,
673-
publish_user_name=user.username,
674-
workspace_id=workspace_id)
695+
work_flow_version = ApplicationVersion(work_flow=application.work_flow, application=application,
696+
name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
697+
publish_user_id=user_id,
698+
publish_user_name=user.username,
699+
workspace_id=workspace_id)
700+
self.reset_application_version(work_flow_version, application)
675701
work_flow_version.save()
676702
return self.one(with_valid=False)
677703

apps/application/serializers/application_version.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from django.utils.translation import gettext_lazy as _
1313
from rest_framework import serializers
1414

15-
from application.models import WorkFlowVersion, Application
15+
from application.models import Application, ApplicationVersion
1616
from common.db.search import page_search
1717
from common.exception.app_exception import AppApiException
1818

@@ -25,7 +25,7 @@ class ApplicationVersionQuerySerializer(serializers.Serializer):
2525

2626
class ApplicationVersionModelSerializer(serializers.ModelSerializer):
2727
class Meta:
28-
model = WorkFlowVersion
28+
model = ApplicationVersion
2929
fields = ['id', 'name', 'workspace_id', 'application_id', 'work_flow', 'publish_user_id', 'publish_user_name',
3030
'create_time',
3131
'update_time']
@@ -43,11 +43,11 @@ class Query(serializers.Serializer):
4343
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
4444

4545
def get_query_set(self, query):
46-
query_set = QuerySet(WorkFlowVersion).filter(application_id=query.get('application_id'))
46+
query_set = QuerySet(ApplicationVersion).filter(application_id=query.get('application_id'))
4747
if 'name' in query and query.get('name') is not None:
4848
query_set = query_set.filter(name__contains=query.get('name'))
4949
if 'workspace_id' in self.data and self.data.get('workspace_id') is not None:
50-
query_set = query_set.filter(workspace_id=self.data.get('workspace_id').get('name'))
50+
query_set = query_set.filter(workspace_id=self.data.get('workspace_id'))
5151
return query_set.order_by("-create_time")
5252

5353
def list(self, query, with_valid=True):
@@ -67,8 +67,8 @@ def page(self, query, current_page, page_size, with_valid=True):
6767
class Operate(serializers.Serializer):
6868
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
6969
application_id = serializers.UUIDField(required=True, label=_("Application ID"))
70-
work_flow_version_id = serializers.UUIDField(required=True,
71-
label=_("Workflow version id"))
70+
application_version_id = serializers.UUIDField(required=True,
71+
label=_("Application version ID"))
7272

7373
def is_valid(self, *, raise_exception=False):
7474
super().is_valid(raise_exception=True)
@@ -82,24 +82,26 @@ def is_valid(self, *, raise_exception=False):
8282
def one(self, with_valid=True):
8383
if with_valid:
8484
self.is_valid(raise_exception=True)
85-
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'),
86-
id=self.data.get('work_flow_version_id')).first()
87-
if work_flow_version is not None:
88-
return ApplicationVersionModelSerializer(work_flow_version).data
85+
application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
86+
id=self.data.get(
87+
'application_version_id')).first()
88+
if application_version is not None:
89+
return ApplicationVersionModelSerializer(application_version).data
8990
else:
9091
raise AppApiException(500, _('Workflow version does not exist'))
9192

9293
def edit(self, instance: Dict, with_valid=True):
9394
if with_valid:
9495
self.is_valid(raise_exception=True)
9596
ApplicationVersionEditSerializer(data=instance).is_valid(raise_exception=True)
96-
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'),
97-
id=self.data.get('work_flow_version_id')).first()
98-
if work_flow_version is not None:
97+
application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
98+
id=self.data.get(
99+
'application_version_id')).first()
100+
if application_version is not None:
99101
name = instance.get('name', None)
100102
if name is not None and len(name) > 0:
101-
work_flow_version.name = name
102-
work_flow_version.save()
103-
return ApplicationVersionModelSerializer(work_flow_version).data
103+
application_version.name = name
104+
application_version.save()
105+
return ApplicationVersionModelSerializer(application_version).data
104106
else:
105107
raise AppApiException(500, _('Workflow version does not exist'))

0 commit comments

Comments
 (0)