Commit 2c990ab

benny-dou <60535774+benny-dou@users.noreply.github.com>
2025-03-14 14:12:55
feat(summary): add daily summary feature
1 parent f0392bd
Changed files (3)
src/llm/summary.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+import json
 import re
 from datetime import datetime, timedelta
 from zoneinfo import ZoneInfo
 
+from loguru import logger
 from pyrogram.client import Client
-from pyrogram.types import Message
+from pyrogram.types import Chat, Message
 
-from config import GPT, MAX_MESSAGE_SUMMARY, PREFIX, TZ
+from config import GPT, MAX_MESSAGE_SUMMARY, PREFIX, TID, TZ
 from llm.models import get_model_config_with_contexts
 from llm.prompts import refine_prompts
 from llm.response import send_to_gpt
@@ -51,6 +53,7 @@ HELP = f"""🤖**GPT总结历史消息** (最多{MAX_MESSAGE_SUMMARY}条)
 - 如果用户名中有空格, 请去除空格。例如: 想指定用户为John Doe请使用 `@JohnDoe`
 - 3️⃣的时间格式中没有任何分隔符, 必须为YYYYMMDDHHMMSS (14位纯数字)
 """
+DAILY_SUMMARY_PREFIX = "🏪**#爬楼助手**\n"
 
 
 async def ai_summary(client: Client, message: Message, summary_prefix: str | None = None, **kwargs):
@@ -203,6 +206,9 @@ async def get_contexts(history: list[dict]) -> dict:
         if info["text"].startswith("/"):  # commands
             continue
 
+        if info["text"].startswith(DAILY_SUMMARY_PREFIX):  # daily summary
+            continue
+
         if info["text"].startswith("👤"):  # social media
             continue
         if info["is_bot"]:  # bots
@@ -244,3 +250,32 @@ def get_message_by_id(history: list[dict], message_id: int | None = None) -> dic
         "username": info["full_name"],
         "message": info["text"] or info["mtype"],
     }
+
+
+async def daily_summary(client: Client):
+    """Daily summary of the chat history."""
+    now = nowdt(TZ)
+    if now.hour not in [4, 12, 20]:
+        return
+    if now.minute != 0:
+        return
+    mapping = {}
+    try:
+        mapping = json.loads(TID.DAILY_SUMMARY)
+    except Exception:
+        logger.warning(f"Invalid DAILY_SUMMARY: {TID.DAILY_SUMMARY}")
+    for source_chat_id, target_chat_id in mapping.items():
+        logger.info(f"Summary chat {source_chat_id}, send results to {target_chat_id}")
+        # fake message
+        message = Message(
+            id=0,
+            chat=Chat(id=target_chat_id),
+            text=f"/summary #8h cid={to_int(source_chat_id)}",  # type: ignore
+        )
+        await ai_summary(
+            client,
+            message,
+            summary_prefix=DAILY_SUMMARY_PREFIX,
+            target_chat=to_int(target_chat_id),
+            reply_msg_id=-1,
+        )
src/config.py
@@ -223,6 +223,7 @@ class TID:  # see more TID usecase in `src/permission.py`
     ADMIN = os.getenv("TID_ADMIN", "")
     # back up ytdlp audio if the user does not request it
     CHANNEL_YTDLP_BACKUP = os.getenv("TID_CHANNEL_YTDLP_BACKUP", "me")
+    DAILY_SUMMARY = os.getenv("TID_DAILY_SUMMARY", "{}")  # {"source-chat-id": "target-chat-id"}, e.g. '{"-1001234567890": "-1009876543210"}'
 
 
 class DB:
src/main.py
@@ -23,6 +23,7 @@ from bridge.ocr import forward_ocr_results
 from bridge.social import forward_social_media_results
 from config import DAILY_MESSAGES, DEVICE_NAME, ENABLE, PROXY, TOKEN, TZ, cache
 from handler import handle_social_media, handle_utilities
+from llm.summary import daily_summary
 from messages.parser import parse_msg
 from permission import check_permission
 from price.entrypoint import match_symbol_category
@@ -109,6 +110,8 @@ async def scheduling(client: Client):
         await match_symbol_category()  # to cache all supported symbols
 
     # custom crontab jobs
+    await daily_summary(client)
+
     now = nowdt(TZ)
     if now.hour == 8 and now.minute == 0:  # daliy messages
         daliy = {}