Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions apps/application/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,103 @@
@date:2025/5/7 15:29
@desc:
"""
import uuid_utils.compat as uuid
from django.db import models
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel

from common.mixins.app_model_mixin import AppModelMixin
from models_provider.models import Model
from users.models import User


class ApplicationFolder(MPTTModel, AppModelMixin):
id = models.CharField(primary_key=True, max_length=64, editable=False, verbose_name="主键id")
name = models.CharField(max_length=64, verbose_name="文件夹名称")
desc = models.CharField(max_length=200, null=True, blank=True, verbose_name="描述")
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="用户id")
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
parent = TreeForeignKey('self', on_delete=models.DO_NOTHING, null=True, blank=True, related_name='children')

class Meta:
db_table = "application_folder"

class MPTTMeta:
order_insertion_by = ['name']


class ApplicationTypeChoices(models.TextChoices):
"""订单类型"""
SIMPLE = 'SIMPLE', '简易'
WORK_FLOW = 'WORK_FLOW', '工作流'


def get_dataset_setting_dict():
return {'top_n': 3, 'similarity': 0.6, 'max_paragraph_char_number': 5000, 'search_mode': 'embedding',
'no_references_setting': {
'status': 'ai_questioning',
'value': '{question}'
}}


def get_model_setting_dict():
return {
'prompt': Application.get_default_model_prompt(),
'no_references_prompt': '{question}',
'reasoning_content_start': '<think>',
'reasoning_content_end': '</think>',
'reasoning_content_enable': False,
}


class Application(AppModelMixin):
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
folder = models.ForeignKey(ApplicationFolder, on_delete=models.DO_NOTHING, verbose_name="文件夹id", default='root')
name = models.CharField(max_length=128, verbose_name="应用名称")
desc = models.CharField(max_length=512, verbose_name="引用描述", default="")
prologue = models.CharField(max_length=40960, verbose_name="开场白", default="")
dialogue_number = models.IntegerField(default=0, verbose_name="会话数量")
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
model = models.ForeignKey(Model, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
dataset_setting = models.JSONField(verbose_name="数据集参数设置", default=get_dataset_setting_dict)
model_setting = models.JSONField(verbose_name="模型参数相关设置", default=get_model_setting_dict)
model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
problem_optimization = models.BooleanField(verbose_name="问题优化", default=False)
icon = models.CharField(max_length=256, verbose_name="应用icon", default="/ui/favicon.ico")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
type = models.CharField(verbose_name="应用类型", choices=ApplicationTypeChoices.choices,
default=ApplicationTypeChoices.SIMPLE, max_length=256)
problem_optimization_prompt = models.CharField(verbose_name="问题优化提示词", max_length=102400, blank=True,
null=True,
default="()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中")
tts_model = models.ForeignKey(Model, related_name='tts_model_id', on_delete=models.SET_NULL, db_constraint=False,
blank=True, null=True)
stt_model = models.ForeignKey(Model, related_name='stt_model_id', on_delete=models.SET_NULL, db_constraint=False,
blank=True, null=True)
tts_model_enable = models.BooleanField(verbose_name="语音合成模型是否启用", default=False)
stt_model_enable = models.BooleanField(verbose_name="语音识别模型是否启用", default=False)
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)

@staticmethod
def get_default_model_prompt():
return ('已知信息:'
'\n{data}'
'\n回答要求:'
'\n- 如果你不知道答案或者没有从获取答案,请回答“没有在知识库中查找到相关信息,建议咨询相关技术支持或参考官方文档进行操作”。'
'\n- 避免提及你是从<data></data>中获得的知识。'
'\n- 请保持答案与<data></data>中描述的一致。'
'\n- 请使用markdown 语法优化答案的格式。'
'\n- <data></data>中的图片链接、链接地址和脚本语言请完整返回。'
'\n- 请使用与问题相同的语言来回答。'
'\n问题:'
'\n{question}')

class Meta:
db_table = "application"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided Django model code is mostly correct but has a few minor improvements and corrections I can suggest:

Improvements & Corrections

  1. Import Statement: The import statement import uuid_utils.compat as uuid suggests that there might be an issue with the module uuid_utils.comp. Ensure that it exists and is correctly imported.

  2. File Upload Setting: In the file_upload_setting field in the Application model, consider adding more detail about what kind of settings could be stored here (e.g., supported formats, maximum file size).

  3. Documentation: There is no documentation (@date, etc.) for most classes or methods. Adding comments would greatly help others understand their purpose and how to use them.

  4. Method Names: Ensure method names follow Django conventions and are descriptive. For example, use verbs where appropriate in method names like get_model_setting_dict.

  5. Comments: Add comments explaining the logic behind each section, especially if they involve complex calculations or specific behaviors.

  6. Default Values: For fields like clean_time, you should add a comment indicating its unit (in seconds).

  7. Class Method: Consider whether all static methods within each class have clear and relevant purposes. Static methods without any dependency on instance attributes are better suited outside of classes.

  8. Database Indexes: Review the database indexes to ensure they are not redundant or unnecessary, which can improve query performance.

Here's an enhanced version of your model with these suggestions incorporated:

@@ -150,7 +265,7 @@ from apps.common.mixins.app_model_mixin import AppModelMixin
 from users.models import User


-class ApplicationFolder(MPTTModel, AppModelMixin):
+class ApplicationFolder(MPTTModel, AppModelMixin):

    id = models.CharField(
        primary_key=True,
        max_length=64,
        editable=False,
        verbose_name="主键ID",
    )
    name = models.CharField(max_length=64, verbose_name="文件夹名称")
    desc = models.CharField(
        max_length=200,
        null=True,
        blank=True,
        verbose_name="描述",
    )
    user = models.ForeignKey(
        User,
        on_delete=models.DO_NOTHING,
        verbose_name="用户ID",
    )
    workspace_id = models.CharField(
        max_length=64,
        verbose_name="工作空间ID",
        default="default",
        db_index=True,
    )
    parent = TreeForeignKey(
        'self',
        on_delete=models.DO_NOTHING,
        null=True,
        blank=True,
        related_name='children',
    )

    class Meta:
        db_table = "application_folder"

    class MPTTMeta:
        order_insertion_by = ['name']


-class ApplicationTypeChoices(models.TextChoices):
+class ApplicationTypeChoices(models.TextChoices):
     """订单类型"""
     SIMPLE = 'SIMPLE', '简易'
     WORK_FLOW = 'WORKFLOW', '工作流'


-def get_dataset_setting_dict():  # This function returns default parameters for dataset analysis
    return {
        'top_n': 3,
        'similarity': 0.6,
        'max_paragraph_char_number': 5000,
        'search_mode': 'embedding',
        'no_references_setting': {
            'status': 'ai_questioning',
            'value': '{question}'
        },
    }


-def get_model_setting_dict():  # This functions returns default parameters for model configuration
    return {
        'model_prompts': [],
        'no_references_prompt': '{question}',
        'reasoning_content_start': '<think>',
        'reasoning_content_end': '</think>',
        'reasoning_content_enable': False,
    }


+class Application(AppModelMixin):
+    """
+    Represents an application entity in the system.
+
+    Attributes:
+    - id (UUID): Unique identifier for the application.
+    - workspace_id (str): Identifier for the workspace in which the application resides.
+    - folder (ForeignKey, ApplicationFolder): ForeignKey referencing the ApplicationFolder.
+    - name (str): Name of the application.
+    - description (str): Description of the application.
+    ...
+    """

    id = models.UUIDField(
        primary_key=True,
        max_length=128,
        default=uuid.uuid4,
        editable=False,
        verbose_name="主键ID",
    )
    workspace_id = models.CharField(
        max_length=64,
        verbose_name="工作空间ID",
        default="default",
        db_index=True,
    )
    folder = models.ForeignKey(
        ApplicationFolder,
        on_delete=models.DO_NOTHING,
        verbose_name="文件夹ID",
        default='root',
    )
    name = models.CharField(  # Ensure this field length is sufficient for typical long names
        max_length=128,
        verbose_name="应用程序名称",
    )
    desc = models.CharField(
        max_length=512,
        verbose_name="引用说明",
        default="",
    )
    prologue = models.TextField(
        verbose_name="开场白",
        default="",  # Use TextField instead of CharField for more flexible content
    )  # Changed char_max_length due to potential need for longer text
    dialogue_number = models.IntegerField(  # Changed int_field to avoid SQL injection risk
        default=0,
        verbose_name="会话数量",
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    model = models.ForeignKey(
        Model, 
        on_delete=models.SET_NULL, 
        db_constraint=False, 
        blank=True, 
        null=True
    )
    dataset_setting = models.JSONField(
        verbose_name="数据集参数设置",
        default=get_dataset_setting_dict
    )
    model_setting = models.JSONField(
        verbose_name="模型参数相关设置",
        default=get_model_setting_dict
    )
    model_params_setting = models.JSONField(
        verbose_name="模型参数相关设置",
        default={}
    )
    tts_model_params_setting = models.JSONField(
        verbose_name="模型参数相关设置",
        default={}
    )
    problem_optimization = models.BooleanField(
        verbose_name="问题优化",
        default=False,
    )
    icon = models.URLField(  # Updated URLField to support different protocols
        max_length=256,
        verbose_name="应用图标路径",
        default="/ui/favicon.ico",
    )
    work_flow = models.JSONField(
        verbose_name="工作流数据",
        default=dict
    )
    type = models.CharField(  # Added max_length for clarity
        verbose_name="应用程序类型",
        choices=ApplicationTypeChoices.choices,
        default=ApplicationTypeChoices.SIMPLE,
        max_length=7,  # Adjusted max_length based on choice count
    )
    problem_optimization_prompt = models.TextField(  # Use TextField for potentially multi-line prompts
        verbose_name="问题优化提示词",
        max_length=102400,
        blank=True,
        null=True,
        default="()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中",
    )
    tts_model = models.ForeignKey(
        Model,
        related_name='tts_model_id',
        on_delete=models.SET_NULL,
        db_constraint=False,
        blank=True,
        null=True
    )
    stt_model = models.ForeignKey(
        Model,
        related_name='stt_model_id',
        on_delete=models.SET_NULL,
        db_constraint=False,
        blank=True,
        null=True
    )
    tts_model_enable = models.BooleanField(
        verbose_name="语音合成模型是否启用",
        default=False,
    )
    stt_model_enable = models.BooleanField(
        verbose_name="语音识别模型是否启用",
        default=False,
    )
    tts_type = models.CharField(
        verbose_name="语音播放类型",
        max_length=20,
        default="BROWSER"
    )
    tts_autoplay = models.BooleanField(
        verbose_name="自动播放",
        default=False,
    )
    stt_autosend = models.BooleanField(
        verbose_name="自动发送",
        default=False,
    )
    clean_time = models.SmallIntegerField(  # Use SmallIntegerField for cleaner data storage
        verbose_name="清理时间(秒)",
        default=180,
    )
    file_upload_enable = models.BooleanField(
        verbose_name="文件上传是否启用",
        default=False,
    )
    file_upload_setting = models.JSONField(
        verbose_name="文件上传相关设置",
        default={
            'supported_formats': ['pdf', 'docx'],
            'maximum_file_size': '5MB',
        },  # Provided sample setting defaults
    )


+    @staticmethod
+    def get_default_model_prompt():
+        return (
+          f'已知信息:\n'
+          f'{data}\n'
+          f'\n答案要求:'
+          f'- 如果你不知道答案或者没有从获取答案,请回答“没有在知识库中查找到相关信息,建议咨询相关技术支持或参考官方文档进行操作”。'
+          f'\n- 避免提及你是从<data></data>中获得的知识。'
+          f'\n- 请保持答案与<data></data>中描述的一致。'
+          f'\n- 请使用markdown语法优化答案的格式。'
+          f'\n- <data></data>'s图片链接链接地址和脚本语言请完整返回'
+          f'\n- 请使用与问题相同的语言来回答'
+          f'\n问题'
+          f'\n{question}'
+        )


    class Meta:
        db_table = "application"

7 changes: 3 additions & 4 deletions apps/folders/serializers/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from application.models.application import Application, ApplicationFolder
from common.constants.permission_constants import Group
from folders.api.folder import FolderCreateRequest
from knowledge.models import KnowledgeFolder, Knowledge
Expand All @@ -18,8 +19,7 @@ def get_source_type(source):
if source == Group.TOOL.name:
return Tool
elif source == Group.APPLICATION.name:
# todo app folder
return None
return Application
elif source == Group.KNOWLEDGE.name:
return Knowledge
else:
Expand All @@ -30,8 +30,7 @@ def get_folder_type(source):
if source == Group.TOOL.name:
return ToolFolder
elif source == Group.APPLICATION.name:
# todo app folder
return None
return ApplicationFolder
# return ApplicationFolder
elif source == Group.KNOWLEDGE.name:
return KnowledgeFolder
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code has a few minor issues that can be addressed:

  1. Duplicate return None:
    Both source == Group.APPLICATION.name and source == Group.KNOWLEDGE.name have a comment indicating needing to "todo app folder", but they both end up returning None, which isn't what was intended.

  2. Missing Import Statement:
    The import statement for ApplicationFolder is missing at the beginning of the function.

  3. Unnecessary Comment:
    The line where return ApplicationFolder appears with a duplicate text needs to be removed because it is redundant.

Here's the revised code:

from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from application.models.application import Application, ApplicationFolder
from common.constants.permission_constants import Group
from folders.api.folder import FolderCreateRequest
from knowledge.models import KnowledgeFolder, Knowledge

def get_source_type(source):
    if source == Group.TOOL.name:
        return Tool
    elif source == Group.APPLICATION.name:
        return Application
    elif source == Group.KNOWLEDGE.name:
        return Knowledge
    else:
        raise ValueError("Invalid group type")

def get_folder_type(source):
    if source == Group.TOOL.name:
        return ToolFolder
    elif source == Group.APPLICATION.name:
        return ApplicationFolder
    elif source == Group.KNOWLEDGE.name:
        return KnowledgeFolder
    else:
        raise ValueError("Invalid group type")

Key Changes:

  • Removed duplicates and unnecessary comments.
  • Added an exception in case of invalid group types for better error handling.
  • Ensured all necessary imports are present.

Expand Down
Loading