Bladeren bron

send knowledge base auto disable notification (#12126)

Jyong 3 maanden geleden
bovenliggende
commit
cf00ee42f5

+ 6 - 0
api/extensions/ext_celery.py

@@ -69,6 +69,7 @@ def init_app(app: DifyApp) -> Celery:
         "schedule.create_tidb_serverless_task",
         "schedule.create_tidb_serverless_task",
         "schedule.update_tidb_serverless_status_task",
         "schedule.update_tidb_serverless_status_task",
         "schedule.clean_messages",
         "schedule.clean_messages",
+        "schedule.mail_clean_document_notify_task",
     ]
     ]
     day = dify_config.CELERY_BEAT_SCHEDULER_TIME
     day = dify_config.CELERY_BEAT_SCHEDULER_TIME
     beat_schedule = {
     beat_schedule = {
@@ -92,6 +93,11 @@ def init_app(app: DifyApp) -> Celery:
             "task": "schedule.clean_messages.clean_messages",
             "task": "schedule.clean_messages.clean_messages",
             "schedule": timedelta(days=day),
             "schedule": timedelta(days=day),
         },
         },
+        # every Monday
+        "mail_clean_document_notify_task": {
+            "task": "schedule.mail_clean_document_notify_task.mail_clean_document_notify_task",
+            "schedule": crontab(minute="0", hour="10", day_of_week="1"),
+        },
     }
     }
     celery_app.conf.update(beat_schedule=beat_schedule, imports=imports)
     celery_app.conf.update(beat_schedule=beat_schedule, imports=imports)
 
 

+ 52 - 25
api/schedule/mail_clean_document_notify_task.py

@@ -3,14 +3,18 @@ import time
 from collections import defaultdict
 from collections import defaultdict
 
 
 import click
 import click
-from celery import shared_task  # type: ignore
+from flask import render_template  # type: ignore
 
 
+import app
+from configs import dify_config
+from extensions.ext_database import db
 from extensions.ext_mail import mail
 from extensions.ext_mail import mail
 from models.account import Account, Tenant, TenantAccountJoin
 from models.account import Account, Tenant, TenantAccountJoin
 from models.dataset import Dataset, DatasetAutoDisableLog
 from models.dataset import Dataset, DatasetAutoDisableLog
+from services.feature_service import FeatureService
 
 
 
 
-@shared_task(queue="mail")
+@app.celery.task(queue="dataset")
 def send_document_clean_notify_task():
 def send_document_clean_notify_task():
     """
     """
     Async Send document clean notify mail
     Async Send document clean notify mail
@@ -29,35 +33,58 @@ def send_document_clean_notify_task():
         # group by tenant_id
         # group by tenant_id
         dataset_auto_disable_logs_map: dict[str, list[DatasetAutoDisableLog]] = defaultdict(list)
         dataset_auto_disable_logs_map: dict[str, list[DatasetAutoDisableLog]] = defaultdict(list)
         for dataset_auto_disable_log in dataset_auto_disable_logs:
         for dataset_auto_disable_log in dataset_auto_disable_logs:
+            if dataset_auto_disable_log.tenant_id not in dataset_auto_disable_logs_map:
+                dataset_auto_disable_logs_map[dataset_auto_disable_log.tenant_id] = []
             dataset_auto_disable_logs_map[dataset_auto_disable_log.tenant_id].append(dataset_auto_disable_log)
             dataset_auto_disable_logs_map[dataset_auto_disable_log.tenant_id].append(dataset_auto_disable_log)
-
+        url = f"{dify_config.CONSOLE_WEB_URL}/datasets"
         for tenant_id, tenant_dataset_auto_disable_logs in dataset_auto_disable_logs_map.items():
         for tenant_id, tenant_dataset_auto_disable_logs in dataset_auto_disable_logs_map.items():
-            knowledge_details = []
-            tenant = Tenant.query.filter(Tenant.id == tenant_id).first()
-            if not tenant:
-                continue
-            current_owner_join = TenantAccountJoin.query.filter_by(tenant_id=tenant.id, role="owner").first()
-            if not current_owner_join:
-                continue
-            account = Account.query.filter(Account.id == current_owner_join.account_id).first()
-            if not account:
-                continue
-
-            dataset_auto_dataset_map = {}  # type: ignore
-            for dataset_auto_disable_log in tenant_dataset_auto_disable_logs:
-                dataset_auto_dataset_map[dataset_auto_disable_log.dataset_id].append(
-                    dataset_auto_disable_log.document_id
-                )
+            features = FeatureService.get_features(tenant_id)
+            plan = features.billing.subscription.plan
+            if plan != "sandbox":
+                knowledge_details = []
+                # check tenant
+                tenant = Tenant.query.filter(Tenant.id == tenant_id).first()
+                if not tenant:
+                    continue
+                # check current owner
+                current_owner_join = TenantAccountJoin.query.filter_by(tenant_id=tenant.id, role="owner").first()
+                if not current_owner_join:
+                    continue
+                account = Account.query.filter(Account.id == current_owner_join.account_id).first()
+                if not account:
+                    continue
 
 
-            for dataset_id, document_ids in dataset_auto_dataset_map.items():
-                dataset = Dataset.query.filter(Dataset.id == dataset_id).first()
-                if dataset:
-                    document_count = len(document_ids)
-                    knowledge_details.append(f"<li>Knowledge base {dataset.name}: {document_count} documents</li>")
+                dataset_auto_dataset_map = {}  # type: ignore
+                for dataset_auto_disable_log in tenant_dataset_auto_disable_logs:
+                    if dataset_auto_disable_log.dataset_id not in dataset_auto_dataset_map:
+                        dataset_auto_dataset_map[dataset_auto_disable_log.dataset_id] = []
+                    dataset_auto_dataset_map[dataset_auto_disable_log.dataset_id].append(
+                        dataset_auto_disable_log.document_id
+                    )
 
 
+                for dataset_id, document_ids in dataset_auto_dataset_map.items():
+                    dataset = Dataset.query.filter(Dataset.id == dataset_id).first()
+                    if dataset:
+                        document_count = len(document_ids)
+                        knowledge_details.append(rf"Knowledge base {dataset.name}: {document_count} documents")
+                if knowledge_details:
+                    html_content = render_template(
+                        "clean_document_job_mail_template-US.html",
+                        userName=account.email,
+                        knowledge_details=knowledge_details,
+                        url=url,
+                    )
+                    mail.send(
+                        to=account.email, subject="Dify Knowledge base auto disable notification", html=html_content
+                    )
+
+            # update notified to True
+            for dataset_auto_disable_log in tenant_dataset_auto_disable_logs:
+                dataset_auto_disable_log.notified = True
+            db.session.commit()
         end_at = time.perf_counter()
         end_at = time.perf_counter()
         logging.info(
         logging.info(
             click.style("Send document clean notify mail succeeded: latency: {}".format(end_at - start_at), fg="green")
             click.style("Send document clean notify mail succeeded: latency: {}".format(end_at - start_at), fg="green")
         )
         )
     except Exception:
     except Exception:
-        logging.exception("Send invite member mail to failed")
+        logging.exception("Send document clean notify mail failed")

+ 8 - 6
api/templates/clean_document_job_mail_template-US.html

@@ -45,14 +45,14 @@
     .content ul li {
     .content ul li {
       margin-bottom: 10px;
       margin-bottom: 10px;
     }
     }
-    .cta-button {
+    .cta-button, .cta-button:hover, .cta-button:active, .cta-button:visited, .cta-button:focus {
       display: block;
       display: block;
       margin: 20px auto;
       margin: 20px auto;
       padding: 10px 20px;
       padding: 10px 20px;
       background-color: #4e89f9;
       background-color: #4e89f9;
-      color: #ffffff;
+      color: #ffffff !important;
       text-align: center;
       text-align: center;
-      text-decoration: none;
+      text-decoration: none !important;
       border-radius: 5px;
       border-radius: 5px;
       width: fit-content;
       width: fit-content;
     }
     }
@@ -69,7 +69,7 @@
   <div class="email-container">
   <div class="email-container">
     <!-- Header -->
     <!-- Header -->
     <div class="header">
     <div class="header">
-      <img src="https://via.placeholder.com/150x40?text=Dify" alt="Dify Logo">
+      <img src="https://img.mailinblue.com/6365111/images/content_library/original/64cb67ca60532312c211dc72.png" alt="Dify Logo">
     </div>
     </div>
 
 
     <!-- Content -->
     <!-- Content -->
@@ -78,11 +78,13 @@
       <p>Dear {{userName}},</p>
       <p>Dear {{userName}},</p>
       <p>
       <p>
         We're sorry for the inconvenience. To ensure optimal performance, documents 
         We're sorry for the inconvenience. To ensure optimal performance, documents 
-        that haven’t been updated or accessed in the past 7 days have been disabled in 
+        that haven’t been updated or accessed in the past 30 days have been disabled in
         your knowledge bases:
         your knowledge bases:
       </p>
       </p>
       <ul>
       <ul>
-        {{knowledge_details}}
+          {% for item in knowledge_details %}
+            <li>{{ item }}</li>
+          {% endfor %}
       </ul>
       </ul>
       <p>You can re-enable them anytime.</p>
       <p>You can re-enable them anytime.</p>
       <a href={{url}} class="cta-button">Re-enable in Dify</a>
       <a href={{url}} class="cta-button">Re-enable in Dify</a>