Skip to content

Commit b044d4f

Browse files
committed
feat: Application Apikey
1 parent 356dbeb commit b044d4f

File tree

8 files changed

+309
-0
lines changed

8 files changed

+309
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from drf_spectacular.types import OpenApiTypes
2+
from drf_spectacular.utils import OpenApiParameter
3+
4+
from common.mixins.api_mixin import APIMixin
5+
6+
7+
class ApplicationKeyCreateAPI(APIMixin):
8+
@staticmethod
9+
def get_parameters():
10+
return [
11+
OpenApiParameter(
12+
name="workspace_id",
13+
description="工作空间id",
14+
type=OpenApiTypes.STR,
15+
location='path',
16+
required=True,
17+
),
18+
OpenApiParameter(
19+
name="application_id",
20+
description="application ID",
21+
type=OpenApiTypes.STR,
22+
location='path',
23+
required=True,
24+
)
25+
]
26+
27+
# class Operate(APIMixin):
28+
# @staticmethod
29+
# def s():
30+
# pass
31+
32+
# def get_response():
33+
# return ApplicationKeyCreateResponse
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Generated by Django 5.2.1 on 2025-05-26 10:19
2+
3+
import application.models.application
4+
import django.db.models.deletion
5+
import mptt.fields
6+
import uuid_utils.compat
7+
from django.db import migrations, models
8+
9+
10+
class Migration(migrations.Migration):
11+
12+
initial = True
13+
14+
dependencies = [
15+
('models_provider', '0001_initial'),
16+
('users', '0002_alter_user_nick_name'),
17+
]
18+
19+
operations = [
20+
migrations.CreateModel(
21+
name='ApplicationFolder',
22+
fields=[
23+
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
24+
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
25+
('id', models.CharField(editable=False, max_length=64, primary_key=True, serialize=False, verbose_name='主键id')),
26+
('name', models.CharField(max_length=64, verbose_name='文件夹名称')),
27+
('desc', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
28+
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
29+
('lft', models.PositiveIntegerField(editable=False)),
30+
('rght', models.PositiveIntegerField(editable=False)),
31+
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
32+
('level', models.PositiveIntegerField(editable=False)),
33+
('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='application.applicationfolder')),
34+
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='users.user', verbose_name='用户id')),
35+
],
36+
options={
37+
'db_table': 'application_folder',
38+
},
39+
),
40+
migrations.CreateModel(
41+
name='Application',
42+
fields=[
43+
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
44+
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
45+
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
46+
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
47+
('name', models.CharField(max_length=128, verbose_name='应用名称')),
48+
('desc', models.CharField(default='', max_length=512, verbose_name='引用描述')),
49+
('prologue', models.CharField(default='', max_length=40960, verbose_name='开场白')),
50+
('dialogue_number', models.IntegerField(default=0, verbose_name='会话数量')),
51+
('dataset_setting', models.JSONField(default=application.models.application.get_dataset_setting_dict, verbose_name='数据集参数设置')),
52+
('model_setting', models.JSONField(default=application.models.application.get_model_setting_dict, verbose_name='模型参数相关设置')),
53+
('model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
54+
('tts_model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
55+
('problem_optimization', models.BooleanField(default=False, verbose_name='问题优化')),
56+
('icon', models.CharField(default='/ui/favicon.ico', max_length=256, verbose_name='应用icon')),
57+
('work_flow', models.JSONField(default=dict, verbose_name='工作流数据')),
58+
('type', models.CharField(choices=[('SIMPLE', '简易'), ('WORK_FLOW', '工作流')], default='SIMPLE', max_length=256, verbose_name='应用类型')),
59+
('problem_optimization_prompt', models.CharField(blank=True, default='()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中', max_length=102400, null=True, verbose_name='问题优化提示词')),
60+
('tts_model_enable', models.BooleanField(default=False, verbose_name='语音合成模型是否启用')),
61+
('stt_model_enable', models.BooleanField(default=False, verbose_name='语音识别模型是否启用')),
62+
('tts_type', models.CharField(default='BROWSER', max_length=20, verbose_name='语音播放类型')),
63+
('tts_autoplay', models.BooleanField(default=False, verbose_name='自动播放')),
64+
('stt_autosend', models.BooleanField(default=False, verbose_name='自动发送')),
65+
('clean_time', models.IntegerField(default=180, verbose_name='清理时间')),
66+
('file_upload_enable', models.BooleanField(default=False, verbose_name='文件上传是否启用')),
67+
('file_upload_setting', models.JSONField(default=dict, verbose_name='文件上传相关设置')),
68+
('model', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='models_provider.model')),
69+
('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')),
70+
('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')),
71+
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='users.user')),
72+
('folder', models.ForeignKey(default='root', on_delete=django.db.models.deletion.DO_NOTHING, to='application.applicationfolder', verbose_name='文件夹id')),
73+
],
74+
options={
75+
'db_table': 'application',
76+
},
77+
),
78+
]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Generated by Django 5.2.1 on 2025-05-26 10:21
2+
3+
import django.contrib.postgres.fields
4+
import django.db.models.deletion
5+
import uuid
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('application', '0001_initial'),
13+
('users', '0002_alter_user_nick_name'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='ApplicationApiKey',
19+
fields=[
20+
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
21+
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
22+
('id', models.UUIDField(default=uuid.uuid1, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
23+
('secret_key', models.CharField(max_length=1024, unique=True, verbose_name='秘钥')),
24+
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
25+
('is_active', models.BooleanField(default=True, verbose_name='是否开启')),
26+
('allow_cross_domain', models.BooleanField(default=False, verbose_name='是否允许跨域')),
27+
('cross_domain_list', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=128), default=list, size=None, verbose_name='跨域列表')),
28+
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='application.application', verbose_name='应用id')),
29+
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.user', verbose_name='用户id')),
30+
],
31+
options={
32+
'db_table': 'application_api_key',
33+
},
34+
),
35+
]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
import uuid
3+
4+
from django.contrib.postgres.fields import ArrayField
5+
from django.db import models
6+
7+
from application.models import Application
8+
from common.mixins.app_model_mixin import AppModelMixin
9+
10+
from users.models import User
11+
12+
13+
class ApplicationApiKey(AppModelMixin):
14+
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
15+
secret_key = models.CharField(max_length=1024, verbose_name="秘钥", unique=True)
16+
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户id")
17+
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
18+
application = models.ForeignKey(Application, on_delete=models.CASCADE, verbose_name="应用id")
19+
is_active = models.BooleanField(default=True, verbose_name="是否开启")
20+
allow_cross_domain = models.BooleanField(default=False, verbose_name="是否允许跨域")
21+
cross_domain_list = ArrayField(verbose_name="跨域列表",
22+
base_field=models.CharField(max_length=128, blank=True)
23+
, default=list)
24+
25+
class Meta:
26+
db_table = "application_api_key"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import hashlib
2+
import uuid_utils.compat as uuid
3+
from baidubce.services.bmr.bmr_client import application
4+
5+
from django.db.models import QuerySet
6+
from rest_framework import serializers
7+
from django.utils.translation import gettext_lazy as _
8+
9+
from application.models import Application
10+
from application.models.application_api_key import ApplicationApiKey
11+
from common.exception.app_exception import AppApiException
12+
13+
14+
class ApplicationKeySerializerModel(serializers.ModelSerializer):
15+
class Meta:
16+
model = ApplicationApiKey
17+
fields = "__all__"
18+
19+
class Edit(serializers.Serializer):
20+
pass
21+
22+
23+
class ApplicationKeySerializer(serializers.Serializer):
24+
user_id = serializers.UUIDField(required=True, label=_('user id'))
25+
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
26+
application_id = serializers.UUIDField(required=True, label=_('application id'))
27+
28+
29+
30+
31+
32+
def is_valid(self, *, raise_exception=False):
33+
super().is_valid(raise_exception=True)
34+
application_id = self.data.get("application_id")
35+
application = QuerySet(Application).filter(id=application_id).first()
36+
if application is None:
37+
raise AppApiException(1001, _("Application does not exist"))
38+
39+
def generate(self, with_valid=True):
40+
if with_valid:
41+
self.is_valid(raise_exception=True)
42+
application_id = self.data.get("application_id")
43+
application = QuerySet(Application).filter(id=application_id).first()
44+
secret_key = 'application-' + hashlib.md5(str(uuid.uuid1()).encode()).hexdigest()
45+
application_api_key = ApplicationApiKey(id=uuid.uuid1(),
46+
secret_key=secret_key,
47+
user_id=application.user_id,
48+
application_id=application_id)
49+
application_api_key.save()
50+
return ApplicationKeySerializerModel(application_api_key).data
51+
52+
def list(self,with_valid=True):
53+
if with_valid:
54+
self.is_valid(raise_exception=True)
55+
application_id = self.data.get("application_id")
56+
return [ApplicationKeySerializerModel(application_api_key).data for application_api_key in
57+
QuerySet(ApplicationApiKey).filter(application_id = application_id)]
58+
59+
class Operate(serializers.Serializer):
60+
user_id = serializers.UUIDField(required=True, label=_('user id'))
61+
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
62+
application_id = serializers.UUIDField(required=True, label=_('application id'))
63+
64+
65+
66+
def edit(self, instance, with_valid=True):
67+
if with_valid:
68+
self.is_valid(raise_exception=True)
69+

apps/application/urls.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.urls import path
2+
3+
from . import views
4+
5+
app_name = 'application'
6+
7+
urlpatterns = [
8+
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key', views.ApplicationKey.as_view()),
9+
]

apps/application/views/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
@date:2025/5/9 18:51
77
@desc:
88
"""
9+
from .application_api_key import *
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from drf_spectacular.utils import extend_schema
2+
from rest_framework.request import Request
3+
from rest_framework.views import APIView
4+
from django.utils.translation import gettext_lazy as _
5+
6+
from application.api.application_api_key import ApplicationKeyCreateAPI
7+
from application.serializers.application_api_key import ApplicationKeySerializer
8+
from common.auth import TokenAuth
9+
from common.result import result, success
10+
11+
12+
class ApplicationKey(APIView):
13+
authentication_classes = [TokenAuth]
14+
15+
@extend_schema(
16+
methods=['POST'],
17+
description=_('Create application ApiKey'),
18+
summary=_('Create application ApiKey'),
19+
operation_id=_('Create application ApiKey'), # type: ignore
20+
parameters=ApplicationKeyCreateAPI.get_parameters(),
21+
tags=[_('Application Api Key')] # type: ignore
22+
)
23+
def post(self,request: Request, application_id: str, workspace_id: str):
24+
return result.success(ApplicationKeySerializer(
25+
data={'application_id': application_id, 'user_id': request.user.id,
26+
'workspace_id':workspace_id}).generate())
27+
28+
@extend_schema(
29+
methods=['GET'],
30+
description=_('GET application ApiKey List'),
31+
summary=_('Create application ApiKey List'),
32+
operation_id=_('Create application ApiKey List'), # type: ignore
33+
parameters=ApplicationKeyCreateAPI.get_parameters(),
34+
tags=[_('Application Api Key')] # type: ignore
35+
)
36+
def get(self,request: Request, application_id: str, workspace_id: str):
37+
return result,success(ApplicationKeySerializer(
38+
data={'application_id':application_id, 'user_id':request.user.id,
39+
'workspace_id':workspace_id}).list())
40+
41+
42+
class Operate(APIView):
43+
authentication_classes = [TokenAuth]
44+
45+
@extend_schema(
46+
methods=['GET'],
47+
description=_('GET application ApiKey List'),
48+
summary=_('Create application ApiKey List'),
49+
operation_id=_('Create application ApiKey List'), # type: ignore
50+
parameters=ApplicationKeyCreateAPI.get_parameters(),
51+
tags=[_('Application Api Key')] # type: ignore
52+
)
53+
def put(self, request: Request, application_id: str, workspace_id: str):
54+
return result.success(ApplicationKeySerializer.Operate(
55+
56+
)
57+
)
58+

0 commit comments

Comments
 (0)