From 60cccf01a3ae121fea9b0ff7189ea0a2547e590c Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Wed, 16 Oct 2024 16:43:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E8=AF=9D=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0018_application_clean_time.py | 18 ++++++ apps/application/models/application.py | 1 + .../serializers/application_serializers.py | 26 +++++++-- apps/common/job/__init__.py | 2 + apps/common/job/clean_chat_job.py | 56 +++++++++++++++++++ ui/src/views/log/index.vue | 51 ++++++++++++++++- 6 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 apps/application/migrations/0018_application_clean_time.py create mode 100644 apps/common/job/clean_chat_job.py diff --git a/apps/application/migrations/0018_application_clean_time.py b/apps/application/migrations/0018_application_clean_time.py new file mode 100644 index 000000000..0662b5f23 --- /dev/null +++ b/apps/application/migrations/0018_application_clean_time.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.15 on 2024-10-16 14:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('application', '0017_application_tts_model_params_setting'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='clean_time', + field=models.IntegerField(default=180, verbose_name='清理时间'), + ), + ] diff --git a/apps/application/models/application.py b/apps/application/models/application.py index ba4c03e26..e37dcb07e 100644 --- a/apps/application/models/application.py +++ b/apps/application/models/application.py @@ -65,6 +65,7 @@ class Application(AppModelMixin): 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") + clean_time = models.IntegerField(verbose_name="清理时间", default=180) @staticmethod def get_default_model_prompt(): diff --git a/apps/application/serializers/application_serializers.py b/apps/application/serializers/application_serializers.py index bdde5859b..cca5ce170 100644 --- a/apps/application/serializers/application_serializers.py +++ b/apps/application/serializers/application_serializers.py @@ -743,13 +743,30 @@ class ApplicationSerializer(serializers.Serializer): application_setting = QuerySet(application_setting_model).filter( application_id=application_access_token.application_id).first() if application_setting is not None: + custom_theme = getattr(application_setting, 'custom_theme', {}) + float_location = getattr(application_setting, 'float_location', {}) + if not custom_theme: + application_setting.custom_theme = { + 'theme_color': '', + 'header_font_color': '' + } + if not float_location: + application_setting.float_location = { + 'x': {'type': '', 'value': ''}, + 'y': {'type': '', 'value': ''} + } application_setting_dict = {'show_source': application_access_token.show_source, 'show_history': application_setting.show_history, 'draggable': application_setting.draggable, 'show_guide': application_setting.show_guide, 'avatar': application_setting.avatar, 'float_icon': application_setting.float_icon, - 'authentication': application_setting.authentication} + 'authentication': application_setting.authentication, + 'disclaimer': application_setting.disclaimer, + 'disclaimer_value': application_setting.disclaimer_value, + 'custom_theme': application_setting.custom_theme, + 'user_avatar': application_setting.user_avatar, + 'float_location': application_setting.float_location} return ApplicationSerializer.Query.reset_application( {**ApplicationSerializer.ApplicationModel(application).data, 'stt_model_id': application.stt_model_id, @@ -810,8 +827,8 @@ class ApplicationSerializer(serializers.Serializer): update_keys = ['name', 'desc', 'model_id', 'multiple_rounds_dialogue', 'prologue', 'status', 'dataset_setting', 'model_setting', 'problem_optimization', 'dialogue_number', 'stt_model_id', 'tts_model_id', 'tts_model_enable', 'stt_model_enable', 'tts_type', - 'api_key_is_active', 'icon', 'work_flow', 'model_params_setting','tts_model_params_setting', - 'problem_optimization_prompt'] + 'api_key_is_active', 'icon', 'work_flow', 'model_params_setting', 'tts_model_params_setting', + 'problem_optimization_prompt', 'clean_time'] for update_key in update_keys: if update_key in instance and instance.get(update_key) is not None: application.__setattr__(update_key, instance.get(update_key)) @@ -952,7 +969,8 @@ class ApplicationSerializer(serializers.Serializer): application_id = self.data.get('application_id') application = QuerySet(Application).filter(id=application_id).first() if application.tts_model_enable: - model = get_model_instance_by_model_user_id(application.tts_model_id, application.user_id, **application.tts_model_params_setting) + model = get_model_instance_by_model_user_id(application.tts_model_id, application.user_id, + **application.tts_model_params_setting) return model.text_to_speech(text) class ApplicationKeySerializerModel(serializers.ModelSerializer): diff --git a/apps/common/job/__init__.py b/apps/common/job/__init__.py index 895bf7f5d..2f4ef2697 100644 --- a/apps/common/job/__init__.py +++ b/apps/common/job/__init__.py @@ -7,7 +7,9 @@ @desc: """ from .client_access_num_job import * +from .clean_chat_job import * def run(): client_access_num_job.run() + clean_chat_job.run() diff --git a/apps/common/job/clean_chat_job.py b/apps/common/job/clean_chat_job.py new file mode 100644 index 000000000..23ff2c85a --- /dev/null +++ b/apps/common/job/clean_chat_job.py @@ -0,0 +1,56 @@ +# coding=utf-8 + +import logging +import datetime + +from django.db import transaction +from django.utils import timezone +from apscheduler.schedulers.background import BackgroundScheduler +from django_apscheduler.jobstores import DjangoJobStore +from application.models import Application, Chat +from django.db.models import Q +from common.lock.impl.file_lock import FileLock + +scheduler = BackgroundScheduler() +scheduler.add_jobstore(DjangoJobStore(), "default") +lock = FileLock() + + +def clean_chat_log_job(): + logging.getLogger("max_kb").info('开始清理对话记录') + now = timezone.now() + + applications = Application.objects.all().values('id', 'clean_time') + cutoff_dates = { + app['id']: now - datetime.timedelta(days=app['clean_time'] or 180) + for app in applications + } + + query_conditions = Q() + for app_id, cutoff_date in cutoff_dates.items(): + query_conditions |= Q(application_id=app_id, create_time__lt=cutoff_date) + + batch_size = 500 + while True: + with transaction.atomic(): + logs_to_delete = Chat.objects.filter(query_conditions).values_list('id', flat=True)[:batch_size] + count = logs_to_delete.count() + if count == 0: + break + deleted_count, _ = Chat.objects.filter(id__in=logs_to_delete).delete() + if deleted_count < batch_size: + break + + logging.getLogger("max_kb").info(f'结束清理对话记录') + + +def run(): + if lock.try_lock('clean_chat_log_job', 30 * 30): + try: + scheduler.start() + existing_job = scheduler.get_job(job_id='clean_chat_log') + if existing_job is not None: + existing_job.remove() + scheduler.add_job(clean_chat_log_job, 'cron', hour='0', minute='5', id='clean_chat_log') + finally: + lock.un_lock('clean_chat_log_job') diff --git a/ui/src/views/log/index.vue b/ui/src/views/log/index.vue index 5748be6a3..01919e543 100644 --- a/ui/src/views/log/index.vue +++ b/ui/src/views/log/index.vue @@ -29,7 +29,10 @@ style="margin-left: 10px" clearable /> - 导出 +
+ 清除策略 + 导出 +
+ + 删除 + + 天之前的对话记录 + +