This commit is contained in:
Your Name
2026-07-29 09:34:02 +08:00
parent 0ff8943ee2
commit f913a57529
54 changed files with 2453 additions and 378 deletions
+120
View File
@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
"""自动回复短句净化、验证页识别与发送节流测试。"""
from collections import deque
from unittest import TestCase, main, mock
import numpy as np
from ai_chat import (
_dify_query_from_chat,
_history_messages,
_humanize,
_repair_obvious_mismatch,
latest_customer_message,
)
from wechat_bot import WeChatBot, looks_like_security_verification
class ReplyStyleTest(TestCase):
CHAT_SAMPLE = (
"高兴亮 7/28 15:54:54\n"
"抱歉刚才说得太复杂了,就是让您多休息,别太累着\n"
"一个小迷糊@微信@微信联系人 7/28 15:55:08\n"
"你多大了"
)
def test_removes_markdown_canned_closing_and_extra_questions(self):
reply = _humanize(
"### 回复\n"
"1. 您好,先别太着急,今天血糖大概多少?\n"
"2. 是空腹还是餐后测的?\n"
"3. 希望以上建议能帮到您。"
)
self.assertNotIn("###", reply)
self.assertNotIn("希望以上建议能帮到您", reply)
self.assertNotIn("您好", reply)
self.assertEqual(reply.count("") + reply.count("?"), 1)
self.assertLessEqual(len(reply), 100)
def test_emergency_reply_keeps_three_short_sentences(self):
reply = _humanize("先别慌。现在立即拨打120。不要自己开车。之后再联系我。")
self.assertIn("120", reply)
self.assertIn("不要自己开车", reply)
self.assertNotIn("之后再联系我", reply)
def test_extracts_the_real_latest_customer_sentence(self):
self.assertEqual(latest_customer_message(self.CHAT_SAMPLE), "你多大了")
def test_old_raw_history_does_not_relabel_staff_reply_as_customer(self):
with mock.patch("ai_chat.ai_config.AI_CONTEXT_ENABLED", True):
messages = _history_messages([
{"role": "user", "content": self.CHAT_SAMPLE},
{"role": "assistant", "content": "四十来岁啦。"},
])
self.assertEqual(messages[0]["content"], "你多大了")
def test_age_question_mismatch_is_repaired(self):
reply = _repair_obvious_mismatch(
"您别管我多大,把身体养好才是正经事。",
self.CHAT_SAMPLE,
)
self.assertEqual(reply, "四十来岁啦,怎么突然问这个?")
def test_casual_tired_message_is_not_redirected_to_hospital(self):
reply = _repair_obvious_mismatch(
"血糖波动会让人乏力,建议去医院让医生调整方案。",
"一个小迷糊 7/28 14:55:43\n好困啊",
)
self.assertEqual(reply, "困了就先眯一会儿,别硬撑着。")
def test_dify_query_marks_latest_message_as_only_target(self):
query = _dify_query_from_chat(self.CHAT_SAMPLE, history=[])
self.assertIn("【本轮是日常闲聊】", query)
self.assertIn("【客户最后一句|唯一回答对象】\n你多大了", query)
def test_clarification_does_not_ask_customer_to_repeat(self):
reply = _repair_obvious_mismatch(
"刚才没听清,您能再说一遍吗?",
"测试客户 7/28 15:54:46\n什么",
history=[
{"role": "user", "content": "好困啊"},
{"role": "assistant", "content": "困了就先眯一会儿,别硬撑着。"},
],
)
self.assertEqual(reply, "我是说,困了就先眯一会儿,别硬撑着。")
class SafetyGateTest(TestCase):
@staticmethod
def _verification_surface(with_nav=False):
image = np.full((1000, 1600, 4), 245, dtype=np.uint8)
image[:, :, 3] = 255
if with_nav:
image[80:920, :96, :3] = 45
for y in range(380, 620, 8):
for x in range(680, 920, 8):
if ((x - 680) // 8 + (y - 380) // 8) % 2 == 0:
image[y:y + 8, x:x + 8, :3] = 15
return image
def test_qr_page_without_main_navigation_is_blocked(self):
self.assertTrue(
looks_like_security_verification(self._verification_surface())
)
def test_normal_navigation_prevents_false_positive(self):
self.assertFalse(
looks_like_security_verification(self._verification_surface(with_nav=True))
)
def test_minimum_send_interval_is_enforced(self):
bot = WeChatBot.__new__(WeChatBot)
bot._send_timestamps = deque([95.0])
bot._last_send_ts = 95.0
with mock.patch("wechat_bot.time.monotonic", return_value=100.0):
self.assertAlmostEqual(bot._send_gate_remaining(), 3.0)
if __name__ == "__main__":
main()