From 6cf05435bfda8932b43334fb419d74e33db15742 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 14 Dec 2023 10:38:55 +0800 Subject: [PATCH] feat: chat prompt --- apps/settings/api/chat.py | 42 ++++- apps/settings/migrations/0011_chatprompt.py | 31 +++ apps/settings/models.py | 13 ++ apps/settings/prompt.py | 197 ++++++++++++++++++++ apps/settings/serializers/__init__.py | 1 + apps/settings/serializers/prompt.py | 11 ++ apps/settings/urls/api_urls.py | 5 + 7 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 apps/settings/migrations/0011_chatprompt.py create mode 100644 apps/settings/prompt.py create mode 100644 apps/settings/serializers/prompt.py diff --git a/apps/settings/api/chat.py b/apps/settings/api/chat.py index a2601fbad..830ab45ea 100644 --- a/apps/settings/api/chat.py +++ b/apps/settings/api/chat.py @@ -4,9 +4,13 @@ from django.conf import settings from django.utils.translation import gettext_lazy as _ from rest_framework import status from rest_framework.generics import GenericAPIView -from rest_framework.views import Response +from rest_framework.response import Response +from common.api import JMSModelViewSet +from common.permissions import IsValidUser, OnlySuperUser from .. import serializers +from ..models import ChatPrompt +from ..prompt import DefaultChatPrompt class ChatAITestingAPI(GenericAPIView): @@ -76,3 +80,39 @@ class ChatAITestingAPI(GenericAPIView): _status, msg = status.HTTP_400_BAD_REQUEST, error return Response(status=_status, data={'msg': msg}) + + +class ChatPromptViewSet(JMSModelViewSet): + serializer_classes = { + 'default': serializers.ChatPromptSerializer, + } + permission_classes = [IsValidUser] + queryset = ChatPrompt.objects.all() + http_method_names = ['get', 'options'] + filterset_fields = ['name'] + search_fields = filterset_fields + + def get_permissions(self): + if self.action in ['create', 'update', 'partial_update', 'destroy']: + self.permission_classes = [OnlySuperUser] + return super().get_permissions() + + def filter_default_prompts(self): + lang = self.request.LANGUAGE_CODE + default_prompts = DefaultChatPrompt.get_prompts(lang) + search_query = self.request.query_params.get('search') + search_query = search_query or self.request.query_params.get('name') + if not search_query: + return default_prompts + + search_query = search_query.lower() + filtered_prompts = [ + prompt for prompt in default_prompts + if search_query in prompt['name'].lower() + ] + return filtered_prompts + + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) + default_prompts = self.filter_default_prompts() + return list(queryset) + default_prompts diff --git a/apps/settings/migrations/0011_chatprompt.py b/apps/settings/migrations/0011_chatprompt.py new file mode 100644 index 000000000..1e2b05801 --- /dev/null +++ b/apps/settings/migrations/0011_chatprompt.py @@ -0,0 +1,31 @@ +# Generated by Django 4.1.10 on 2023-12-13 11:07 + +import uuid + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('settings', '0010_alter_setting_options'), + ] + + operations = [ + migrations.CreateModel( + name='ChatPrompt', + fields=[ + ('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')), + ('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')), + ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), + ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=128, unique=True, verbose_name='Name')), + ('content', models.TextField(verbose_name='Content')), + ('builtin', models.BooleanField(default=False, verbose_name='Builtin')), + ], + options={ + 'verbose_name': 'Chat prompt', + }, + ), + ] diff --git a/apps/settings/models.py b/apps/settings/models.py index 660af78ec..1da643b9e 100644 --- a/apps/settings/models.py +++ b/apps/settings/models.py @@ -8,6 +8,7 @@ from django.db import models from django.db.utils import ProgrammingError, OperationalError from django.utils.translation import gettext_lazy as _ +from common.db.models import JMSBaseModel from common.utils import signer, get_logger logger = get_logger(__name__) @@ -173,3 +174,15 @@ class Setting(models.Model): ('change_terminal', _('Can change terminal setting')), ('change_other', _('Can change other setting')), ] + + +class ChatPrompt(JMSBaseModel): + name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True) + content = models.TextField(blank=False, null=False, verbose_name=_('Content')) + builtin = models.BooleanField(default=False, verbose_name=_('Builtin')) + + class Meta: + verbose_name = _("Chat prompt") + + def __str__(self): + return self.name diff --git a/apps/settings/prompt.py b/apps/settings/prompt.py new file mode 100644 index 000000000..516b24de8 --- /dev/null +++ b/apps/settings/prompt.py @@ -0,0 +1,197 @@ +class DefaultChatPrompt: + DEFAULT = { + 'zh': [ + { + 'name': '小红书风格', + 'content': '请使用 Emoji 风格编辑以下段落,该风格以引人入胜的标题、' + '每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。', + }, + { + 'name': '写作助理', + 'content': '作为一名中文写作改进助理,你的任务是改进所提供文本的拼写、语法、清晰、简洁和整体可读性,' + '同时分解长句,减少重复,并提供改进建议。请只提供文本的更正版本,避免包括解释。', + }, + { + 'name': 'Nature 风格润色', + 'content': '我希望你能充当专业的拼写和语法校对者,并改进我的文章。' + '我想让你用更美丽、优雅、高级的英语单词和句子替换我的简化 A0 级别的单词和句子,' + '保持意思不变,但使它们更具文学性,在《自然》杂志风格中提高我的表达水平。', + }, + { + 'name': '周报生成器', + 'content': '使用下面提供的文本作为中文周报的基础,生成一个简洁的摘要,突出最重要的内容。该报告应以 markdown 格式编写,' + '并应易于阅读和理解,以满足一般受众的需要。特别是要注重提供对利益相关者和决策者有用的见解和分析。' + '你也可以根据需要使用任何额外的信息或来源。', + }, + { + 'name': '数据库专家', + 'content': '我希望你充当一个数据库专家的角色,当我问你 sql 相关的问题时,' + '我需要你转换为标准的 sql 语句,当我的描述不够精准时,请给出合适的反馈', + }, + { + 'name': '全栈程序员', + 'content': '我希望你能扮演一个软件开发者的角色。我将提供一些关于网络应用需求的具体信息,' + '而你的工作是提出一个架构和代码,用 Golang 和 Angular 开发安全的应用。', + }, + { + 'name': '前端开发', + 'content': '我希望你能担任高级前端开发员。我将描述一个项目的细节,你将用这些工具来编码项目。' + 'Create React App, yarn, Ant Design, List, Redux Toolkit, createSlice, thunk, axios. ' + '你应该将文件合并到单一的 index.js 文件中,而不是其他。不要写解释。', + }, + { + 'name': '架构师 IT', + 'content': '我希望你能扮演一个 IT 架构师的角色。我将提供一些关于应用程序或其他数字产品功能的细节,' + '而你的工作是想出将其整合到 IT 环境中的方法。这可能涉及到分析业务需求,进行差距分析,' + '并将新系统的功能映射到现有的 IT 环境中。接下来的步骤是创建一个解决方案设计,' + '一个物理网络蓝图,定义系统集成的接口和部署环境的蓝图。', + }, + { + 'name': '代码释义器', + 'content': '我希望你能充当代码解释者,阐明代码的语法和语义。', + }, + { + 'name': 'IT 编程问题', + 'content': '我想让你充当 Stackoverflow 的帖子。我将提出与编程有关的问题,你将回答答案是什么。' + '我希望你只回答给定的答案,在没有足够的细节时写出解释。当我需要用英语告诉你一些事情时,我会把文字放在大括号里{像这样}。' + }, + ], + 'en': [ + { + "name": "Xiaohongshu Style", + "content": "Please edit the following paragraphs in Emoji style. " + "This style is characterized by engaging titles, the inclusion of emojis in each paragraph, " + "and adding related tags at the end. Ensure the original meaning is maintained." + }, + { + "name": "Writing Assistant", + "content": "As a Chinese writing improvement assistant, " + "your task is to improve the provided text in terms of spelling, grammar, clarity, " + "conciseness, and overall readability. Also, break down long sentences, reduce repetition, " + "and provide suggestions for improvement. Please only provide the corrected version of " + "the text, avoiding including explanations." + }, + { + "name": "Nature Style Editing", + "content": "I want you to act as a professional spelling and grammar proofreader and improve " + "my article. I want you to replace my simplified A0 level words and sentences with " + "more beautiful, elegant, and advanced English words and sentences. Keep the meaning " + "the same but make them more literary, enhancing my expression in the style of 'Nature' " + "magazine." + }, + { + "name": "Weekly Report Generator", + "content": "Using the text provided below as a basis for a Chinese weekly report, " + "generate a concise summary that highlights the most important content. " + "The report should be written in markdown format and should be easy to read " + "and understand for a general audience, especially focusing on providing insights " + "and analysis useful to stakeholders and decision-makers. You may also use any additional " + "information or sources as needed." + }, + { + "name": "Database Expert", + "content": "I want you to act as a database expert. When I ask you questions related to SQL, " + "I need you to convert them into standard SQL statements. " + "Please provide appropriate feedback when my descriptions are not precise enough." + }, + { + "name": "Full-Stack Programmer", + "content": "I want you to play the role of a software developer. " + "I will provide specific information about web application requirements, " + "and your job is to propose an architecture and code for developing a secure application " + "using Golang and Angular." + }, + { + "name": "Front-End Developer", + "content": "I want you to act as a senior front-end developer. " + "I will describe the details of a project, and you will code the project using these tools:" + " Create React App, yarn, Ant Design, List, Redux Toolkit, createSlice, thunk, axios. " + "You should consolidate files into a single index.js file, and not write explanations." + }, + { + "name": "IT Architect", + "content": "I want you to play the role of an IT architect. " + "I will provide details about the functionality of applications or other digital products, " + "and your job is to figure out how to integrate them into the IT environment. " + "This may involve analyzing business requirements, conducting gap analysis, " + "and mapping the new system's features to the existing IT environment. " + "The next steps are to create a solution design, a physical network blueprint, " + "define interfaces for system integration, and a blueprint for the deployment environment." + }, + { + "name": "Code Interpreter", + "content": "I want you to act as a code interpreter, clarifying the syntax and semantics of code." + }, + { + "name": "IT Programming Questions", + "content": "I want you to act as a Stackoverflow post. I will ask questions related to programming, " + "and you will answer what the answer is. Write out explanations " + "when there are not enough details. When I need to tell you something in English, " + "I will enclose the text in braces {like this}." + } + ], + 'ja': [ + { + "name": "小红书風格", + "content": "Emojiスタイルで以下の段落を編集してください。このスタイルは、魅力的なタイトル、" + "各段落に絵文字を含め、関連するタグを末尾に追加することが特徴です。原文の意味を保持してください。" + }, + { + "name": "ライティングアシスタント", + "content": "中国語のライティング改善アシスタントとして、提供されたテキストのスペル、" + "文法、明瞭さ、簡潔さ、全体的な可読性を改善し、長い文を分解し、重複を減らし、" + "改善提案を提供します。テキストの修正版のみを提供し、説明は含めないでください。" + }, + { + "name": "Nature スタイルの編集", + "content": "プロのスペルと文法の校正者として機能し、私の記事を改善してください。" + "私の簡素化されたA0レベルの単語や文章を、より美しく、優雅で、" + "高度な英語の単語や文章に置き換えて、文学的な要素を加え、「自然」誌スタイルで表現レベルを高めてください。" + }, + { + "name": "週報ジェネレータ", + "content": "以下のテキストを基にして中国語の週報の簡潔な要約を作成し、最も重要な内容を強調してください。" + "このレポートはマークダウン形式で書かれ、一般の聴衆にとって読みやすく理解しやすいものでなければなりません。" + "特に、利害関係者や意思決定者に有用な洞察と分析を提供することに重点を置いてください。" + "必要に応じて、追加の情報やソースを使用しても構いません。" + }, + { + "name": "データベースの専門家", + "content": "データベース専門家として機能し、私がsqlに関連する質問をするとき、" + "それを標準のsqlステートメントに変換してください。私の説明が不正確な場合は、適切なフィードバックを提供してください。" + }, + { + "name": "フルスタックプログラマー", + "content": "ソフトウェア開発者の役割を果たしてください。私はウェブアプリケーションの要件に関する具体的な情報を提供します。" + "あなたの仕事は、GolangとAngularを使用して安全なアプリケーションを開発するためのアーキテクチャとコードを提案することです。" + }, + { + "name": "フロントエンド開発", + "content": "上級フロントエンド開発者として機能してください。私はプロジェクトの詳細を説明し、" + "これらのツールを使用してプロジェクトをコーディングします。" + "Create React App、yarn、Ant Design、List、Redux Toolkit、createSlice、thunk、axiosを使用してください。" + "ファイルをindex.jsファイルに統合し、他のファイルではなく、説明は書かないでください。" + }, + { + "name": "ITアーキテクト", + "content": "ITアーキテクトの役割を果たしてください。私はアプリケーションや他のデジタル製品の機能に関する詳細を提供します。" + "あなたの仕事は、それをIT環境に統合する方法を考えることです。これには、ビジネス要件の分析、ギャップ分析の実施、" + "新システムの機能を既存のIT環境にマッピングすることが含まれる場合があります。次のステップは、" + "ソリューションデザインの作成、物理的なネットワークのブループリント、システム統合のインターフェース、およびデプロイメント環境のブループリントを定義することです。" + }, + { + "name": "コードインタープリター", + "content": "コードの解釈者として機能し、コードの文法と意味を明確に説明してください。" + }, + { + "name": "ITプログラミングの問題", + "content": "Stackoverflowの投稿として機能してください。私はプログラミングに関連する質問をします。" + "あなたは答えを何であるか答えます。十分な詳細がない場合は説明を書いてください。英語で何かを伝える必要があるときは、" + "大括弧でテキストを囲みます{このように}。" + } + ] + } + + @classmethod + def get_prompts(cls, lang: str) -> list: + return cls.DEFAULT.get(lang[:2], 'zh') diff --git a/apps/settings/serializers/__init__.py b/apps/settings/serializers/__init__.py index fe94eb1da..600684387 100644 --- a/apps/settings/serializers/__init__.py +++ b/apps/settings/serializers/__init__.py @@ -8,6 +8,7 @@ from .feature import * from .msg import * from .msg import * from .other import * +from .prompt import * from .public import * from .security import * from .settings import * diff --git a/apps/settings/serializers/prompt.py b/apps/settings/serializers/prompt.py new file mode 100644 index 000000000..6b7804516 --- /dev/null +++ b/apps/settings/serializers/prompt.py @@ -0,0 +1,11 @@ +from rest_framework import serializers + +from settings.models import ChatPrompt + + +class ChatPromptSerializer(serializers.ModelSerializer): + class Meta: + model = ChatPrompt + fields = [ + 'id', 'name', 'content', 'builtin' + ] diff --git a/apps/settings/urls/api_urls.py b/apps/settings/urls/api_urls.py index ed8cf74de..fdfae5146 100644 --- a/apps/settings/urls/api_urls.py +++ b/apps/settings/urls/api_urls.py @@ -1,10 +1,13 @@ from __future__ import absolute_import from django.urls import path +from rest_framework_bulk.routes import BulkRouter from .. import api app_name = 'common' +router = BulkRouter() +router.register(r'chatai-prompts', api.ChatPromptViewSet, 'chatai-prompt') urlpatterns = [ path('mail/testing/', api.MailTestingAPI.as_view(), name='mail-testing'), @@ -28,3 +31,5 @@ urlpatterns = [ path('public/open/', api.OpenPublicSettingApi.as_view(), name='open-public-setting'), path('server-info/', api.ServerInfoApi.as_view(), name='server-info'), ] + +urlpatterns += router.urls