From 0ed1530b4049944f44554ba4711acb823a211854 Mon Sep 17 00:00:00 2001
From: yj <2077506045@qq.com>
Date: 星期二, 26 八月 2025 10:37:23 +0800
Subject: [PATCH] 1.新增结束语判断;2.增加@客服后静默;3.增加判断群已静默后AI已回复也不发消息

---
 /dev/null                         |  119 -------------------
 test.py                           |   13 ++
 config.py                         |    9 +
 app/api/callback.py               |    9 +
 app/services/message_processor.py |  153 ++++++++++++++++++++-----
 logs/app.log                      |    7 
 6 files changed, 151 insertions(+), 159 deletions(-)

diff --git a/app/api/callback.py b/app/api/callback.py
index e4c4858..2be5e12 100644
--- a/app/api/callback.py
+++ b/app/api/callback.py
@@ -48,8 +48,13 @@
             f"鏀跺埌鍥炶皟娑堟伅: messageType={callback_data.messageType}, wcId={callback_data.wcId}"
         )
 
-        # 灏哖ydantic妯″瀷杞崲涓哄瓧鍏�
-        callback_dict = callback_data.model_dump()
+        # 灏哖ydantic妯″瀷杞崲涓哄瓧鍏革紙鍏煎v1鍜寁2锛�
+        if hasattr(callback_data, 'model_dump'):
+            # Pydantic v2
+            callback_dict = callback_data.model_dump()
+        else:
+            # Pydantic v1
+            callback_dict = callback_data.dict()
 
         # 灏嗘秷鎭姞鍏ラ槦鍒�
         success = message_processor.enqueue_callback_message(callback_dict)
diff --git a/app/services/message_processor.py b/app/services/message_processor.py
index 5ac473c..0b26bff 100644
--- a/app/services/message_processor.py
+++ b/app/services/message_processor.py
@@ -84,7 +84,9 @@
             else:
                 combined_content = content  # 濡傛灉閮芥病鏈夛紝浣跨敤鍘熷content
 
-            logger.info(f"寮曠敤娑堟伅鍐呭鎻愬彇瀹屾垚: refer_content_length={len(refer_content)}, xml_title_length={len(xml_title)}, data_title_length={len(title)}, final_title_length={len(final_title)}")
+            logger.info(
+                f"寮曠敤娑堟伅鍐呭鎻愬彇瀹屾垚: refer_content_length={len(refer_content)}, xml_title_length={len(xml_title)}, data_title_length={len(title)}, final_title_length={len(final_title)}"
+            )
             return combined_content
 
         except Exception as e:
@@ -107,7 +109,7 @@
             customer_service_names = settings.customer_service_names
 
             # 鏌ユ壘鎵�鏈堾瀛楃鍚庣殑瀹㈡湇鍚嶇О
-            at_pattern = r'@([^\s]+)'
+            at_pattern = r"@([^\s]+)"
             matches = re.findall(at_pattern, ai_answer)
 
             valid_at_names = []
@@ -124,10 +126,14 @@
                 with next(get_db()) as db:
                     for name in valid_at_names:
                         # 鏍规嵁nick_name鏌ユ壘鑱旂郴浜�
-                        contact = db.query(Contact).filter(Contact.nick_name == name).first()
+                        contact = (
+                            db.query(Contact).filter(Contact.nick_name == name).first()
+                        )
                         if contact:
                             at_wc_ids.append(contact.wc_id)
-                            logger.info(f"鎵惧埌瀹㈡湇鑱旂郴浜�: name={name}, wc_id={contact.wc_id}")
+                            logger.info(
+                                f"鎵惧埌瀹㈡湇鑱旂郴浜�: name={name}, wc_id={contact.wc_id}"
+                            )
                         else:
                             logger.warning(f"鏈壘鍒板鏈嶈仈绯讳汉: name={name}")
 
@@ -136,6 +142,28 @@
         except Exception as e:
             logger.error(f"瑙f瀽@瀛楃寮傚父: error={str(e)}")
             return ai_answer, []
+
+    def is_end_str(self, ai_answer: str) -> bool:
+        """
+        瑙f瀽AI鍥炲鍒ゆ柇鏄惁鏄粨鏉熷瓧绗︿覆
+
+        Args:
+            ai_answer: AI鍥炲鍐呭
+
+        Returns:
+        """
+        try:
+            # 鑾峰彇閰嶇疆鐨勭粨鏉熷瓧绗︿覆鍒楄〃
+            end_str_list = settings.end_str_list
+            for end_str in end_str_list:
+                substrings = end_str.split(',')
+                # 妫�鏌� match_str 鏄惁鍖呭惈姣忎竴涓瓙瀛楃涓�
+                if all(sub in ai_answer for sub in substrings):
+                    return True
+            return False
+        except Exception as e:
+            logger.error(f"瑙f瀽缁撴潫瀛楃涓插紓甯�: error={str(e)}")
+            return False
 
     def is_valid_group_message(self, callback_data: Dict[str, Any]) -> bool:
         """
@@ -177,18 +205,24 @@
         is_friend_ignored = friend_ignore_service.is_friend_ignored(from_user)
 
         if is_friend_ignored:
-            logger.info(f"蹇界暐濂藉弸鍙戦�佺殑娑堟伅: fromUser={from_user}, fromGroup={from_group}")
+            logger.info(
+                f"蹇界暐濂藉弸鍙戦�佺殑娑堟伅: fromUser={from_user}, fromGroup={from_group}"
+            )
             # 缁熻琚拷鐣ョ殑濂藉弸鍙戣█娆℃暟锛堢‘淇濊蹇界暐鐨勫ソ鍙嬫秷鎭篃绾冲叆缁熻锛�
             group_stats_service.increment_user_message_count(from_group, from_user)
             # 婵�娲绘垨寤堕暱璇ョ兢缁勭殑闈欓粯妯″紡
             if silence_service.is_silence_active(from_group):
                 # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忓凡婵�娲伙紝寤堕暱鏃堕棿
                 silence_service.extend_silence_mode(from_group)
-                logger.info(f"濂藉弸娑堟伅琚拷鐣ワ紝缇ょ粍闈欓粯妯″紡鏃堕棿宸插埛鏂�: fromUser={from_user}, fromGroup={from_group}")
+                logger.info(
+                    f"濂藉弸娑堟伅琚拷鐣ワ紝缇ょ粍闈欓粯妯″紡鏃堕棿宸插埛鏂�: fromUser={from_user}, fromGroup={from_group}"
+                )
             else:
                 # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忔湭婵�娲伙紝婵�娲婚潤榛樻ā寮�
                 silence_service.activate_silence_mode(from_group)
-                logger.info(f"濂藉弸娑堟伅琚拷鐣ワ紝缇ょ粍闈欓粯妯″紡宸叉縺娲�: fromUser={from_user}, fromGroup={from_group}")
+                logger.info(
+                    f"濂藉弸娑堟伅琚拷鐣ワ紝缇ょ粍闈欓粯妯″紡宸叉縺娲�: fromUser={from_user}, fromGroup={from_group}"
+                )
             return False
 
         # # 缁熻姝e父澶勭悊鐨勫ソ鍙嬪彂瑷�娆℃暟
@@ -219,18 +253,28 @@
         from app.services.message_aggregator import message_aggregator
 
         # 灏濊瘯灏嗘秷鎭坊鍔犲埌鑱氬悎涓�
-        should_process_immediately, aggregated_data = message_aggregator.add_message_to_aggregation(callback_data)
+        should_process_immediately, aggregated_data = (
+            message_aggregator.add_message_to_aggregation(callback_data)
+        )
 
         if should_process_immediately:
             # 闇�瑕佺珛鍗冲鐞嗭紙涓嶈仛鍚堟垨鑱氬悎瓒呮椂锛�
-            data = aggregated_data.get("data", {}) if aggregated_data else callback_data.get("data", {})
+            data = (
+                aggregated_data.get("data", {})
+                if aggregated_data
+                else callback_data.get("data", {})
+            )
             from_user = data.get("fromUser")
 
             # 灏嗘秷鎭姞鍏edis闃熷垪
-            return redis_queue.enqueue_message(from_user, aggregated_data or callback_data)
+            return redis_queue.enqueue_message(
+                from_user, aggregated_data or callback_data
+            )
         else:
             # 娑堟伅宸茶鑱氬悎锛屼笉闇�瑕佺珛鍗冲鐞�
-            logger.info(f"娑堟伅宸叉坊鍔犲埌鑱氬悎闃熷垪锛岀瓑寰呰仛鍚堝鐞�: fromUser={callback_data.get('data', {}).get('fromUser')}")
+            logger.info(
+                f"娑堟伅宸叉坊鍔犲埌鑱氬悎闃熷垪锛岀瓑寰呰仛鍚堝鐞�: fromUser={callback_data.get('data', {}).get('fromUser')}"
+            )
             return True
 
     def ensure_contact_exists(self, from_group: str, w_id: str, db: Session) -> bool:
@@ -309,7 +353,9 @@
             w_id = data.get("wId")
             message_type = message_data.get("messageType")
 
-            logger.info(f"寮�濮嬪鐞嗘秷鎭�: from_user={from_user}, from_group={from_group}, message_type={message_type}")
+            logger.info(
+                f"寮�濮嬪鐞嗘秷鎭�: from_user={from_user}, from_group={from_group}, message_type={message_type}"
+            )
 
             # 鏍规嵁娑堟伅绫诲瀷澶勭悊鍐呭
             if message_type == "80014":
@@ -325,8 +371,12 @@
                     return False
 
                 # 3.2 鑾峰彇缇ょ粍涓彂瑷�娆℃暟鏈�澶氱殑鐢ㄦ埛鏄电О
-                most_active_nickname = group_stats_service.get_most_active_user_nickname(from_group)
-                logger.info(f"缇ょ粍鏈�娲昏穬鐢ㄦ埛鏄电О: group={from_group}, nickname={most_active_nickname}")
+                most_active_nickname = (
+                    group_stats_service.get_most_active_user_nickname(from_group)
+                )
+                logger.info(
+                    f"缇ょ粍鏈�娲昏穬鐢ㄦ埛鏄电О: group={from_group}, nickname={most_active_nickname}"
+                )
 
                 # 3.3 鑾峰彇鐢ㄦ埛鍦ㄥ綋鍓嶇兢缁勭殑conversation_id
                 conversation_id = redis_queue.get_conversation_id(from_user, from_group)
@@ -336,8 +386,13 @@
                     query=content,
                     user=from_user,
                     conversation_id=conversation_id,
-                    nick_name=most_active_nickname
+                    nick_name=most_active_nickname,
                 )
+
+                if silence_service.is_silence_active(from_group):
+                    # 鍥炲鍓嶅垽鏂槸鍚︽縺娲婚潤榛橈紝宸查潤榛樺垯涓嶅洖澶�
+                    logger.error(f"Dify宸插搷搴斾絾缇ょ粍宸查潤榛橈細from_user={from_user}")
+                    return False
 
                 if not dify_response:
                     logger.error(f"Dify鍝嶅簲澶辫触: from_user={from_user}")
@@ -349,7 +404,9 @@
 
                 # 鏇存柊Redis涓殑conversation_id锛堝熀浜庣敤鎴�+缇ょ粍锛�
                 if new_conversation_id:
-                    redis_queue.set_conversation_id(from_user, new_conversation_id, from_group, 1800)
+                    redis_queue.set_conversation_id(
+                        from_user, new_conversation_id, from_group, settings.silence_duration_minutes * 60
+                    )
 
                 # 3.4 淇濆瓨瀵硅瘽璁板綍鍒版暟鎹簱
                 # 鎸夌敤鎴枫�佺兢缁勫拰灏忔椂鍒嗙粍瀵硅瘽璁板綍
@@ -363,7 +420,7 @@
                         Conversation.from_user == from_user,
                         Conversation.conversation_id == new_conversation_id,
                         Conversation.group == from_group,
-                        Conversation.hour == hour_key
+                        Conversation.hour == hour_key,
                     )
                     .first()
                 )
@@ -378,20 +435,23 @@
                             content_list = []
 
                         # 杩藉姞鏂扮殑瀵硅瘽鍐呭
-                        content_list.append({
-                            "user": content,
-                            "ai": ai_answer
-                        })
+                        content_list.append({"user": content, "ai": ai_answer})
 
                         # 鏇存柊璁板綍
-                        existing_conversation.content = json.dumps(content_list, ensure_ascii=False)
+                        existing_conversation.content = json.dumps(
+                            content_list, ensure_ascii=False
+                        )
                         existing_conversation.is_processed = True
-                        logger.info(f"杩藉姞鍒板綋鍓嶇敤鎴风兢缁勫皬鏃跺璇濊褰�: user={from_user}, group={from_group}, hour={hour_key}, 瀵硅瘽杞={len(content_list)}")
+                        logger.info(
+                            f"杩藉姞鍒板綋鍓嶇敤鎴风兢缁勫皬鏃跺璇濊褰�: user={from_user}, group={from_group}, hour={hour_key}, 瀵硅瘽杞={len(content_list)}"
+                        )
                     except json.JSONDecodeError as e:
                         logger.error(f"瑙f瀽鐜版湁瀵硅瘽鍐呭JSON澶辫触: {str(e)}, 閲嶆柊鍒涘缓")
                         # 濡傛灉JSON瑙f瀽澶辫触锛岄噸鏂板垱寤篶ontent
                         content_list = [{"user": content, "ai": ai_answer}]
-                        existing_conversation.content = json.dumps(content_list, ensure_ascii=False)
+                        existing_conversation.content = json.dumps(
+                            content_list, ensure_ascii=False
+                        )
                         existing_conversation.is_processed = True
                 else:
                     # 鍒涘缓鏂拌褰� - 鏂扮殑鐢ㄦ埛缇ょ粍灏忔椂瀵硅瘽鎴栭娆″璇濓紝浣跨敤JSON鏍煎紡瀛樺偍瀵硅瘽鍐呭
@@ -405,7 +465,9 @@
                         is_processed=True,
                     )
                     db.add(new_conversation)
-                    logger.info(f"鍒涘缓鏂扮殑鐢ㄦ埛缇ょ粍灏忔椂瀵硅瘽璁板綍: user={from_user}, group={from_group}, hour={hour_key}, 鍒濆瀵硅瘽杞=1")
+                    logger.info(
+                        f"鍒涘缓鏂扮殑鐢ㄦ埛缇ょ粍灏忔椂瀵硅瘽璁板綍: user={from_user}, group={from_group}, hour={hour_key}, 鍒濆瀵硅瘽杞=1"
+                    )
 
                 db.commit()
 
@@ -414,7 +476,8 @@
                 if ai_answer:
                     # 瑙f瀽AI鍥炲涓殑@瀛楃
                     processed_answer, at_wc_ids = self.parse_at_mentions(ai_answer)
-
+                    # 鍒ゆ柇AI鍥炲鏄惁鏄粨鏉熷瓧绗︿覆
+                    is_end_str = self.is_end_str(ai_answer)
                     # 鍙戦�佹秷鎭紝鏈�澶氶噸璇�3娆�
                     for attempt in range(3):
                         if at_wc_ids:
@@ -423,6 +486,19 @@
                             if ecloud_client.send_group_at_message(
                                 w_id, from_group, processed_answer, at_wc_ids
                             ):
+                                # @鍚庤Е鍙戦潤榛樻ā寮�
+                                if silence_service.is_silence_active(from_group):
+                                    # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忓凡婵�娲伙紝寤堕暱鏃堕棿
+                                    silence_service.extend_silence_mode(from_group)
+                                    logger.info(
+                                        f"AI鍥炲@瀹㈡湇锛岀兢缁勯潤榛樻ā寮忔椂闂村凡鍒锋柊: fromUser={from_user}, fromGroup={from_group}"
+                                    )
+                                else:
+                                    # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忔湭婵�娲伙紝婵�娲婚潤榛樻ā寮�
+                                    silence_service.activate_silence_mode(from_group)
+                                    logger.info(
+                                        f"AI鍥炲@瀹㈡湇锛岀兢缁勯潤榛樻ā寮忓凡婵�娲�: fromUser={from_user}, fromGroup={from_group}"
+                                    )
                                 success = True
                                 break
                         else:
@@ -434,10 +510,27 @@
                                 success = True
                                 break
 
-                        logger.warning(f"鍙戦�丄I鍥炵瓟澶辫触锛屽皾璇曢噸璇� ({attempt + 1}/3): from_user={from_user}")
+                        logger.warning(
+                            f"鍙戦�丄I鍥炵瓟澶辫触锛屽皾璇曢噸璇� ({attempt + 1}/3): from_user={from_user}"
+                        )
                         if attempt < 2:  # 涓嶆槸鏈�鍚庝竴娆″皾璇曪紝绛夊緟涓�娈垫椂闂村啀閲嶈瘯
-                            time.sleep(2 ** attempt)  # 鎸囨暟閫�閬�
-                
+                            time.sleep(2**attempt)  # 鎸囨暟閫�閬�
+
+                    # AI鍥炲缁撴潫瀛楃涓茶Е鍙戦潤榛樻ā寮�
+                    if is_end_str:
+                        if silence_service.is_silence_active(from_group):
+                            # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忓凡婵�娲伙紝寤堕暱鏃堕棿
+                            silence_service.extend_silence_mode(from_group)
+                            logger.info(
+                                f"AI鍥炲缁撴潫瀛楃涓诧紝缇ょ粍闈欓粯妯″紡鏃堕棿宸插埛鏂�: fromUser={from_user}, fromGroup={from_group}"
+                            )
+                        else:
+                            # 濡傛灉璇ョ兢缁勯潤榛樻ā寮忔湭婵�娲伙紝婵�娲婚潤榛樻ā寮�
+                            silence_service.activate_silence_mode(from_group)
+                            logger.info(
+                                f"AI鍥炲缁撴潫瀛楃涓诧紝缇ょ粍闈欓粯妯″紡宸叉縺娲�: fromUser={from_user}, fromGroup={from_group}"
+                            )
+
                 if success:
                     # 鏇存柊鍙戦�佺姸鎬�
                     conversation = (
@@ -446,7 +539,7 @@
                             Conversation.from_user == from_user,
                             Conversation.conversation_id == new_conversation_id,
                             Conversation.group == from_group,
-                            Conversation.hour == hour_key
+                            Conversation.hour == hour_key,
                         )
                         .first()
                     )
diff --git a/config.py b/config.py
index 2fcbf94..7942292 100644
--- a/config.py
+++ b/config.py
@@ -78,9 +78,9 @@
         self.friend_ignore_whitelist = friend_ignore_config["whitelist"]
 
         # 闈欓粯妯″紡閰嶇疆
-        silence_mode_config = config_data["silence_mode"]
-        self.silence_mode_enabled = silence_mode_config["enabled"]
-        self.silence_duration_minutes = silence_mode_config["duration_minutes"]
+        silence_mode_config = config_data.get("silence_mode", {})
+        self.silence_mode_enabled = silence_mode_config.get("enabled", True)
+        self.silence_duration_minutes = silence_mode_config.get("duration_minutes", 10)
 
         # 鍦ㄧ嚎鐘舵�佺洃鎺ч厤缃�
         online_status_config = config_data["online_status_monitor"]
@@ -116,6 +116,9 @@
         self.message_aggregation_enabled = message_aggregation_config.get("enabled", True)
         self.message_aggregation_timeout = message_aggregation_config.get("timeout_seconds", 15)
 
+        # 缁撴潫瀛楃涓查厤缃�
+        self.end_str_list = config_data.get("end_str_list", [])
+
     def update_ecloud_w_id(self, new_w_id: str) -> bool:
         """
         鍔ㄦ�佹洿鏂癊浜戠瀹剁殑w_id閰嶇疆
diff --git a/example_usage.py b/example_usage.py
deleted file mode 100644
index e6373a1..0000000
--- a/example_usage.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python3
-"""
-鍦ㄧ嚎鐘舵�佺洃鎺у姛鑳戒娇鐢ㄧず渚�
-"""
-
-import asyncio
-import time
-from config import settings
-from app.services.ecloud_client import ecloud_client
-from app.services.email_service import email_service
-from app.services.sms_service import sms_service
-from app.workers.online_status_worker import online_status_worker
-
-
-async def test_online_status_monitoring():
-    """娴嬭瘯鍦ㄧ嚎鐘舵�佺洃鎺у姛鑳�"""
-    print("=== 鍦ㄧ嚎鐘舵�佺洃鎺у姛鑳芥祴璇� ===\n")
-    
-    # 1. 娴嬭瘯鏌ヨ鍦ㄧ嚎寰俊鍒楄〃
-    print("1. 娴嬭瘯鏌ヨ鍦ㄧ嚎寰俊鍒楄〃...")
-    online_list = ecloud_client.query_online_wechat_list()
-    if online_list is not None:
-        print(f"   鏌ヨ鎴愬姛锛屽湪绾垮井淇℃暟閲�: {len(online_list)}")
-        for i, wechat in enumerate(online_list):
-            print(f"   寰俊{i+1}: wcId={wechat.get('wcId')}, wId={wechat.get('wId')}")
-    else:
-        print("   鏌ヨ澶辫触")
-    print()
-    
-    # 2. 娴嬭瘯閭欢鏈嶅姟
-    print("2. 娴嬭瘯閭欢鏈嶅姟...")
-    if settings.email_enabled:
-        # 娴嬭瘯杩炴帴
-        email_connected = email_service.test_connection()
-        print(f"   閭欢鏈嶅姟杩炴帴: {'鎴愬姛' if email_connected else '澶辫触'}")
-        
-        if email_connected:
-            # 鍙戦�佹祴璇曢偖浠�
-            test_subject = "鍦ㄧ嚎鐘舵�佺洃鎺ф祴璇曢偖浠�"
-            test_content = f"杩欐槸涓�灏佹祴璇曢偖浠讹紝鍙戦�佹椂闂�: {time.strftime('%Y-%m-%d %H:%M:%S')}"
-            email_sent = email_service.send_notification(test_subject, test_content)
-            print(f"   娴嬭瘯閭欢鍙戦��: {'鎴愬姛' if email_sent else '澶辫触'}")
-    else:
-        print("   閭欢鏈嶅姟宸茬鐢�")
-    print()
-    
-    # 3. 娴嬭瘯鐭俊鏈嶅姟
-    print("3. 娴嬭瘯鐭俊鏈嶅姟...")
-    if settings.sms_enabled:
-        # 鍙戦�佹祴璇曠煭淇�
-        test_content = f"銆愭祴璇曘�戝湪绾跨姸鎬佺洃鎺ф祴璇曠煭淇★紝鏃堕棿: {time.strftime('%H:%M:%S')}"
-        sms_sent = sms_service.send_notification(test_content)
-        print(f"   娴嬭瘯鐭俊鍙戦��: {'鎴愬姛' if sms_sent else '澶辫触'}")
-    else:
-        print("   鐭俊鏈嶅姟宸茬鐢�")
-    print()
-    
-    # 4. 娴嬭瘯w_id鍔ㄦ�佹洿鏂�
-    print("4. 娴嬭瘯w_id鍔ㄦ�佹洿鏂�...")
-    current_w_id = settings.get_current_w_id()
-    print(f"   褰撳墠閰嶇疆鐨剋_id: {current_w_id}")
-    
-    if online_list and len(online_list) > 0:
-        online_w_id = online_list[0].get("wId")
-        if online_w_id != current_w_id:
-            print(f"   妫�娴嬪埌w_id鍙樺寲: {current_w_id} -> {online_w_id}")
-            success = settings.update_ecloud_w_id(online_w_id)
-            print(f"   w_id鏇存柊: {'鎴愬姛' if success else '澶辫触'}")
-        else:
-            print("   w_id鏃犲彉鍖栵紝鏃犻渶鏇存柊")
-    else:
-        print("   鏃犲湪绾垮井淇★紝鏃犳硶娴嬭瘯w_id鏇存柊")
-    print()
-    
-    # 5. 鏄剧ず宸ヤ綔杩涚▼鐘舵��
-    print("5. 鍦ㄧ嚎鐘舵�佺洃鎺у伐浣滆繘绋嬬姸鎬�...")
-    status = online_status_worker.get_status()
-    print(f"   杩愯鐘舵��: {'杩愯涓�' if status['running'] else '宸插仠姝�'}")
-    print(f"   鍔熻兘鍚敤: {'鏄�' if status['enabled'] else '鍚�'}")
-    print(f"   妫�娴嬮棿闅�: {status['check_interval_minutes']}鍒嗛挓")
-    print(f"   閫氱煡鍐峰嵈: {status['notification_cooldown_minutes']}鍒嗛挓")
-    if status['last_notification_time']:
-        last_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(status['last_notification_time']))
-        print(f"   涓婃閫氱煡: {last_time}")
-    else:
-        print("   涓婃閫氱煡: 鏃�")
-    print()
-    
-    print("=== 娴嬭瘯瀹屾垚 ===")
-
-
-def show_configuration():
-    """鏄剧ず褰撳墠閰嶇疆"""
-    print("=== 褰撳墠閰嶇疆淇℃伅 ===\n")
-    
-    print("鍦ㄧ嚎鐘舵�佺洃鎺ч厤缃�:")
-    print(f"  鍚敤鐘舵��: {'鏄�' if settings.online_status_enabled else '鍚�'}")
-    print(f"  妫�娴嬮棿闅�: {settings.online_status_check_interval}鍒嗛挓")
-    print(f"  閫氱煡娑堟伅: {settings.online_status_notification_message}")
-    print()
-    
-    print("閭欢閫氱煡閰嶇疆:")
-    print(f"  鍚敤鐘舵��: {'鏄�' if settings.email_enabled else '鍚�'}")
-    if settings.email_enabled:
-        print(f"  SMTP鏈嶅姟鍣�: {settings.email_smtp_server}:{settings.email_smtp_port}")
-        print(f"  鍙戜欢浜�: {settings.email_from_email}")
-        print(f"  鏀朵欢浜�: {', '.join(settings.email_to_emails)}")
-    print()
-    
-    print("鐭俊閫氱煡閰嶇疆:")
-    print(f"  鍚敤鐘舵��: {'鏄�' if settings.sms_enabled else '鍚�'}")
-    if settings.sms_enabled:
-        print(f"  API鍦板潃: {settings.sms_api_url}")
-        print(f"  鐢ㄦ埛鍚�: {settings.sms_username}")
-        print(f"  鎺ユ敹鍙风爜: {', '.join(settings.sms_phone_numbers)}")
-    print()
-    
-    print("E浜戠瀹堕厤缃�:")
-    print(f"  API鍦板潃: {settings.ecloud_base_url}")
-    print(f"  褰撳墠w_id: {settings.ecloud_w_id}")
-    print()
-
-
-if __name__ == "__main__":
-    print("鍦ㄧ嚎鐘舵�佺洃鎺у姛鑳戒娇鐢ㄧず渚媆n")
-    
-    # 鏄剧ず閰嶇疆淇℃伅
-    show_configuration()
-    
-    # 杩愯娴嬭瘯
-    asyncio.run(test_online_status_monitoring())
-    
-    print("\n娉ㄦ剰浜嬮」:")
-    print("1. 璇风‘淇濆凡姝g‘閰嶇疆config.json涓殑鐩稿叧鍙傛暟")
-    print("2. 閭欢鍜岀煭淇℃祴璇曚細瀹為檯鍙戦�佹秷鎭紝璇疯皑鎱庝娇鐢�")
-    print("3. 寤鸿鍦ㄧ敓浜х幆澧冧腑绂佺敤娴嬭瘯鍔熻兘")
diff --git a/logs/app.log b/logs/app.log
index 4f17013..22941d3 100644
--- a/logs/app.log
+++ b/logs/app.log
@@ -1,5 +1,2 @@
-2025-08-07 16:49:53 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-08-07 17:07:18 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-08-07 17:09:51 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-08-07 17:48:05 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-08-07 17:51:18 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-08-22 16:15:05 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-08-22 16:34:15 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..fe0e171
--- /dev/null
+++ b/test.py
@@ -0,0 +1,13 @@
+def match_string(pattern_list, match_str):
+    for pattern in pattern_list:
+        substrings = pattern.split(',')
+        # 妫�鏌� match_str 鏄惁鍖呭惈姣忎竴涓瓙瀛楃涓�
+        if all(sub in match_str for sub in substrings):
+            return True
+    return False
+
+# 绀轰緥浣跨敤
+pattern_list = ["鍡棷,闂,闅忔椂", "闅忔椂,鎵炬垜"]
+match_str = "鍡棷,鏈変粈涔堜簨鎯呴殢鏃惰仈绯�"
+result = match_string(pattern_list, match_str)
+print(result)  # 杈撳嚭: True
\ No newline at end of file
diff --git a/test_group_stats.py b/test_group_stats.py
deleted file mode 100644
index e4aa7e0..0000000
--- a/test_group_stats.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python3
-"""
-缇ょ粍缁熻鍔熻兘娴嬭瘯鑴氭湰
-"""
-
-import sys
-import os
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-
-from app.services.group_stats_service import group_stats_service
-from config import settings
-
-
-def test_group_stats():
-    """娴嬭瘯缇ょ粍缁熻鍔熻兘"""
-    print("=== 缇ょ粍缁熻鍔熻兘娴嬭瘯 ===\n")
-    
-    # 娴嬭瘯缇ょ粍ID
-    test_group_id = "test_group_123"
-    test_users = ["user1", "user2", "user3"]
-    
-    print(f"1. 娴嬭瘯缇ょ粍: {test_group_id}")
-    print(f"2. 娴嬭瘯鐢ㄦ埛: {test_users}")
-    print(f"3. 榛樿瀹㈡湇鍚嶇О: {settings.customer_service_default_name}")
-    print()
-    
-    # 娓呯┖娴嬭瘯鏁版嵁
-    print("4. 娓呯┖娴嬭瘯鏁版嵁...")
-    group_stats_service.clear_group_stats(test_group_id)
-    print("   娓呯┖瀹屾垚")
-    print()
-    
-    # 娴嬭瘯鍒濆鐘舵��
-    print("5. 娴嬭瘯鍒濆鐘舵��...")
-    initial_stats = group_stats_service.get_group_message_stats(test_group_id)
-    initial_nickname = group_stats_service.get_most_active_user_nickname(test_group_id)
-    print(f"   鍒濆缁熻: {initial_stats}")
-    print(f"   鍒濆鏈�娲昏穬鐢ㄦ埛鏄电О: {initial_nickname}")
-    print()
-    
-    # 妯℃嫙鐢ㄦ埛鍙戣█
-    print("6. 妯℃嫙鐢ㄦ埛鍙戣█...")
-    # user1 鍙戣█ 5 娆�
-    for i in range(5):
-        group_stats_service.increment_user_message_count(test_group_id, test_users[0])
-        print(f"   {test_users[0]} 鍙戣█绗� {i+1} 娆�")
-    
-    # user2 鍙戣█ 3 娆�
-    for i in range(3):
-        group_stats_service.increment_user_message_count(test_group_id, test_users[1])
-        print(f"   {test_users[1]} 鍙戣█绗� {i+1} 娆�")
-    
-    # user3 鍙戣█ 7 娆�
-    for i in range(7):
-        group_stats_service.increment_user_message_count(test_group_id, test_users[2])
-        print(f"   {test_users[2]} 鍙戣█绗� {i+1} 娆�")
-    print()
-    
-    # 鏌ョ湅缁熻缁撴灉
-    print("7. 鏌ョ湅缁熻缁撴灉...")
-    final_stats = group_stats_service.get_group_message_stats(test_group_id)
-    final_nickname = group_stats_service.get_most_active_user_nickname(test_group_id)
-    print(f"   鏈�缁堢粺璁�: {final_stats}")
-    print(f"   鏈�娲昏穬鐢ㄦ埛鏄电О: {final_nickname}")
-    print()
-    
-    # 鑾峰彇缁熻鎽樿
-    print("8. 鑾峰彇缁熻鎽樿...")
-    summary = group_stats_service.get_group_stats_summary(test_group_id)
-    print(f"   缁熻鎽樿: {summary}")
-    print()
-    
-    # 娴嬭瘯鐩稿悓鍙戣█娆℃暟鐨勬儏鍐�
-    print("9. 娴嬭瘯鐩稿悓鍙戣█娆℃暟鐨勬儏鍐�...")
-    test_group_id_2 = "test_group_equal"
-    group_stats_service.clear_group_stats(test_group_id_2)
-    
-    # 涓や釜鐢ㄦ埛閮藉彂瑷� 3 娆�
-    for i in range(3):
-        group_stats_service.increment_user_message_count(test_group_id_2, "equal_user1")
-        group_stats_service.increment_user_message_count(test_group_id_2, "equal_user2")
-    
-    equal_stats = group_stats_service.get_group_message_stats(test_group_id_2)
-    equal_nickname = group_stats_service.get_most_active_user_nickname(test_group_id_2)
-    print(f"   鐩稿悓鍙戣█娆℃暟缁熻: {equal_stats}")
-    print(f"   鐩稿悓鍙戣█娆℃暟鏈�娲昏穬鐢ㄦ埛鏄电О: {equal_nickname}")
-    print()
-    
-    # 娴嬭瘯鏃犲彂瑷�鐨勬儏鍐�
-    print("10. 娴嬭瘯鏃犲彂瑷�鐨勬儏鍐�...")
-    test_group_id_3 = "test_group_empty"
-    group_stats_service.clear_group_stats(test_group_id_3)
-    
-    empty_stats = group_stats_service.get_group_message_stats(test_group_id_3)
-    empty_nickname = group_stats_service.get_most_active_user_nickname(test_group_id_3)
-    print(f"    鏃犲彂瑷�缁熻: {empty_stats}")
-    print(f"    鏃犲彂瑷�鏈�娲昏穬鐢ㄦ埛鏄电О: {empty_nickname}")
-    print()
-    
-    print("=== 娴嬭瘯瀹屾垚 ===")
-
-
-def test_config():
-    """娴嬭瘯閰嶇疆鍔熻兘"""
-    print("=== 閰嶇疆娴嬭瘯 ===\n")
-    
-    print(f"瀹㈡湇鍚嶇О鍒楄〃: {settings.customer_service_names}")
-    print(f"榛樿瀹㈡湇鍚嶇О: {settings.customer_service_default_name}")
-    print()
-
-
-if __name__ == "__main__":
-    try:
-        test_config()
-        test_group_stats()
-    except Exception as e:
-        print(f"娴嬭瘯澶辫触: {str(e)}")
-        import traceback
-        traceback.print_exc()

--
Gitblit v1.9.1