From 6cccac21c5a1cf398e9bd69edc882f32c82512d0 Mon Sep 17 00:00:00 2001 From: --git_token Date: Thu, 25 Jun 2026 08:10:01 +0800 Subject: [PATCH] auto backup 2026-06-25 08:10:01 --- MEMORY.md | 4 +- .../ai_descriptions_feishu_2026-06-23.json | 17 ++ .../ai_descriptions_wechat_2026-06-23.json | 53 +++++ .../cluster_context_2026-06-23.json | 211 ++++++++++++++++++ .../飞书反馈_2026-06-24.xlsx | Bin 0 -> 12034 bytes .../detect_p0_realtime.cpython-312.pyc | Bin 0 -> 24574 bytes .../detect_p0_wechat.cpython-312.pyc | Bin 0 -> 24065 bytes scripts/detect_p0_realtime.py | 109 ++++++++- scripts/detect_p0_wechat.py | 109 ++++++++- 9 files changed, 490 insertions(+), 13 deletions(-) create mode 100644 output/daily_feedback/ai_descriptions_feishu_2026-06-23.json create mode 100644 output/daily_feedback/ai_descriptions_wechat_2026-06-23.json create mode 100644 output/daily_feedback/cluster_context_2026-06-23.json create mode 100644 output/daily_feedback/飞书反馈_2026-06-24.xlsx create mode 100644 scripts/__pycache__/detect_p0_realtime.cpython-312.pyc create mode 100644 scripts/__pycache__/detect_p0_wechat.cpython-312.pyc diff --git a/MEMORY.md b/MEMORY.md index 2c9c727..8492643 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -59,7 +59,7 @@ - 阈值:同小时 + 发送人交集 + 相似度 > 0.20;跨小时 + 发送人 ≥2 重叠 + 相似度 > 0.35 - 影响文件:`detect_p0_wechat.py`、`detect_p0_realtime.py` -### P0 告警问题描述清洗规则(2026-06-22 刘新玉确认) +### P0 告警问题描述清洗规则(2026-06-24 更新) - P0 告警的"问题描述"字段必须经过 `_clean_summary` 清洗,不能直接贴原始消息 - 清洗规则(`detect_p0_wechat.py` / `detect_p0_realtime.py` 的 `_clean_summary` 函数): 1. 去掉 `[聊天记录]` 转发标记 @@ -69,6 +69,8 @@ 5. 去掉 `[视频]`/`[图片]`/`[语音]` 等媒体标记 6. 疑问句→陈述句改写:去掉"这个反馈可以跟用户确认下..."等讨论话术前缀 + 疑问结构 + 句末疑问词;碎片化症状词补全(如 `闪退的` → `用户反馈闪退,需确认操作场景`) - `_pick_best_summary` 优先选非转发/非内部讨论的消息,跳过含 `[聊天记录]`、`↳ 回复`、`` 标记的消息 +- **内部技术讨论过滤(2026-06-24 新增)**:`_is_internal_discussion()` 检测技术术语(hotfix/分支/打包/构建/部署/发版等)+ 讨论话术(不是/我觉得/应该是/你们用/改回来等),匹配后跳过该消息。全部消息均为内部讨论时,`_extract_problem_from_discussion()` 尝试提取用户问题关键词,无法提取则返回通用提示"内部技术讨论中提及问题,需人工确认具体用户反馈内容" +- **内部讨论 P0 不推送(2026-06-24 刘新玉确认)**:簇内全部消息均为内部技术讨论时,直接跳过不推送到「小葵小葵」群,仅记录去重状态避免重复检测 ## 经验教训 diff --git a/output/daily_feedback/ai_descriptions_feishu_2026-06-23.json b/output/daily_feedback/ai_descriptions_feishu_2026-06-23.json new file mode 100644 index 0000000..57d7b73 --- /dev/null +++ b/output/daily_feedback/ai_descriptions_feishu_2026-06-23.json @@ -0,0 +1,17 @@ +{ + "date": "2026-06-23", + "descriptions": [ + { + "index": 1, + "description": "iPad端用户在完成第四单元(L1)口语单元挑战后无法查看正确答案且解析内容与实际题目不符,应用同时频繁闪退。" + }, + { + "index": 2, + "description": "在H5页面的L2级别U10单元巩固题目中,用户提交正确答案却被系统判定为错误。" + }, + { + "index": 3, + "description": "无明确问题" + } + ] +} \ No newline at end of file diff --git a/output/daily_feedback/ai_descriptions_wechat_2026-06-23.json b/output/daily_feedback/ai_descriptions_wechat_2026-06-23.json new file mode 100644 index 0000000..ed949a8 --- /dev/null +++ b/output/daily_feedback/ai_descriptions_wechat_2026-06-23.json @@ -0,0 +1,53 @@ +{ + "date": "2026-06-23", + "descriptions": [ + { + "index": 1, + "description": "用户完成单元挑战" + }, + { + "index": 2, + "description": "瓦拉英语L2级别U10单元巩固题目在单元挑战H5页面中,正确答案被判定为错误。" + }, + { + "index": 3, + "description": "在苹果iPad端的瓦拉app中,语音识别功能出现卡顿和无法识别的问题。" + }, + { + "index": 4, + "description": "用户反馈语音识别时转圈等待时间长且无法成功识别" + }, + { + "index": 5, + "description": "无明确问题" + }, + { + "index": 6, + "description": "用户在启动游戏时一直处相关人员载转圈状态,无法进入游戏,切换网络和卸载重装均未解决。" + }, + { + "index": 7, + "description": "部分用户从昨晚开始无法进入课堂进行学习" + }, + { + "index": 8, + "description": "无明确问题" + }, + { + "index": 9, + "description": "用户无法进入S2的14-4关卡" + }, + { + "index": 10, + "description": "存在资源依相关人员题,需引导用户更新S1资源" + }, + { + "index": 11, + "description": "无明确问题" + }, + { + "index": 12, + "description": "无明确问题" + } + ] +} \ No newline at end of file diff --git a/output/daily_feedback/cluster_context_2026-06-23.json b/output/daily_feedback/cluster_context_2026-06-23.json new file mode 100644 index 0000000..2a0540c --- /dev/null +++ b/output/daily_feedback/cluster_context_2026-06-23.json @@ -0,0 +1,211 @@ +{ + "date": "2026-06-23", + "total_clusters": 3, + "clusters": [ + { + "index": 1, + "_idx": 1, + "cluster_id": "1135459811533962105", + "location": { + "端": "移动端", + "环节": "单元挑战", + "课程": "", + "角色/组件": "网络" + }, + "priority": "P2", + "priority_detail": "", + "category": "启动/运行异常", + "conclusion": "**当前问题排查结论:** 暂无结论排查中", + "messages": [ + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "[聊天记录] 子曦和瓦拉英语-花花班主任(早10晚7)\n子曦: [视频]\n子曦: 花花,做的单元挑战的题,做完之后有错误,怎么看不到答案呢,点击题目解析出来的和今天做的题不一样呢\n子曦: \"咱们用的是什么设备呢?您现在重新安装一下试试,或者是更新一下软件试试\"\n------\n还有关于闪退的问题,刚才孩子在学习的时候又闪退了,我今天刚刚把它卸载又重新安装过了,为什么还是不行呢?\n子曦: [图片]\n子曦: [图片]\n子曦: 我来上班了,手边没有设备,这是我昨天给您录的视频里截出来的两张图片,第一张是刚做的单元挑战的题目,第二张是我点开题目解析后出来的画面,这两道题根本对不上呀\n子曦: \"[视频]\"\n------\n您可以看一下这个视频\n子曦: 主要是有的题目孩子不会,问我呢我也不会,不知道咋办了[捂脸]", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 10:26:29" + }, + { + "sender": "跃馬點煋", + "content": "我跟踪一下这个单元挑战的问题。稍后回复。\n ↳ 回复 瓦拉英语-花花班主任(早10晚7): 子曦和瓦拉英语-花花班主任(早10晚7)1900\n\n\t\n\t\t<![CDATA[@花生第四单元单元挑战,口语部分]]>\n\t\t\n\t\t57\n\t\t\n\t\t\t\n\t\t\t<...", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 10:39:36" + }, + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "@花生一级别\n ↳ 回复 花生: L1还是L2", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 11:26:54" + }, + { + "sender": "跃馬點煋", + "content": "还有用户手机号", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 10:29:10" + }, + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "18603892527用户做完单元挑战题目和解析对应不上,另外说经常闪退", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 10:29:34" + }, + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "[聊天记录] DX17和瓦拉英语-花花班主任(早10晚7)\nDX17: [视频]\nDX17: [视频]\nDX17: \"[视频]\"\n------\n这个怎么都打不开,我还卸载了重新下载的,也还是不行\nDX17: 也不是网络问题,其他的都可以打开,就他", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 10:34:05" + }, + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "15281078450苹果平板,明天说打不开课程,辛苦看下", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 10:34:29" + }, + { + "sender": "花生", + "content": "让用户下一下这个s1的资源\n ↳ 回复 花生: \n\n\t@花生 L2 的5700<...", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 19:20:14" + }, + { + "sender": "一_FVision", + "content": "让用户重新进一下看看", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 11:06:28" + }, + { + "sender": "跃馬點煋", + "content": "这样操作一下\n ↳ 回复 瓦拉场务-糖果果: 让用户重新进一下看看", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 12:02:15" + }, + { + "sender": "跃馬點煋", + "content": "目前,我从服务器日志来看,题目解析服务的请求最晚是:06-22 17:07:57\n也就是说用户从6月22日下午5点08分之后没有请求过题目解析", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 11:10:06" + }, + { + "sender": "瓦拉英语-花花班班(早10晚7-周末休息)", + "content": "@wayne老师,那现在需要家长操作什么吗?可以解决一下\n ↳ 回复 跃馬點煋: 目前,我从服务器日志来看,题目解析服务的请求最晚是:06-22 17:07:57\n也就是说用户从6月22日下午5点08分之后没有请求过题目解析", + "msg_type": "link", + "media_url": "", + "time": "2026-06-23 11:59:42" + } + ] + }, + { + "index": 3, + "_idx": 3, + "cluster_id": "2399062222045209808", + "location": { + "端": "未知", + "环节": "未知", + "课程": "", + "角色/组件": "" + }, + "priority": "P2", + "priority_detail": "", + "category": "其他问题", + "conclusion": "**当前问题排查结论:** 暂无结论排查中", + "messages": [ + { + "sender": "瓦拉英语-益达老师", + "content": "[表情]", + "msg_type": "sticker", + "media_url": "", + "time": "2026-06-23 20:04:09" + }, + { + "sender": "kevin", + "content": "@瓦拉英语-益达老师  一样的资源依赖问题,引导用户更新一下S1 的资源就可以了", + "msg_type": "text", + "media_url": "", + "time": "2026-06-23 20:07:02" + } + ] + } + ] +} \ No newline at end of file diff --git a/output/daily_feedback/飞书反馈_2026-06-24.xlsx b/output/daily_feedback/飞书反馈_2026-06-24.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..dee3d6c783a6cc7a520f4e6d7ced0bb427436aa7 GIT binary patch literal 12034 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 eWB>#EU&=~V0U9*=3G|h7-7QPT&Pq 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 literal 0 HcmV?d00001 diff --git a/scripts/detect_p0_realtime.py b/scripts/detect_p0_realtime.py index 9c41cdd..66517b8 100644 --- a/scripts/detect_p0_realtime.py +++ b/scripts/detect_p0_realtime.py @@ -126,6 +126,79 @@ def is_probably_p0(cluster_msgs): return info["priority"] == "P0", info +# 内部技术讨论特征词(用于检测团队内部讨论而非用户反馈) +_INTERNAL_DISCUSSION_PATTERNS = [ + # 技术术语 + r'hotfix', r'\w+_hf\b', r'分支', r'打包', r'构建', r'部署', r'预发布', + r'测试环境', r'灰度', r'发版', r'上线', r'回滚', r'版本号', + r'master\b', r'develop\b', r'release\b', + # 讨论话术(否定/反问/建议) + r'^(?:不是|不对|不,)', r'我觉得', r'应该是', r'你们(?:用|试|改)', + r'想不改除非', r'需要再改回来', r'是一样的', r'除非你们', + r'这周要更新', r'更新之前', r'改回来', + # 技术操作描述 + r'hotfix打的包', r'分支的内容', r'测试后面的关卡', +] +_INTERNAL_DISCUSSION_RE = re.compile('|'.join(_INTERNAL_DISCUSSION_PATTERNS), re.IGNORECASE) + + +def _is_internal_discussion(text): + """判断消息是否为团队内部技术讨论,而非用户反馈。""" + if not text or len(text) < 5: + return False + # 检查是否匹配内部讨论特征 + if _INTERNAL_DISCUSSION_RE.search(text): + return True + # 消息长度超过 80 字且包含多个技术/讨论特征 → 很可能是内部讨论 + if len(text) > 80: + tech_count = len(re.findall(r'(?:hotfix|分支|打包|构建|部署|测试|版本|上线|发版|回滚|灰度|预发布)', text, re.IGNORECASE)) + discuss_count = len(re.findall(r'(?:不是|不对|我觉得|应该是|你们|我们|改回来|除非|一样的)', text)) + if tech_count >= 2 or discuss_count >= 2 or (tech_count + discuss_count) >= 3: + return True + return False + + +def _extract_problem_from_discussion(text, cluster_msgs=None): + """从内部技术讨论中提取核心问题描述。 + 尝试从讨论中识别用户实际遇到的问题,而非团队的技术分析。 + 无法提取时,归纳讨论主题作为参考。 + """ + # 先尝试从簇中找非内部讨论的消息 + if cluster_msgs: + for m in cluster_msgs: + t = str(m[3]).strip() if m[3] else "" + if t and len(t) > 3 and not _is_internal_discussion(t): + return _clean_summary(t) + + # 从讨论文本中提取问题关键词 + problem_indicators = [ + (r'(?:用户|玩家|有人).{0,10}(?:反馈|说|遇到|出现|发现).{0,30}(?:闪退|崩溃|卡死|卡顿|白屏|黑屏|无法|不能|打不开|进不去|报错|异常)', ''), + (r'(?:闪退|崩溃|卡死|卡顿|白屏|黑屏|无法登录|进不去|打不开|报错|异常|bug|BUG)', ''), + ] + for pat, _ in problem_indicators: + m = re.search(pat, text, re.IGNORECASE) + if m: + extracted = m.group(0) + if len(extracted) > 5: + return f"用户反馈{extracted},需确认影响范围" + + # 无法提取具体问题 → 归纳讨论主题 + topic_map = [ + (r'关卡|解锁|单元|U\d+', '关卡/解锁'), + (r'打包|构建|hotfix|分支|发版|上线|更新', '打包/发版'), + (r'测试|灰度|预发布|交叉测', '测试/灰度'), + (r'配置|后台|服务端|接口', '配置/后台'), + (r'闪退|崩溃|卡死|卡顿|白屏|黑屏', '崩溃/异常'), + (r'加载|转圈|进不去|打不开|无法', '加载/访问'), + ] + topics = [] + for pat, label in topic_map: + if re.search(pat, text, re.IGNORECASE): + topics.append(label) + topic_str = '/'.join(topics[:3]) if topics else '相关' + return f"团队内部讨论{topic_str}问题,需人工确认具体用户反馈内容" + + def _clean_summary(text): """清洗摘要文本,提取核心问题描述(处理转发消息、内部讨论等噪音)。""" # 去掉 [聊天记录] 等转发标记 @@ -188,7 +261,8 @@ def _clean_summary(text): def _pick_best_summary(cluster_msgs): """从簇中选出最能代表 P0 问题的摘要消息。 - 优先选择匹配 P0 关键词且非转发/非内部讨论的消息。""" + 优先选择匹配 P0 关键词且非转发/非内部讨论的消息。 + 内部技术讨论消息会被跳过,优先使用用户原始反馈。""" from priority_classifier import P0_KEYWORDS # 收集所有 P0 关键词正则 @@ -197,27 +271,32 @@ def _pick_best_summary(cluster_msgs): p0_patterns.append(cat_pats) combined_p0 = re.compile('|'.join(p0_patterns), re.IGNORECASE) - # 判断是否为转发消息/内部讨论(包含 [聊天记录]、↳ 回复 等标记) - def _is_forward_or_discussion(t): + # 判断是否为转发消息(包含 [聊天记录]、↳ 回复、XML 标记) + def _is_forward(t): return bool(re.search(r'^\[聊天记录\]|↳\s*回复|| 3 and not _is_internal_discussion(t): + all_internal = False + break + if all_internal: + print(f"[P0-detect] ⏭️ 全部为内部技术讨论,跳过推送") + state[sig] = {"time": datetime.now().isoformat(), "fp": fp} + continue + if args.dry_run: alert = generate_p0_alert_text(cmsgs, info) print(f"[DRY-RUN] 将发送:\n{alert}") diff --git a/scripts/detect_p0_wechat.py b/scripts/detect_p0_wechat.py index 8bb75fc..6d2dcac 100755 --- a/scripts/detect_p0_wechat.py +++ b/scripts/detect_p0_wechat.py @@ -120,6 +120,79 @@ def is_probably_p0(cluster_msgs): return info["priority"] == "P0", info +# 内部技术讨论特征词(用于检测团队内部讨论而非用户反馈) +_INTERNAL_DISCUSSION_PATTERNS = [ + # 技术术语 + r'hotfix', r'\w+_hf\b', r'分支', r'打包', r'构建', r'部署', r'预发布', + r'测试环境', r'灰度', r'发版', r'上线', r'回滚', r'版本号', + r'master\b', r'develop\b', r'release\b', + # 讨论话术(否定/反问/建议) + r'^(?:不是|不对|不,)', r'我觉得', r'应该是', r'你们(?:用|试|改)', + r'想不改除非', r'需要再改回来', r'是一样的', r'除非你们', + r'这周要更新', r'更新之前', r'改回来', + # 技术操作描述 + r'hotfix打的包', r'分支的内容', r'测试后面的关卡', +] +_INTERNAL_DISCUSSION_RE = re.compile('|'.join(_INTERNAL_DISCUSSION_PATTERNS), re.IGNORECASE) + + +def _is_internal_discussion(text): + """判断消息是否为团队内部技术讨论,而非用户反馈。""" + if not text or len(text) < 5: + return False + # 检查是否匹配内部讨论特征 + if _INTERNAL_DISCUSSION_RE.search(text): + return True + # 消息长度超过 80 字且包含多个技术/讨论特征 → 很可能是内部讨论 + if len(text) > 80: + tech_count = len(re.findall(r'(?:hotfix|分支|打包|构建|部署|测试|版本|上线|发版|回滚|灰度|预发布)', text, re.IGNORECASE)) + discuss_count = len(re.findall(r'(?:不是|不对|我觉得|应该是|你们|我们|改回来|除非|一样的)', text)) + if tech_count >= 2 or discuss_count >= 2 or (tech_count + discuss_count) >= 3: + return True + return False + + +def _extract_problem_from_discussion(text, cluster_msgs=None): + """从内部技术讨论中提取核心问题描述。 + 尝试从讨论中识别用户实际遇到的问题,而非团队的技术分析。 + 无法提取时,归纳讨论主题作为参考。 + """ + # 先尝试从簇中找非内部讨论的消息 + if cluster_msgs: + for m in cluster_msgs: + t = str(m[3]).strip() if m[3] else "" + if t and len(t) > 3 and not _is_internal_discussion(t): + return _clean_summary(t) + + # 从讨论文本中提取问题关键词 + problem_indicators = [ + (r'(?:用户|玩家|有人).{0,10}(?:反馈|说|遇到|出现|发现).{0,30}(?:闪退|崩溃|卡死|卡顿|白屏|黑屏|无法|不能|打不开|进不去|报错|异常)', ''), + (r'(?:闪退|崩溃|卡死|卡顿|白屏|黑屏|无法登录|进不去|打不开|报错|异常|bug|BUG)', ''), + ] + for pat, _ in problem_indicators: + m = re.search(pat, text, re.IGNORECASE) + if m: + extracted = m.group(0) + if len(extracted) > 5: + return f"用户反馈{extracted},需确认影响范围" + + # 无法提取具体问题 → 归纳讨论主题 + topic_map = [ + (r'关卡|解锁|单元|U\d+', '关卡/解锁'), + (r'打包|构建|hotfix|分支|发版|上线|更新', '打包/发版'), + (r'测试|灰度|预发布|交叉测', '测试/灰度'), + (r'配置|后台|服务端|接口', '配置/后台'), + (r'闪退|崩溃|卡死|卡顿|白屏|黑屏', '崩溃/异常'), + (r'加载|转圈|进不去|打不开|无法', '加载/访问'), + ] + topics = [] + for pat, label in topic_map: + if re.search(pat, text, re.IGNORECASE): + topics.append(label) + topic_str = '/'.join(topics[:3]) if topics else '相关' + return f"团队内部讨论{topic_str}问题,需人工确认具体用户反馈内容" + + def _clean_summary(text): """清洗摘要文本,提取核心问题描述(处理转发消息、内部讨论等噪音)。""" # 去掉 [聊天记录] 等转发标记 @@ -182,7 +255,8 @@ def _clean_summary(text): def _pick_best_summary(cluster_msgs): """从簇中选出最能代表 P0 问题的摘要消息。 - 优先选择匹配 P0 关键词且非转发/非内部讨论的消息。""" + 优先选择匹配 P0 关键词且非转发/非内部讨论的消息。 + 内部技术讨论消息会被跳过,优先使用用户原始反馈。""" from priority_classifier import P0_KEYWORDS # 收集所有 P0 关键词正则 @@ -191,27 +265,32 @@ def _pick_best_summary(cluster_msgs): p0_patterns.append(cat_pats) combined_p0 = re.compile('|'.join(p0_patterns), re.IGNORECASE) - # 判断是否为转发消息/内部讨论(包含 [聊天记录]、↳ 回复 等标记) - def _is_forward_or_discussion(t): + # 判断是否为转发消息(包含 [聊天记录]、↳ 回复、XML 标记) + def _is_forward(t): return bool(re.search(r'^\[聊天记录\]|↳\s*回复|| 3 and not _is_internal_discussion(t): + all_internal = False + break + if all_internal: + print(f"[P0-wechat] ⏭️ 全部为内部技术讨论,跳过推送") + state[sig] = {"time": datetime.now().isoformat(), "fp": fp} + continue + if args.dry_run: alert = generate_p0_alert_text(cmsgs, info) print(f"[DRY-RUN] 将发送:\n{alert}")