Files
kefu/wechat_rpa/reply_session_policy.py
T
2026-09-21 10:34:06 +08:00

64 lines
2.7 KiB
Python

"""Reply eligibility from session identity only, never from message contents."""
import re
import unicodedata
APPLICATION_REASON = '企小码系统会话不参与自动回复,已跳过'
GROUP_REASON = '群聊不参与自动回复,已跳过'
APPLICATION_NAMES = frozenset({'企小码', '企小码会话', '企小码会话管理', '企小碼', '企小碼會話管理'})
GROUP_KINDS = frozenset({'group', 'group_chat', 'groupchat', 'chatroom', 'room', '群聊', '群会话'})
def normalize_session_name(value):
value = unicodedata.normalize('NFKC', str(value or ''))
return re.sub(r'[\s\u200b-\u200d\ufeff]+', '', value).strip()
def _true(value):
return value is True or value == 1 or isinstance(value, str) and value.strip().lower() in {'true', '1', 'yes'}
def excluded_session_reason(name='', conv_id='', metadata=None):
"""Only inspect recognized metadata keys. Free text is intentionally ignored."""
metadata = metadata if isinstance(metadata, dict) else {}
records = [metadata]
# Persisted visual DB identities are nested; do not recurse into messages.
event = metadata.get('database_event')
if isinstance(event, dict):
records.append(event)
names = [name]
ids = [conv_id]
for record in records:
names.extend(record.get(key) for key in ('display_name', 'conv_name', 'conversation_name', 'session_name'))
ids.extend(record.get(key) for key in ('conv_id', 'conversation_id', 'conversationId'))
if any(normalize_session_name(value) in APPLICATION_NAMES for value in names if value):
return APPLICATION_REASON
for value in ids:
value = str(value or '').strip()
if value.upper().startswith('R:') or value.lower().endswith('@chatroom'):
return GROUP_REASON
for record in records:
if any(_true(record.get(key)) for key in ('is_group', 'is_group_chat', 'isGroup')):
return GROUP_REASON
for key in ('kind', 'chat_type', 'conversation_type', 'session_type'):
if str(record.get(key) or '').strip().lower() in GROUP_KINDS:
return GROUP_REASON
return ''
def visual_group_title_reason(title, name=''):
"""Match a member count added to the opened title, not a row unread badge.
A personal nickname ending in '(2)' appears unchanged in the list and title;
it is not a group. Bare numeric counts require a separately known base name.
"""
title = normalize_session_name(title)
name = normalize_session_name(name)
if not title or '@' in title or name == title:
return ''
match = re.fullmatch(r'(.+?)\(([0-9]{1,6})(人|位成员|成员)?\)', title)
if not match or int(match[2]) < 2:
return ''
if match[3] or name and match[1] == name:
return GROUP_REASON
return ''