10 KiB
name, description, version, tags
| name | description | version | tags | |||
|---|---|---|---|---|---|---|
| wecom-file-receive | 通过企业微信接收文件并对接现有工作流(合同审查、文件处理等)。企微群里文件无法同时@人,需要用户引用文件消息后@小Maggie触发。 | 1.0.0 |
|
企业微信文件接收与处理
触发条件
- 用户在企微群里发送文件后,引用该文件消息并@小Maggie
- 收到的消息中包含文档附件(saved at路径)
文件接收机制
用户操作方式
- 用户在企微群里直接发送文件(此时无法同时@人,小Maggie收不到)
- 用户回复那条文件消息并@小Maggie(如"@小Maggie 审查这个合同")
- 网关从引用消息(quote)中提取文件的url和aeskey,下载并AES解密后保存到本地
文件保存位置
- 自动保存到
~/.hermes/cache/documents/目录 - 文件名格式:
doc_<hash>_<原始文件名> - 消息中会显示
The file is saved at: <完整路径>
支持的文件类型
- 文档:.docx, .doc, .pdf, .xlsx, .xls
- 图片:.jpg, .png, .gif, .webp
- 其他:任意文件类型均可接收
收到文件后的通知规则
群里收到的文件
在同一个群里回复确认收到,列出文件名和发送人。
私信收到的文件
不要主动往群里推送通知。 在私信里回复确认收到即可。如需通知群里的人,等群里有新的@消息时顺便汇报,或私信相关人员。
⚠️ 为什么不主动推群消息(铁律)
企微 AI Bot 不能用 APP_CMD_SEND 主动发群消息,Hermes 底层会复用旧的 inbound req_id 通过 APP_CMD_RESPONSE 发送。这种"拿过期会话凭证推送非用户发起的消息"的行为有风险:
- 可能触发企微服务端风控/限流
- 短时间频繁重启后叠加此行为,曾导致部分用户的群@消息不再被推送(2026-06-08事件)
- sender 解析可能变成 "unknown",发出不专业的消息
- 2026-06-09 Doro明确指令:"不要往群里发消息,已经触发风险机制了"
auto_notify_new_file.sh 守护进程也遵守此规则——只走 notify_doro(私信),不调 notify_group。详见 uwf skill。
⚠️ get_sender() 发件人检测不可靠
auto_notify_new_file.sh 中的 get_sender() 函数查 sessions 表最近5分钟的最后一个 session 的 user_id,经常误判(如邱律师的文件被识别为WeiWei)。准确确认发件人的方法是查 messages 表:
SELECT s.user_id, m.content FROM messages m
JOIN sessions s ON m.session_id = s.id
WHERE m.content LIKE '%sent a document%文件名关键词%'
ORDER BY m.timestamp DESC LIMIT 3
通知方式选择
- 群里收到的文件 → 在同一个群里回复通知(这是正常的回复,有 reply_req_id)
- 私信收到的文件 → 私信 Doro 通知,不要主动往群里推。原因:AI Bot 不能 APP_CMD_SEND 主动发群消息,Hermes 靠复用旧 req_id 的 APP_CMD_RESPONSE 发送——旧 req_id 可能已过期,且频繁对过期 req_id 发消息可能被企微风控
邱律师(QiuTing)的合同:收到就开干
邱律师私信发的合同文件(.docx/.doc/.pdf),收到后不问处理方式,直接执行全流程:
- 私信回复邱律师确认收到文件
- 上传Nextcloud待审查目录
- 启动review-contract workflow(
setsid后台运行) - workflow全链路自动跑完(含final_review)
- 小Maggie作为总负责人做终审质检——发现问题自己修,确认无误才通知Doro
- 终审通过→更新合同审查清单.xlsx→上传Nextcloud→私信Doro(简洁格式:
任务交付/【修】xxx.docx)
⚠️ 总负责人原则(Doro 2026-06-08确立):Doro看到的必须是终审确认无误的。workflow的final_review只是机器检查,真正的终审是小Maggie的判断。
⚠️ 全程走Doro私信通知,不发群消息。
其他人的文件:通知后等指示
Doro、洪总等其他人发的文件,私信Doro汇报后等Doro指示再处理。
通知方法(私信Doro):
使用 send_message(target='wecom:doro', message='...') 即可。
处理流程
场景一:合同审查
用户发文件并说"审查这个合同"时:
- 从消息中获取文件保存路径
- 将文件复制到 Nextcloud 待审查目录:
docker cp <本地文件> nextcloud-nextcloud-1:/var/www/html/data/doro/files/Doro合同审查任务/待审查/<原始文件名> docker exec nextcloud-nextcloud-1 chown www-data:www-data <目标路径> docker exec -u www-data nextcloud-nextcloud-1 php occ files:scan doro --path='/doro/files/Doro合同审查任务/待审查/' - 按现有合同审查workflow执行(加载contract-reviewer + contract-editor skill)
- 完成后交付到任务交付目录
场景二:文件提取/处理
用户发文件并要求提取内容、翻译、格式转换等:
- 从消息中获取文件保存路径
- 直接在本地处理(读取docx/pdf内容、提取表格等)
- 按用户指示输出结果(生成新文件、上传到指定目录等)
场景三:文件转存
用户发文件并要求存到某个目录:
- 从消息中获取文件保存路径
- docker cp 到 Nextcloud 指定目录
- chown + occ files:scan 同步
文件不在cache——检查Nextcloud直传
当用户说"我上传了XX文件"但 ~/.hermes/cache/documents/ 里没有时,文件可能是通过Nextcloud网页/客户端直接上传的(不经过企微)。
排查步骤
- 先扫描Nextcloud刷新文件索引:
sudo docker exec nextcloud-nextcloud-1 php occ files:scan doro --path="/doro/files/<预期目录>" - 按文件名关键词搜索整个Doro目录树:
sudo docker exec nextcloud-nextcloud-1 bash -c 'find /var/www/html/data/doro/files/ -name "*关键词*"' - 检查
.part文件——Nextcloud分块上传的临时文件:sudo docker exec nextcloud-nextcloud-1 bash -c 'find /var/www/html/data/doro/files/ -name "*.part"'- 文件名格式:
<hash>.ocTransferId<number>.part .part文件存在 = 上传正在进行中- 大小在增长 = 还在传,等它完成
.part消失且没有新文件出现 = 上传失败/取消,通知用户重新上传
- 文件名格式:
⚠️ 注意事项
.part文件不会被occ files:scan发现(Nextcloud不索引临时文件),必须用find直接查文件系统- 大文件上传可能很慢(通过Nextcloud网页上传取决于用户网速),不要过早判断失败
- 上传失败时
.part文件会被Nextcloud自动清理,不留痕迹 - 确认上传失败后,告知用户"文件上传似乎中断了,请重新上传"
文件名处理
- cache中的文件名经过URL编码,需要解码还原原始文件名
- 上传到Nextcloud时使用原始文件名(从消息中提取)
- 遵循文件命名规则skill(file-naming-convention)
注意事项
- 企微群文件限制:文件消息无法同时@人,必须通过引用回复触发
- URL有效期:企微文件下载URL有效期约5分钟,网关收到后立即下载,不存在过期问题
- AES加密:企微文件传输经过AES加密,网关自动解密(已修复base64 padding问题)
- 图片也支持:图片同样通过引用回复方式接收,保存到cache/images/目录
审计:统计某天某人发了多少文件
当Doro问"邱律师昨天发了多少合同"时,不能靠Nextcloud文件时间戳或cache/documents/时间戳。原因:
- Nextcloud待审查目录的文件是小Maggie上传的,时间是上传时间不是接收时间
- 有些文件是更早期的积压件(如班组慰问品、夏阳代建在6月5日就在Nextcloud了)
- cache/documents/文件可能已被清理
方法1:查Nextcloud数据库(最可靠)
直接查MariaDB获取精确的存入时间和操作人。详见 references/nextcloud-db-queries.md。
# 查文件存入时间
docker exec nextcloud-db-1 mariadb -u nextcloud -p'Nc2026Db!Szw' nextcloud \
-e "SELECT fileid, path, FROM_UNIXTIME(storage_mtime) as stored_utc FROM oc_filecache WHERE path LIKE '%关键词%';"
# 查是谁上传的(仅限通过Nextcloud UI上传的文件)
docker exec nextcloud-db-1 mariadb -u nextcloud -p'Nc2026Db!Szw' nextcloud \
-e "SELECT FROM_UNIXTIME(timestamp) as time_utc, user, subject, file FROM oc_activity WHERE file LIKE '%关键词%';"
⚠️ docker cp + occ files:scan 上传的文件不会产生 oc_activity 记录。无记录=自动流程上传。
方法2:查gateway日志中的接收确认记录
# 北京时间6月8日 = UTC Jun 7 16:00 ~ Jun 8 16:00
journalctl --user -u hermes-gateway \
--since "2026-06-07 16:00:00" --until "2026-06-08 16:00:00" \
| grep "收到邱律师私信发来\|邱律师好.*文件已收到"
每条匹配 = 一次文件接收。注意:
- 同一份合同可能发了多次(如复达合同发了2次),要区分"文件发送次数"和"不同合同数"
- 时区转换:服务器UTC,Doro问的是北京时间,必须先转换再查
- 不要把上传/审查/交付时间当成接收时间
教训(2026-06-09)
Doro问"邱律师昨天发了多少合同",小Maggie第一次回答5份(基于Nextcloud文件时间戳),被Doro纠正。查gateway日志后确认是6次文件发送、5份不同合同。
Gateway断开期间的文件恢复
问题:企微WebSocket断开期间,私信文件消息收不到。
症状:journalctl --user -u hermes-gateway | grep "WeCom.*websocket.*closed"
恢复方法:
- 重启gateway:
systemctl --user restart hermes-gateway - WebSocket重连后,企微服务端通常会重新推送断开期间的消息(但不100%可靠)
- 重启后检查cache/documents/是否有新文件到达
- 如果文件没补回来,检查Nextcloud待审查目录是否已有同名文件(可能之前session已上传)
- 都没有→私信邱律师:"合同X的文件未收到,请重新发送"
预防:cron每15分钟检查WebSocket健康,发现断开及时重启,缩短丢消息窗口。
needs_clarification处理(问邱律师,不问Doro)
当classifier无法判断顾问单位(如甲方信息空白)返回needs_clarification时:
- 私信邱律师询问:"合同X甲方信息空白,请确认甲方单位"
- 不问Doro——Doro是最终确认人,不应被拉进执行环节
- 邱律师回复后,带补充信息创建新thread重新跑
- 同时跳过该合同,继续处理其他排队的合同