-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: application view init #3147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # coding=utf-8 | ||
| """ | ||
| @project: MaxKB | ||
| @Author:虎虎 | ||
| @file: application.py | ||
| @date:2025/5/26 16:59 | ||
| @desc: | ||
| """ | ||
| from django.utils.translation import gettext_lazy as _ | ||
| from drf_spectacular.types import OpenApiTypes | ||
| from drf_spectacular.utils import OpenApiParameter | ||
| from rest_framework import serializers | ||
|
|
||
| from application.serializers.application import ApplicationCreateSerializer | ||
| from common.mixins.api_mixin import APIMixin | ||
|
|
||
|
|
||
| class ApplicationCreateRequest(ApplicationCreateSerializer.SimplateRequest): | ||
| work_flow = serializers.DictField(required=True, label=_("Workflow Objects")) | ||
|
|
||
|
|
||
| class ApplicationCreateAPI(APIMixin): | ||
| @staticmethod | ||
| def get_parameters(): | ||
| return [ | ||
| OpenApiParameter( | ||
| name="workspace_id", | ||
| description="工作空间id", | ||
| type=OpenApiTypes.STR, | ||
| location='path', | ||
| required=True, | ||
| ) | ||
| ] | ||
|
|
||
| @staticmethod | ||
| def get_request(): | ||
| return ApplicationCreateRequest | ||
|
|
||
| @staticmethod | ||
| def get_response(): | ||
| return FolderCreateResponse | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| # coding=utf-8 | ||
| """ | ||
| @project: MaxKB | ||
| @Author:虎虎 | ||
| @file: application.py | ||
| @date:2025/5/26 17:03 | ||
| @desc: | ||
| """ | ||
| import re | ||
| from typing import Dict | ||
|
|
||
| import uuid_utils.compat as uuid | ||
| from django.core import validators | ||
| from django.db import models | ||
| from django.db.models import QuerySet | ||
| from django.utils.translation import gettext_lazy as _ | ||
| from rest_framework import serializers | ||
|
|
||
| from application.models.application import Application, ApplicationTypeChoices | ||
| from common.exception.app_exception import AppApiException | ||
| from knowledge.models import Knowledge | ||
| from models_provider.models import Model | ||
|
|
||
|
|
||
| class NoReferencesChoices(models.TextChoices): | ||
| """订单类型""" | ||
| ai_questioning = 'ai_questioning', 'ai回答' | ||
| designated_answer = 'designated_answer', '指定回答' | ||
|
|
||
|
|
||
| class NoReferencesSetting(serializers.Serializer): | ||
| status = serializers.ChoiceField(required=True, choices=NoReferencesChoices.choices, | ||
| label=_("No reference status")) | ||
| value = serializers.CharField(required=True, label=_("Prompt word")) | ||
|
|
||
|
|
||
| class KnowledgeSettingSerializer(serializers.Serializer): | ||
| top_n = serializers.FloatField(required=True, max_value=10000, min_value=1, | ||
| label=_("Reference segment number")) | ||
| similarity = serializers.FloatField(required=True, max_value=1, min_value=0, | ||
| label=_("Acquaintance")) | ||
| max_paragraph_char_number = serializers.IntegerField(required=True, min_value=500, max_value=100000, | ||
| label=_("Maximum number of quoted characters")) | ||
| search_mode = serializers.CharField(required=True, validators=[ | ||
| validators.RegexValidator(regex=re.compile("^embedding|keywords|blend$"), | ||
| message=_("The type only supports embedding|keywords|blend"), code=500) | ||
| ], label=_("Retrieval Mode")) | ||
|
|
||
| no_references_setting = NoReferencesSetting(required=True, | ||
| label=_("Segment settings not referenced")) | ||
|
|
||
|
|
||
| class ModelKnowledgeAssociation(serializers.Serializer): | ||
| user_id = serializers.UUIDField(required=True, label=_("User ID")) | ||
| model_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, | ||
| label=_("Model id")) | ||
| Knowledge_id_list = serializers.ListSerializer(required=False, child=serializers.UUIDField(required=True, | ||
| label=_( | ||
| "Knowledge base id")), | ||
| label=_("Knowledge Base List")) | ||
|
|
||
| def is_valid(self, *, raise_exception=True): | ||
| super().is_valid(raise_exception=True) | ||
| model_id = self.data.get('model_id') | ||
| user_id = self.data.get('user_id') | ||
| if model_id is not None and len(model_id) > 0: | ||
| if not QuerySet(Model).filter(id=model_id).exists(): | ||
| raise AppApiException(500, f'{_("Model does not exist")}【{model_id}】') | ||
| knowledge_id_list = list(set(self.data.get('knowledge_id_list'))) | ||
| exist_knowledge_id_list = [str(knowledge.id) for knowledge in | ||
| QuerySet(Knowledge).filter(id__in=knowledge_id_list, user_id=user_id)] | ||
| for knowledge_id in knowledge_id_list: | ||
| if not exist_knowledge_id_list.__contains__(knowledge_id): | ||
| raise AppApiException(500, f'{_("The knowledge base id does not exist")}【{knowledge_id}】') | ||
|
|
||
|
|
||
| class ModelSettingSerializer(serializers.Serializer): | ||
| prompt = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=102400, | ||
| label=_("Prompt word")) | ||
| system = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=102400, | ||
| label=_("Role prompts")) | ||
| no_references_prompt = serializers.CharField(required=True, max_length=102400, allow_null=True, allow_blank=True, | ||
| label=_("No citation segmentation prompt")) | ||
| reasoning_content_enable = serializers.BooleanField(required=False, | ||
| label=_("Thinking process switch")) | ||
| reasoning_content_start = serializers.CharField(required=False, allow_null=True, default="<think>", | ||
| allow_blank=True, max_length=256, | ||
| trim_whitespace=False, | ||
| label=_("The thinking process begins to mark")) | ||
| reasoning_content_end = serializers.CharField(required=False, allow_null=True, allow_blank=True, default="</think>", | ||
| max_length=256, | ||
| trim_whitespace=False, | ||
| label=_("End of thinking process marker")) | ||
|
|
||
|
|
||
| class ApplicationCreateSerializer(serializers.Serializer): | ||
| class WorkflowRequest(serializers.Serializer): | ||
| name = serializers.CharField(required=True, max_length=64, min_length=1, | ||
| label=_("Application Name")) | ||
| desc = serializers.CharField(required=False, allow_null=True, allow_blank=True, | ||
| max_length=256, min_length=1, | ||
| label=_("Application Description")) | ||
| work_flow = serializers.DictField(required=True, label=_("Workflow Objects")) | ||
| prologue = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=102400, | ||
| label=_("Opening remarks")) | ||
|
|
||
| @staticmethod | ||
| def to_application_model(user_id: str, application: Dict): | ||
| default_workflow = application.get('work_flow') | ||
| for node in default_workflow.get('nodes'): | ||
| if node.get('id') == 'base-node': | ||
| node.get('properties')['node_data']['desc'] = application.get('desc') | ||
| node.get('properties')['node_data']['name'] = application.get('name') | ||
| node.get('properties')['node_data']['prologue'] = application.get('prologue') | ||
| return Application(id=uuid.uuid7(), | ||
| name=application.get('name'), | ||
| desc=application.get('desc'), | ||
| prologue="", | ||
| dialogue_number=0, | ||
| user_id=user_id, model_id=None, | ||
| knowledge_setting={}, | ||
| model_setting={}, | ||
| problem_optimization=False, | ||
| type=ApplicationTypeChoices.WORK_FLOW, | ||
| stt_model_enable=application.get('stt_model_enable', False), | ||
| stt_model_id=application.get('stt_model', None), | ||
| tts_model_id=application.get('tts_model', None), | ||
| tts_model_enable=application.get('tts_model_enable', False), | ||
| tts_model_params_setting=application.get('tts_model_params_setting', {}), | ||
| tts_type=application.get('tts_type', None), | ||
| file_upload_enable=application.get('file_upload_enable', False), | ||
| file_upload_setting=application.get('file_upload_setting', {}), | ||
| work_flow=default_workflow | ||
| ) | ||
|
|
||
| class SimplateRequest(serializers.Serializer): | ||
| name = serializers.CharField(required=True, max_length=64, min_length=1, | ||
| label=_("application name")) | ||
| desc = serializers.CharField(required=False, allow_null=True, allow_blank=True, | ||
| max_length=256, min_length=1, | ||
| label=_("application describe")) | ||
| model_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, | ||
| label=_("Model")) | ||
| dialogue_number = serializers.IntegerField(required=True, | ||
| min_value=0, | ||
| max_value=1024, | ||
| label=_("Historical chat records")) | ||
| prologue = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=102400, | ||
| label=_("Opening remarks")) | ||
| knowledge_id_list = serializers.ListSerializer(required=False, child=serializers.UUIDField(required=True), | ||
| allow_null=True, | ||
| label=_("Related Knowledge Base")) | ||
| # 数据集相关设置 | ||
| knowledge_setting = KnowledgeSettingSerializer(required=True) | ||
| # 模型相关设置 | ||
| model_setting = ModelSettingSerializer(required=True) | ||
| # 问题补全 | ||
| problem_optimization = serializers.BooleanField(required=True, | ||
| label=_("Question completion")) | ||
| problem_optimization_prompt = serializers.CharField(required=False, max_length=102400, | ||
| label=_("Question completion prompt")) | ||
| # 应用类型 | ||
| type = serializers.CharField(required=True, label=_("Application Type"), | ||
| validators=[ | ||
| validators.RegexValidator(regex=re.compile("^SIMPLE|WORK_FLOW$"), | ||
| message=_( | ||
| "Application type only supports SIMPLE|WORK_FLOW"), | ||
| code=500) | ||
| ] | ||
| ) | ||
| model_params_setting = serializers.DictField(required=False, | ||
| label=_('Model parameters')) | ||
|
|
||
| def is_valid(self, *, user_id=None, raise_exception=False): | ||
| super().is_valid(raise_exception=True) | ||
| ModelKnowledgeAssociation(data={'user_id': user_id, 'model_id': self.data.get('model_id'), | ||
| 'knowledge_id_list': self.data.get('knowledge_id_list')}).is_valid() | ||
|
|
||
|
|
||
| class ApplicationSerializer(serializers.Serializer): | ||
| def insert(self): | ||
| pass |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # coding=utf-8 | ||
| """ | ||
| @project: MaxKB | ||
| @Author:虎虎 | ||
| @file: application.py | ||
| @date:2025/5/26 16:51 | ||
| @desc: | ||
| """ | ||
| from django.utils.translation import gettext_lazy as _ | ||
| from drf_spectacular.utils import extend_schema | ||
| from rest_framework.request import Request | ||
| from rest_framework.views import APIView | ||
|
|
||
| from application.api.application_api import ApplicationCreateAPI | ||
| from application.serializers.application import ApplicationSerializer | ||
| from common import result | ||
|
|
||
|
|
||
| class Application(APIView): | ||
|
|
||
| @extend_schema( | ||
| methods=['POST'], | ||
| description=_('Create an application'), | ||
| summary=_('Create an application'), | ||
| operation_id=_('Create an application'), # type: ignore | ||
| parameters=ApplicationCreateAPI.get_parameters(), | ||
| request=ApplicationCreateAPI.get_request(), | ||
| responses=ApplicationCreateAPI.get_response(), | ||
| tags=[_('Application')] # type: ignore | ||
| ) | ||
| def post(self, request: Request): | ||
| return result.success(ApplicationSerializer.insert(request.data)) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided code is syntactically correct, but there are a few areas that can be improved for clarity and maintainability:
Here's a revised version of the code incorporating these suggestions: # coding=utf-8
"""
@project: MaxKB
@author:虎虎
@file:application.py
@date:2025/5/26 16:51
@desc:
"""
import json
from django.http import JsonResponse
from rest_framework.parsers import JSONParser
from drf_spectacular.utils import extend_schema
from rest_framework.views import APIView
from application.api.application_api import ApplicationCreateAPI
from application.serializers.application import ApplicationSerializer
@appenddocstring("This endpoint creates a new application using the specified serializer.")
class CreateApplicationAPIView(APIView):
@extend_schema(
methods=['POST'],
description=_("Create an application"),
summary=_("Create an application"),
operation_id="create_application", # type: ignore
parameters=ApplicationCreateAPI.get_params(),
request=json.dumps(ApplicationCreateAPI.get_post_data(), ensure_ascii=False),
responses={201: {'description': 'Application created successfully', 'content': {'application/json': {}}},
400: {'description': 'Bad Request', 'content': {'application/json': {}}},
500: {'description': 'Server Error', 'content': {'application/json': {}}}},
tags=["Application"] # type: ignore
)
def post(self, request):
serializer = ApplicationSerializer(data=request.data)
if serializer.is_valid():
response_content = serializer.validated_data
return JsonResponse({'message': "Application created successfully"}, status=201)
else:
return jsonResponse(serializer.errors, status=400)Key Improvements Made:
These changes make the code cleaner, easier to understand, and prepare it for future development and maintenance. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,7 +44,8 @@ | |
| 'common', | ||
| 'system_manage', | ||
| 'models_provider', | ||
| 'django_celery_beat' | ||
| 'django_celery_beat', | ||
| 'application' | ||
| ] | ||
|
|
||
| MIDDLEWARE = [ | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code provided looks mostly straightforward and follows typical Django project structure practices. However, there is one potential issue that could be addressed:
Here's an optimized version of the code with these considerations considered: ## common,
## system_manage/,
## models_provider,
## django_celery_beat,
+django.middleware.security.SecurityMiddleware,
+django.contrib.sessions.middleware.SessionMiddleware,
+django.middleware.common.CommonMiddleware,
+django.middleware.csrf.CsrfViewMiddleware,
+django.contrib.auth.middleware.AuthenticationMiddleware,
## models_provider/
# This will handle static files served during development (e.g., media)
if settings.DEBUG:
MIDDLEWARE.append('whitenoise.middleware.WhiteNoiseMiddleware')
else:
# Production should use secure content delivery network (CDN) instead
passExplanation:
These additions provide a more comprehensive set of middlewares for your Django app, ensuring it handles basic security measures effectively while still allowing flexibility depending on deployment environments. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided Python code snippet appears to be a part of a Django project that utilizes DRF (Django REST Framework) along with Spectacular for generating Swagger/OpenAPI documentation. The code defines an API endpoint for creating applications within a workspace structure.
Here's a checklist with some suggestions and potential improvements:
Imports: Ensure all necessary modules are imported at the top. This includes
gettext_lazy,OpenApiTypes,OpenApiParameter, `rest_framework', 'app.serializers.application.ApplicationCreateSerializer', and 'common.mixins.api_mixin.APIMixin'.Class Names: Class names like
ApplicationCreateResponseshould match what is defined inFolderCreateResponse. If not, update them accordingly.Method Naming: Method names like
get_parameters,get_request, andget_responsefollow standard conventions. Adjust if needed based on your specific requirements.Docstrings: Update docstrings to reflect changes in method parameters and functionality where applicable.
Type Annotations: Use type annotations as much as possible to improve clarity and maintainability.
Example Improvements
In this example:
DefaultRouterfrom DRF is used to simplify URL configuration.ApplicationCreateViewclass can be created to handle GET requests which might include additional logic around parameter fetching or response formatting.patterns.This approach provides a clean separation of concerns between route definition and view logic, making it easier to manage the API endpoints and extend them later if necessary.