Files
kefu/deploy/recognition-audit-20260916/fix_protocol_database_boundaries.py
T
2026-09-21 10:34:06 +08:00

90 lines
4.4 KiB
Python

from pathlib import Path
import hashlib
import json
import shutil
audit=Path(__file__).resolve().parent
changes=[]
for root in (Path('C:/wechat_rpa'),Path('C:/kefu/wechat_rpa')):
path=root/'wxwork_db.py'
before=path.read_bytes()
text=path.read_text(encoding='utf-8')
old=''' try:
send_time = float(send_time)
except (TypeError, ValueError):
return None
if send_time > 10 ** 12:
send_time /= 1000.0
if send_time <= 0:
return None
'''
new=''' try:
send_time = float(send_time)
if send_time > 10 ** 12:
send_time /= 1000.0
if not math.isfinite(send_time) or send_time <= 0:
return None
# Context rendering uses local datetime conversion. Reject corrupt
# rows here so neither polling order nor later formatting can crash.
datetime.fromtimestamp(send_time)
except (TypeError, ValueError, OverflowError, OSError):
return None
'''
assert text.count(old)==1
assert 'import math\n' not in text
text=text.replace('import json\n','import json\nimport math\n',1).replace(old,new)
backup=root/'backups/recognition-audit-20260916'/path.name
backup.parent.mkdir(parents=True,exist_ok=True)
assert not backup.exists()
backup.write_bytes(before)
path.write_text(text,encoding='utf-8')
shutil.copy2(audit/'test_database_timestamp_audit.py',root/'test_database_timestamp_audit.py')
changes.append({'path':str(path),'backup':str(backup),'before_sha256':hashlib.sha256(before).hexdigest(),'after_sha256':hashlib.sha256(path.read_bytes()).hexdigest()})
path=Path('C:/wechat_rpa/protocol_engine.py')
before=path.read_bytes()
text=path.read_text(encoding='utf-8')
old='''def _unanswered_requires_manual(context):
# A text caption after an image/voice is still a media question. Only inspect
# the unanswered batch: media already handled by a human must not block later text.
for message in reversed((context or {}).get('messages') or []):
if message.get('is_self'):break
if not _is_text_message(message):return True
return False
'''
new='''def _unanswered_manual_reason(context):
# A text caption after media is still a media question. Human replies and
# restored-contact notices separate the current batch from old history.
count=0
for message in reversed((context or {}).get('messages') or []):
if message.get('is_self') or system_contact_status(message)=='restored':break
count+=1
if not _is_text_message(message):return '当前未回复消息包含图片、语音或其他非文本内容,协议版需人工处理'
if count>100:return '连续未回复消息超过 100 条,无法保证问题完整,请人工处理后继续'
return ''
'''
assert text.count(old)==1
text=text.replace(old,new)
old=''' context=self.db.get_conversation_context_by_id(self.account,state['conv_id'],limit=100)
if not _is_text_message(state) or _unanswered_requires_manual(context):
with self._lock:state.update(reply_text='',staged_reply_text='',approved=False,awaiting_review=False)
self._stage(key,'error','此消息类型需要人工处理','当前未回复消息包含图片、语音或其他非文本内容,协议版需人工处理');return
'''
new=''' # One extra row detects a current customer batch cut by the 100-message window.
context=self.db.get_conversation_context_by_id(self.account,state['conv_id'],limit=101)
manual_reason=_unanswered_manual_reason(context)
if not _is_text_message(state):manual_reason=manual_reason or '当前协议版只自动处理文本消息'
if manual_reason:
with self._lock:state.update(reply_text='',staged_reply_text='',approved=False,awaiting_review=False)
self._stage(key,'error','当前消息需要人工处理',manual_reason);return
'''
assert text.count(old)==1
text=text.replace(old,new)
backup=path.parent/'backups/recognition-audit-20260916/protocol_engine.media-fix.py'
assert not backup.exists()
backup.write_bytes(before)
path.write_text(text,encoding='utf-8')
changes.append({'path':str(path),'backup':str(backup),'before_sha256':hashlib.sha256(before).hexdigest(),'after_sha256':hashlib.sha256(path.read_bytes()).hexdigest()})
(audit/'protocol-database-fix-manifest.json').write_text(json.dumps(changes,indent=2),encoding='utf-8')
print(json.dumps(changes))