diff --git a/apps/application/api/application_api_key.py b/apps/application/api/application_api_key.py
new file mode 100644
index 000000000..6c5c6fa2a
--- /dev/null
+++ b/apps/application/api/application_api_key.py
@@ -0,0 +1,33 @@
+from drf_spectacular.types import OpenApiTypes
+from drf_spectacular.utils import OpenApiParameter
+
+from common.mixins.api_mixin import APIMixin
+
+
+class ApplicationKeyCreateAPI(APIMixin):
+ @staticmethod
+ def get_parameters():
+ return [
+ OpenApiParameter(
+ name="workspace_id",
+ description="工作空间id",
+ type=OpenApiTypes.STR,
+ location='path',
+ required=True,
+ ),
+ OpenApiParameter(
+ name="application_id",
+ description="application ID",
+ type=OpenApiTypes.STR,
+ location='path',
+ required=True,
+ )
+ ]
+
+ # class Operate(APIMixin):
+ # @staticmethod
+ # def s():
+ # pass
+
+ # def get_response():
+ # return ApplicationKeyCreateResponse
diff --git a/apps/application/migrations/0001_initial.py b/apps/application/migrations/0001_initial.py
new file mode 100644
index 000000000..4c6dd91a6
--- /dev/null
+++ b/apps/application/migrations/0001_initial.py
@@ -0,0 +1,78 @@
+# Generated by Django 5.2.1 on 2025-05-26 10:19
+
+import application.models.application
+import django.db.models.deletion
+import mptt.fields
+import uuid_utils.compat
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('models_provider', '0001_initial'),
+ ('users', '0002_alter_user_nick_name'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ApplicationFolder',
+ fields=[
+ ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
+ ('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
+ ('id', models.CharField(editable=False, max_length=64, primary_key=True, serialize=False, verbose_name='主键id')),
+ ('name', models.CharField(max_length=64, verbose_name='文件夹名称')),
+ ('desc', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
+ ('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
+ ('lft', models.PositiveIntegerField(editable=False)),
+ ('rght', models.PositiveIntegerField(editable=False)),
+ ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
+ ('level', models.PositiveIntegerField(editable=False)),
+ ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='application.applicationfolder')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='users.user', verbose_name='用户id')),
+ ],
+ options={
+ 'db_table': 'application_folder',
+ },
+ ),
+ migrations.CreateModel(
+ name='Application',
+ 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')),
+ ('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
+ ('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='会话数量')),
+ ('dataset_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='/ui/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}) 要求: 输出一个补全问题,并且放在标签中', max_length=102400, null=True, verbose_name='问题优化提示词')),
+ ('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='文件上传相关设置')),
+ ('model', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='models_provider.model')),
+ ('stt_model', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stt_model_id', to='models_provider.model')),
+ ('tts_model', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tts_model_id', to='models_provider.model')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='users.user')),
+ ('folder', models.ForeignKey(default='root', on_delete=django.db.models.deletion.DO_NOTHING, to='application.applicationfolder', verbose_name='文件夹id')),
+ ],
+ options={
+ 'db_table': 'application',
+ },
+ ),
+ ]
diff --git a/apps/application/migrations/0002_applicationapikey.py b/apps/application/migrations/0002_applicationapikey.py
new file mode 100644
index 000000000..8629039fb
--- /dev/null
+++ b/apps/application/migrations/0002_applicationapikey.py
@@ -0,0 +1,35 @@
+# Generated by Django 5.2.1 on 2025-05-26 10:21
+
+import django.contrib.postgres.fields
+import django.db.models.deletion
+import uuid
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('application', '0001_initial'),
+ ('users', '0002_alter_user_nick_name'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ApplicationApiKey',
+ 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.uuid1, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
+ ('secret_key', models.CharField(max_length=1024, unique=True, verbose_name='秘钥')),
+ ('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
+ ('is_active', models.BooleanField(default=True, verbose_name='是否开启')),
+ ('allow_cross_domain', models.BooleanField(default=False, verbose_name='是否允许跨域')),
+ ('cross_domain_list', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=128), default=list, size=None, verbose_name='跨域列表')),
+ ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='application.application', verbose_name='应用id')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.user', verbose_name='用户id')),
+ ],
+ options={
+ 'db_table': 'application_api_key',
+ },
+ ),
+ ]
diff --git a/apps/application/models/application_api_key.py b/apps/application/models/application_api_key.py
new file mode 100644
index 000000000..69fad9ba6
--- /dev/null
+++ b/apps/application/models/application_api_key.py
@@ -0,0 +1,26 @@
+
+import uuid
+
+from django.contrib.postgres.fields import ArrayField
+from django.db import models
+
+from application.models import Application
+from common.mixins.app_model_mixin import AppModelMixin
+
+from users.models import User
+
+
+class ApplicationApiKey(AppModelMixin):
+ id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
+ secret_key = models.CharField(max_length=1024, verbose_name="秘钥", unique=True)
+ user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户id")
+ workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
+ application = models.ForeignKey(Application, on_delete=models.CASCADE, verbose_name="应用id")
+ is_active = models.BooleanField(default=True, verbose_name="是否开启")
+ allow_cross_domain = models.BooleanField(default=False, verbose_name="是否允许跨域")
+ cross_domain_list = ArrayField(verbose_name="跨域列表",
+ base_field=models.CharField(max_length=128, blank=True)
+ , default=list)
+
+ class Meta:
+ db_table = "application_api_key"
\ No newline at end of file
diff --git a/apps/application/serializers/application_api_key.py b/apps/application/serializers/application_api_key.py
new file mode 100644
index 000000000..dc352169f
--- /dev/null
+++ b/apps/application/serializers/application_api_key.py
@@ -0,0 +1,69 @@
+import hashlib
+import uuid_utils.compat as uuid
+from baidubce.services.bmr.bmr_client import application
+
+from django.db.models import QuerySet
+from rest_framework import serializers
+from django.utils.translation import gettext_lazy as _
+
+from application.models import Application
+from application.models.application_api_key import ApplicationApiKey
+from common.exception.app_exception import AppApiException
+
+
+class ApplicationKeySerializerModel(serializers.ModelSerializer):
+ class Meta:
+ model = ApplicationApiKey
+ fields = "__all__"
+
+class Edit(serializers.Serializer):
+ pass
+
+
+class ApplicationKeySerializer(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 is_valid(self, *, raise_exception=False):
+ super().is_valid(raise_exception=True)
+ application_id = self.data.get("application_id")
+ application = QuerySet(Application).filter(id=application_id).first()
+ if application is None:
+ raise AppApiException(1001, _("Application does not exist"))
+
+ def generate(self, with_valid=True):
+ if with_valid:
+ self.is_valid(raise_exception=True)
+ application_id = self.data.get("application_id")
+ application = QuerySet(Application).filter(id=application_id).first()
+ secret_key = 'application-' + hashlib.md5(str(uuid.uuid1()).encode()).hexdigest()
+ application_api_key = ApplicationApiKey(id=uuid.uuid1(),
+ secret_key=secret_key,
+ user_id=application.user_id,
+ application_id=application_id)
+ application_api_key.save()
+ return ApplicationKeySerializerModel(application_api_key).data
+
+ 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)]
+
+ 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)
+
diff --git a/apps/application/urls.py b/apps/application/urls.py
new file mode 100644
index 000000000..b4c63f627
--- /dev/null
+++ b/apps/application/urls.py
@@ -0,0 +1,9 @@
+from django.urls import path
+
+from . import views
+
+app_name = 'application'
+
+urlpatterns = [
+ path('workspace//application//application_key', views.ApplicationKey.as_view()),
+]
diff --git a/apps/application/views/__init__.py b/apps/application/views/__init__.py
index 9b6036777..c168364ef 100644
--- a/apps/application/views/__init__.py
+++ b/apps/application/views/__init__.py
@@ -6,3 +6,4 @@
@date:2025/5/9 18:51
@desc:
"""
+from .application_api_key import *
\ No newline at end of file
diff --git a/apps/application/views/application_api_key.py b/apps/application/views/application_api_key.py
new file mode 100644
index 000000000..419472e01
--- /dev/null
+++ b/apps/application/views/application_api_key.py
@@ -0,0 +1,58 @@
+from drf_spectacular.utils import extend_schema
+from rest_framework.request import Request
+from rest_framework.views import APIView
+from django.utils.translation import gettext_lazy as _
+
+from application.api.application_api_key import ApplicationKeyCreateAPI
+from application.serializers.application_api_key import ApplicationKeySerializer
+from common.auth import TokenAuth
+from common.result import result, success
+
+
+class ApplicationKey(APIView):
+ authentication_classes = [TokenAuth]
+
+ @extend_schema(
+ methods=['POST'],
+ description=_('Create application ApiKey'),
+ summary=_('Create application ApiKey'),
+ operation_id=_('Create application ApiKey'), # type: ignore
+ parameters=ApplicationKeyCreateAPI.get_parameters(),
+ tags=[_('Application Api Key')] # type: ignore
+ )
+ def post(self,request: Request, application_id: str, workspace_id: str):
+ return result.success(ApplicationKeySerializer(
+ data={'application_id': application_id, 'user_id': request.user.id,
+ 'workspace_id':workspace_id}).generate())
+
+ @extend_schema(
+ methods=['GET'],
+ description=_('GET application ApiKey List'),
+ summary=_('Create application ApiKey List'),
+ operation_id=_('Create application ApiKey List'), # type: ignore
+ parameters=ApplicationKeyCreateAPI.get_parameters(),
+ tags=[_('Application Api Key')] # type: ignore
+ )
+ def get(self,request: Request, application_id: str, workspace_id: str):
+ return result,success(ApplicationKeySerializer(
+ data={'application_id':application_id, 'user_id':request.user.id,
+ 'workspace_id':workspace_id}).list())
+
+
+ class Operate(APIView):
+ authentication_classes = [TokenAuth]
+
+ @extend_schema(
+ methods=['GET'],
+ description=_('GET application ApiKey List'),
+ summary=_('Create application ApiKey List'),
+ operation_id=_('Create application ApiKey List'), # type: ignore
+ parameters=ApplicationKeyCreateAPI.get_parameters(),
+ tags=[_('Application Api Key')] # type: ignore
+ )
+ def put(self, request: Request, application_id: str, workspace_id: str):
+ return result.success(ApplicationKeySerializer.Operate(
+
+ )
+ )
+