Skip to content

Commit a90f6c8

Browse files
committed
refactor: email setting
1 parent a09d0d5 commit a90f6c8

File tree

10 files changed

+324
-7
lines changed

10 files changed

+324
-7
lines changed

apps/common/constants/permission_constants.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,23 +217,28 @@ class PermissionConstants(Enum):
217217
KNOWLEDGE_CREATE = Permission(group=Group.KNOWLEDGE, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN,
218218
RoleConstants.USER])
219219
KNOWLEDGE_EDIT = Permission(group=Group.KNOWLEDGE, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN,
220-
RoleConstants.USER])
220+
RoleConstants.USER])
221221
KNOWLEDGE_DELETE = Permission(group=Group.KNOWLEDGE, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
222222
RoleConstants.USER])
223223
DOCUMENT_READ = Permission(group=Group.KNOWLEDGE, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
224-
RoleConstants.USER])
224+
RoleConstants.USER])
225225
DOCUMENT_CREATE = Permission(group=Group.KNOWLEDGE, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
226-
RoleConstants.USER])
226+
RoleConstants.USER])
227227
DOCUMENT_EDIT = Permission(group=Group.KNOWLEDGE, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
228-
RoleConstants.USER])
228+
RoleConstants.USER])
229229
DOCUMENT_DELETE = Permission(group=Group.KNOWLEDGE, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN,
230-
RoleConstants.USER])
230+
RoleConstants.USER])
231231

232232
WORKSPACE_USER_RESOURCE_PERMISSION_READ = Permission(group=Group.WORKSPACE_USER_RESOURCE_PERMISSION,
233233
operate=Operate.READ,
234234
role_list=[RoleConstants.ADMIN,
235235
RoleConstants.WORKSPACE_MANAGE])
236236

237+
EMAIL_SETTING_READ = Permission(group=Group.USER, operate=Operate.READ,
238+
role_list=[RoleConstants.ADMIN])
239+
EMAIL_SETTING_EDIT = Permission(group=Group.USER, operate=Operate.EDIT,
240+
role_list=[RoleConstants.ADMIN])
241+
237242
def get_workspace_application_permission(self):
238243
return lambda r, kwargs: Permission(group=self.value.group, operate=self.value.operate,
239244
resource_path=
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: model_apply_serializers.py
6+
@date:2024/8/20 20:39
7+
@desc:
8+
"""
9+
from django.db import connection
10+
from django.db.models import QuerySet
11+
from langchain_core.documents import Document
12+
from rest_framework import serializers
13+
14+
from common.config.embedding_config import ModelManage
15+
from django.utils.translation import gettext_lazy as _
16+
17+
from models_provider.models import Model
18+
from models_provider.tools import get_model
19+
20+
21+
def get_embedding_model(model_id):
22+
model = QuerySet(Model).filter(id=model_id).first()
23+
# 手动关闭数据库连接
24+
connection.close()
25+
embedding_model = ModelManage.get_model(model_id,
26+
lambda _id: get_model(model, use_local=True))
27+
return embedding_model
28+
29+
30+
class EmbedDocuments(serializers.Serializer):
31+
texts = serializers.ListField(required=True, child=serializers.CharField(required=True,
32+
label=_('vector text')),
33+
label=_('vector text list')),
34+
35+
36+
class EmbedQuery(serializers.Serializer):
37+
text = serializers.CharField(required=True, label=_('vector text'))
38+
39+
40+
class CompressDocument(serializers.Serializer):
41+
page_content = serializers.CharField(required=True, label=_('text'))
42+
metadata = serializers.DictField(required=False, label=_('metadata'))
43+
44+
45+
class CompressDocuments(serializers.Serializer):
46+
documents = CompressDocument(required=True, many=True)
47+
query = serializers.CharField(required=True, label=_('query'))
48+
49+
50+
class ModelApplySerializers(serializers.Serializer):
51+
model_id = serializers.UUIDField(required=True, label=_('model id'))
52+
53+
def embed_documents(self, instance, with_valid=True):
54+
if with_valid:
55+
self.is_valid(raise_exception=True)
56+
EmbedDocuments(data=instance).is_valid(raise_exception=True)
57+
58+
model = get_embedding_model(self.data.get('model_id'))
59+
return model.embed_documents(instance.getlist('texts'))
60+
61+
def embed_query(self, instance, with_valid=True):
62+
if with_valid:
63+
self.is_valid(raise_exception=True)
64+
EmbedQuery(data=instance).is_valid(raise_exception=True)
65+
66+
model = get_embedding_model(self.data.get('model_id'))
67+
return model.embed_query(instance.get('text'))
68+
69+
def compress_documents(self, instance, with_valid=True):
70+
if with_valid:
71+
self.is_valid(raise_exception=True)
72+
CompressDocuments(data=instance).is_valid(raise_exception=True)
73+
model = get_embedding_model(self.data.get('model_id'))
74+
return [{'page_content': d.page_content, 'metadata': d.metadata} for d in model.compress_documents(
75+
[Document(page_content=document.get('page_content'), metadata=document.get('metadata')) for document in
76+
instance.get('documents')], instance.get('query'))]

apps/models_provider/urls.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from django.urls import path
24

35
from . import views
@@ -15,3 +17,10 @@
1517
path('workspace/<str:workspace_id>/model/<str:model_id>/pause_download', views.Model.PauseDownload.as_view()),
1618
path('workspace/<str:workspace_id>/model/<str:model_id>/meta', views.Model.ModelMeta.as_view()),
1719
]
20+
21+
if os.environ.get('SERVER_NAME', 'web') == 'local_model':
22+
urlpatterns += [
23+
path('workspace/<str:workspace_id>/model/<str:model_id>/embed_documents', views.ModelApply.EmbedDocuments.as_view()),
24+
path('workspace/<str:workspace_id>model/<str:model_id>/embed_query', views.ModelApply.EmbedQuery.as_view()),
25+
path('workspace/<str:workspace_id>model/<str:model_id>/compress_documents', views.ModelApply.CompressDocuments.as_view()),
26+
]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# coding=utf-8
22

33
from .model import *
4-
from .provide import *
4+
from .provide import *
5+
from .model_apply import *
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: model_apply.py
6+
@date:2024/8/20 20:38
7+
@desc:
8+
"""
9+
from urllib.request import Request
10+
11+
from django.utils.translation import gettext_lazy as _
12+
from drf_spectacular.utils import extend_schema
13+
from rest_framework.views import APIView
14+
15+
from common.auth.authentication import has_permissions
16+
from common.constants.permission_constants import PermissionConstants
17+
from common.result import result
18+
from models_provider.api.model import DefaultModelResponse
19+
from models_provider.serializers.model_apply_serializers import ModelApplySerializers
20+
21+
22+
class ModelApply(APIView):
23+
class EmbedDocuments(APIView):
24+
@extend_schema(methods=['POST'],
25+
summary=_('Vectorization documentation'),
26+
description=_('Vectorization documentation'),
27+
operation_id=_('Vectorization documentation'),
28+
responses=DefaultModelResponse.get_response(),
29+
tags=[_('Model')]
30+
)
31+
@has_permissions(PermissionConstants.MODEL_READ.get_workspace_permission())
32+
def post(self, request: Request, workspace_id, model_id):
33+
return result.success(
34+
ModelApplySerializers(data={'model_id': model_id}).embed_documents(request.data))
35+
36+
class EmbedQuery(APIView):
37+
@extend_schema(methods=['POST'],
38+
summary=_('Vectorization documentation'),
39+
description=_('Vectorization documentation'),
40+
operation_id=_('Vectorization documentation'),
41+
responses=DefaultModelResponse.get_response(),
42+
tags=[_('Model')]
43+
)
44+
@has_permissions(PermissionConstants.MODEL_READ.get_workspace_permission())
45+
def post(self, request: Request, workspace_id, model_id):
46+
return result.success(
47+
ModelApplySerializers(data={'model_id': model_id}).embed_query(request.data))
48+
49+
class CompressDocuments(APIView):
50+
@extend_schema(methods=['POST'],
51+
summary=_('Reorder documents'),
52+
description=_('Reorder documents'),
53+
operation_id=_('Reorder documents'),
54+
responses=DefaultModelResponse.get_response(),
55+
tags=[_('Model')]
56+
)
57+
@has_permissions(PermissionConstants.MODEL_READ.get_workspace_permission())
58+
def post(self, request: Request, workspace_id, model_id):
59+
return result.success(
60+
ModelApplySerializers(data={'model_id': model_id}).compress_documents(request.data))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎虎
5+
@file: workspace_user_resource_permission.py
6+
@date:2025/4/28 18:13
7+
@desc:
8+
"""
9+
from drf_spectacular.types import OpenApiTypes
10+
from drf_spectacular.utils import OpenApiParameter
11+
12+
from common.mixins.api_mixin import APIMixin
13+
from common.result import ResultSerializer
14+
from system_manage.serializers.email_setting import EmailSettingSerializer
15+
from system_manage.serializers.user_resource_permission import UserResourcePermissionResponse, \
16+
UpdateUserResourcePermissionRequest
17+
18+
19+
class EmailResponse(ResultSerializer):
20+
def get_data(self):
21+
return EmailSettingSerializer.Create()
22+
23+
24+
class EmailSettingAPI(APIMixin):
25+
@staticmethod
26+
def get_request():
27+
return EmailSettingSerializer.Create()
28+
29+
@staticmethod
30+
def get_response():
31+
return EmailResponse
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# coding=utf-8
2+
"""
3+
@project: maxkb
4+
@Author:虎
5+
@file: system_setting.py
6+
@date:2024/3/19 16:29
7+
@desc:
8+
"""
9+
from django.core.mail.backends.smtp import EmailBackend
10+
from django.db.models import QuerySet
11+
from rest_framework import serializers
12+
13+
from common.exception.app_exception import AppApiException
14+
from django.utils.translation import gettext_lazy as _
15+
16+
from system_manage.models import SystemSetting, SettingType
17+
18+
19+
class EmailSettingSerializer(serializers.Serializer):
20+
@staticmethod
21+
def one():
22+
system_setting = QuerySet(SystemSetting).filter(type=SettingType.EMAIL.value).first()
23+
if system_setting is None:
24+
return {}
25+
return system_setting.meta
26+
27+
class Create(serializers.Serializer):
28+
email_host = serializers.CharField(required=True, label=_('SMTP host'))
29+
email_port = serializers.IntegerField(required=True, label=_('SMTP port'))
30+
email_host_user = serializers.CharField(required=True, label=_('Sender\'s email'))
31+
email_host_password = serializers.CharField(required=True, label=_('Password'))
32+
email_use_tls = serializers.BooleanField(required=True, label=_('Whether to enable TLS'))
33+
email_use_ssl = serializers.BooleanField(required=True, label=_('Whether to enable SSL'))
34+
from_email = serializers.EmailField(required=True, label=_('Sender\'s email'))
35+
36+
def is_valid(self, *, raise_exception=False):
37+
super().is_valid(raise_exception=True)
38+
try:
39+
EmailBackend(self.data.get("email_host"),
40+
self.data.get("email_port"),
41+
self.data.get("email_host_user"),
42+
self.data.get("email_host_password"),
43+
self.data.get("email_use_tls"),
44+
False,
45+
self.data.get("email_use_ssl")
46+
).open()
47+
except Exception as e:
48+
print(e)
49+
raise AppApiException(1004, _('Email verification failed'))
50+
51+
def update_or_save(self):
52+
self.is_valid(raise_exception=True)
53+
system_setting = QuerySet(SystemSetting).filter(type=SettingType.EMAIL.value).first()
54+
if system_setting is None:
55+
system_setting = SystemSetting(type=SettingType.EMAIL.value)
56+
system_setting.meta = self.to_email_meta()
57+
system_setting.save()
58+
return system_setting.meta
59+
60+
def to_email_meta(self):
61+
return {'email_host': self.data.get('email_host'),
62+
'email_port': self.data.get('email_port'),
63+
'email_host_user': self.data.get('email_host_user'),
64+
'email_host_password': self.data.get('email_host_password'),
65+
'email_use_tls': self.data.get('email_use_tls'),
66+
'email_use_ssl': self.data.get('email_use_ssl'),
67+
'from_email': self.data.get('from_email')
68+
}

apps/system_manage/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44

55
app_name = "system_manage"
66
urlpatterns = [
7-
path('workspace/<str:workspace_id>/user_resource_permission', views.WorkSpaceUserResourcePermissionView.as_view())
7+
path('workspace/<str:workspace_id>/user_resource_permission', views.WorkSpaceUserResourcePermissionView.as_view()),
8+
path('email_setting', views.SystemSetting.Email.as_view()),
89
]

apps/system_manage/views/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
@desc:
88
"""
99
from .user_resource_permission import *
10+
from .email_setting import *
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# coding=utf-8
2+
"""
3+
@project: maxkb
4+
@Author:虎
5+
@file: system_setting.py
6+
@date:2024/3/19 16:01
7+
@desc:
8+
"""
9+
from drf_spectacular.utils import extend_schema
10+
from rest_framework.request import Request
11+
from rest_framework.views import APIView
12+
13+
from common.auth import TokenAuth
14+
from common.auth.authentication import has_permissions
15+
from common.constants.permission_constants import PermissionConstants
16+
17+
from django.utils.translation import gettext_lazy as _
18+
19+
from common.result import result
20+
from models_provider.api.model import DefaultModelResponse
21+
from system_manage.api.email_setting import EmailSettingAPI
22+
from system_manage.serializers.email_setting import EmailSettingSerializer
23+
24+
25+
class SystemSetting(APIView):
26+
class Email(APIView):
27+
authentication_classes = [TokenAuth]
28+
29+
@extend_schema(methods=['PUT'],
30+
summary=_('Create or update email settings'),
31+
description=_('Create or update email settings'),
32+
operation_id=_('Create or update email settings'),
33+
request=EmailSettingAPI.get_request(),
34+
responses=EmailSettingAPI.get_response(),
35+
tags=[_('Email settings')])
36+
@has_permissions(PermissionConstants.EMAIL_SETTING_EDIT)
37+
def put(self, request: Request):
38+
return result.success(
39+
EmailSettingSerializer.Create(
40+
data=request.data).update_or_save())
41+
42+
@extend_schema(
43+
methods=['POST'],
44+
summary=_('Test email settings'),
45+
operation_id=_('Test email settings'),
46+
request=EmailSettingAPI.get_request(),
47+
responses=DefaultModelResponse.get_response(),
48+
tags=[_('Email settings')]
49+
)
50+
@has_permissions(PermissionConstants.EMAIL_SETTING_EDIT)
51+
def post(self, request: Request):
52+
return result.success(
53+
EmailSettingSerializer.Create(
54+
data=request.data).is_valid())
55+
56+
@extend_schema(methods=['GET'],
57+
summary=_('Get email settings'),
58+
description=_('Get email settings'),
59+
operation_id=_('Get email settings'),
60+
responses=DefaultModelResponse.get_response(),
61+
tags=[_('Email settings')])
62+
@has_permissions(PermissionConstants.EMAIL_SETTING_READ)
63+
def get(self, request: Request):
64+
return result.success(
65+
EmailSettingSerializer.one())

0 commit comments

Comments
 (0)