一个 FkWeChat 插件:长按任意微信消息 → 调用 TypeSafe Jev 判定模型 → 几秒后在屏幕上弹出结论。不发任何消息、不改聊天记录,对方完全不知道。
① 意图:打招呼或闲聊 85%
情绪:平静 56% · 客套 42% · 着急 2%
② 着急:不着急 · 0.48/3
③ 建议:正常交流 90%
用途:对方这句话到底什么意思?该用什么姿态回?——判定用的,不是自动回复机器人。
⚡ v1.9 起基本是"点完就出":长按弹出的那一刻就开始算(预判),你点中「意图」时结果通常已经回来了 —— 实测冷启动第一次 1144ms → 9ms。数字和做法都在下面《有多快》。
🔗 姊妹项目:旁观者 · JevBystander —— 同一个判定口径的安卓无障碍版:不用 root / 不用 Xposed,只读屏 + 固定 3 条 Toast。 装不了 LSPosed、或者怕 hook 微信的话用它;两套实现完全独立,同一台手机也能共存。 (代价:无障碍版只看得到屏幕上已显示的文字)
| ✅ 做 | ❌ 不做 |
|---|---|
| 意图判定(10 格):闲聊 / 问情况 / 求办事 / 催进度 / 推销 / 投诉 / 通知 / 吐槽 / 邀约 … | 不生成回复文案(Jev 模型只做判定,不出自由文本) |
| 情绪判定(9 格):平静 / 高兴 / 不满 / 生气 / 焦虑 / 着急 / 难过 / 讽刺 / 客套,带概率分布前 3 名 | 不自动回复、不代发消息 |
| 着急程度(4 档 + 0~3 分) | 不做本地推理(消息会发到你自己的 API key 对应的服务) |
| 回复姿态(11 格):调侃 / 正常 / 客套 / 赞赏 / 关心 / 共情 / 同情 / 安抚道歉 / 问细节 / 婉拒 / 暂不回 | |
| 附送:是否等你回复、风险高低、应对动作 | |
| 关系感知:同事 / 客户 / 情侣 / 死党… 同一句话结论完全不同 |
-
手机装好 FkWeChat(LSPosed 模块)并在宿主里开启插件支持。
-
把这个目录里的
main.java、info.prop拷到:/storage/emulated/0/Android/media/com.tencent.mm/FkWeChat/Plugin/JevIntent/ -
填你自己的 TypeSafe/Jev key(没有 key?看
docs/如何获取API密钥.md,免费,1 分钟)。两种填法任选:- 改
config.properties:把config.example.properties复制成config.properties(同一目录),写api_key=apikey_你的key - 不改文件:等插件第一次长按生成了
设置.properties,直接在最上面的 【1】接口密钥 后面写apikey_你的key(两边都填以设置.properties为准;那边留空就回落到config.properties)
- 改
-
插件管理器里启用并重载(或重启微信)→ 看到 Toast「JevIntent 就绪 v1.9」就成功了。
-
在任意聊天里长按一条文本消息(引用回复的消息也支持)→ 菜单出现「意图」。
⚠️ 仓库里不含任何密钥。config.properties、设置.properties、presets.properties都是本地文件,已写进.gitignore。
长按消息 → 菜单只有两项:
| 菜单项 | 作用 |
|---|---|
| 意图 | 分析这条消息,结果按固定 3 条弹出 |
| 关系=普通朋友 | 点一下循环切换本会话的关系(10 档),按会话分别记忆 |
关系是「每个会话一个」(同事群和女朋友可以是两套结论),所以放不进全局设置文件,用这个菜单项切。
| 现象 | 含义 |
|---|---|
| 重载后 Toast 「JevIntent 就绪 v1.9」 | 插件加载成功 ✅ |
| 长按消息没有「意图」 | 插件没加载 / 没配 key / 这条不是文本消息(图片语音视频不给菜单) |
| 点「意图」后 Toast「还没读到 api_key」 | 去 设置.properties 的【1】接口密钥 或 config.properties 填 key |
长按任意文本消息(引用回复的也支持)→ 菜单弹出,只有两项:
意图
关系=普通朋友 ← 标题就是这个会话「当前的关系」
点一下「关系=普通朋友」→ 立刻 Toast 「本会话关系 → 陌生人」,菜单标题同步变。 循环顺序:普通朋友 → 陌生人 → 家人 → 情侣 → 死党 → 同事 → 客户 → 领导 → 同学 → 网友 → 回到普通朋友。
按会话分别记:跟同事聊和跟女朋友聊是两套结论,互不影响(存在 presets.properties)。
关系影响有多大?同一句「我爱你」—— 情侣 = 高兴 94% / 建议肯定赞赏;同事 = 高兴 56% + 讽刺 34% / 建议温和婉拒。
[立即] Toast:Jev 分析中… ← 可在设置里关掉
[3~10 秒] Toast:意图:打招呼或闲聊 85%
情绪:平静 56% · 客套 42% · 着急 2%
[+2 秒] Toast:着急:不着急 · 0.48/3
[+2 秒] Toast:建议:正常交流 90%
默认 结果方式=A:全程只在本机弹提示,一条消息都不发,对方完全不知道。
失败也会明说(Jev 失败:Read timed out 之类),不会静默。
把「结果方式」改成 B 引用回复 / C 直接发消息,结果会作为真实消息发进聊天(对方能看到), 适合"发给自己小号当备忘"这类玩法,慎用。
.../FkWeChat/Plugin/JevIntent/
├── main.java 插件本体(你放进去的)
├── info.prop 插件信息
├── config.properties 你的 key(可选,也可以填在设置文件里)
├── 设置.properties ← 第一次长按后自动生成:所有开关都在这里改
└── presets.properties ← 每个会话的关系/性别记在这
打开 设置.properties,把想要的那项等号后面的字母改掉(例:情绪条数=C),保存。
下次长按即时生效,不用重载插件、不用改代码。字母写错也不会崩(自动取第一个选项)。
| 情况 | 处理 |
|---|---|
| 结论明显不像这个关系说的 | 先确认菜单标题里的关系对不对(点它循环切换) |
| 看不出上下文 | 设置里 上下文句数 调到 C/D(5 句 / 7 句) |
| 情绪第一名只有 30% 多 | 说明模型也拿不准 —— 这时候看前三名,别只看第一 |
| 嫌弹 4 次(含"分析中…") | 设置里 分析中提示=B,就只剩 3 条 |
| 引用气泡空白 | 设置里 引用块字段=B(des) |
第一次长按后会自动生成 设置.properties(和 main.java 同目录,带完整中文注释)。
改等号后面的字母 → 保存 → 长按消息立即生效(不用重载插件、不用改代码)。
这个文件永远不会被自动覆盖,删掉它下次长按会重新生成一份。
生成出来长这样:
# 【1】情绪条数
# A. 只显示 1 条
# B. 显示 3 条
# C. 显示 5 条
情绪条数=B| 文件里的项 | 怎么填 | 默认 |
|---|---|---|
| 接口密钥 | 直接写 apikey_xxx 整串(不是 A/B/C);留空则用 config.properties |
空 |
| 情绪条数 | A 1条 / B 3条 / C 5条 | B |
| 附带老四项 | A 显示(待回复/风险/应对)/ B 不显示 | A |
| 结果方式 | A 只弹提示(对方看不到)/ B 引用回复 / C 直接发消息 | A |
| 提示间隔 | A 2000ms / B 1200ms / C 3000ms | A |
| 上下文句数 | A 不带 / B 3句 / C 5句 / D 7句 | B |
| 分析中提示 | A 显示「分析中…」/ B 不显示 | A |
| 只看文本消息 | A 是 / B 所有消息都挂菜单 | A |
| 引用块字段 | A title / B des(引用气泡空白时改这个) | A |
| 模型 | A jev-latest / B 固定 jev-1.13.0 | A |
| 预判 | A 开(长按就开始算,点「意图」秒出)/ B 关(省调用) | A |
| 结果缓存 | A 开(同一条消息再看秒回)/ B 关 | A |
| 耗时日志 | A 日志带耗时 / B 不打 | A |
| 默认关系 | A 普通朋友 / B 同事 / C 客户 / D 家人 / E 死党 / F 陌生人 / G 领导 / H 同学 | A |
| 默认性别 | A 未知 / B 男 / C 女 | A |
字母写错(比如写
Z)不会崩,自动取第一个选项,日志里会记一行。
先把延迟拆开量了一遍(同一台 PC、同一个真接口、同样的 7 个问题):
| 花在哪 | 实测 |
|---|---|
| 客户端建连接(DNS+TCP+TLS,连接池冷) | 830~873ms(只有冷启动这一次) |
| 客户端建连接(复用已有连接) | 9~14ms |
| 服务端算完(首字节) | 250~330ms ← 唯一的大头 |
| 服务端抖动时的尖刺 | 1.5~1.8s(约 3% 概率) |
顺手证伪了两件事,省得白折腾:
- 砍问题不省时间:只问 3 题(意图/情绪/姿态)TTFB 283
314ms,问满 7 题 291295ms —— 基本没差。 - 省握手没用:TLS 会话复用已经生效,连接复用时握手只要 9ms,省不出东西。
真正有用的是把等待藏起来。v1.9 三件套:
| 改动 | 效果(实测) |
|---|---|
| 预判:长按弹出菜单那一刻就把请求发出去 | 冷启动第一次:1144ms → 点「意图」只等 9ms |
连接复用:成功后不再 disconnect() |
第二次起握手 873ms → 14ms |
| 结果缓存:同一条消息再看一眼直接秒回 | 第二次 0ms、0 次接口调用(上限 40 条) |
| 拿不到答案时的重试等待 600ms → 120ms | 最坏情况少等 480ms |
「预判」的代价:如果你点了「关系=…」而不是「意图」,这次调用就白花了。 点「意图」这条常见路径调用次数不变(预判那次就是正式那次),只是等待被挪到了你挑菜单的时候。
- 情绪是概率分布的前 3 名,不是三次独立判断 —— 所以
平静 56% · 客套 42%表示"像平静 56%、像客套 42%"。 第一名低于 40% 时说明它自己也拿不准,看前三名比看第一名有用。 - 着急 是 0~3 的连续分 + 四档档位(不着急/一般/急/非常急)。
- 建议 = 回复姿态(只给姿态,不给措辞),例如
建议:正常交流 90%意思是"用正常交流的姿态回"。
| 场景 | 情绪 top | 着急 | 建议(回复姿态) |
|---|---|---|---|
| 情侣·无上下文 | 高兴 94% | 0.02/3 | 肯定赞赏 74% |
| 情侣·刚吵完(加 2 句上下文) | 平静 32% · 难过 27% · 高兴 12% | 0.8/3 | 先安抚道歉 85% |
| 普通朋友 | 高兴 46% · 讽刺 38% · 客套 11% | 0.17/3 | 温和婉拒 74% |
| 陌生人 | 高兴 60% · 讽刺 28% | 0.13/3 | 温和婉拒 72% |
| 同事 | 高兴 56% · 讽刺 34% | 0.10/3 | 温和婉拒 67% |
同一个「我爱你」:情侣读成"高兴/该肯定赞赏",非情侣全读成"高兴 + 讽刺/该温和婉拒"。 上下文比关系更能翻盘:情侣加两句"刚吵完",姿态就从「肯定赞赏」变成「先安抚道歉 85%」。
-
onMsgMenu(msg)挂上长按菜单,拿到被长按的msg(含内容、时间、引用块)。 -
组一个
state(关系 / 对方性别 / 会话类型 / 最近对话 / 待分析消息)+ 7 个问题,POST https://api.typesafe.ai/v1/systemone:{ "state": "{\"关系\":\"情侣\",\"最近对话\":[…],\"待分析消息\":\"我爱你\"}", "model": "jev-latest", "questions": { "intent": {"type":"choice","criteria":{…}}, "emotion": {"type":"choice","criteria":{…}}, "urgency": {"type":"score","criteria":[…]}, "reply_style": {"type":"choice","criteria":{…}}, … } }choice类问题会返回完整概率分布(probabilities),所以一个情绪问题就能给出前 3 名 + 比例。 -
结果按固定 3 条 Toast 弹出(或引用回复 / 直接发消息,取决于设置)。
为什么设置是文件而不是界面:宿主插件 API 只暴露了
toast一个 UI 原语, 没有弹窗、没有输入框(其他函数一节里只有toast)。所以"文件即面板"是最稳的方案。
| 现象 | 原因 / 处理 |
|---|---|
| 长按没有「意图」 | 插件没加载(看 Toast)、或设置里「只看文本消息=A」而这条是图片/语音。引用回复的文本消息是支持的 |
| 提示「未配置 Jev key」 | 先按 docs/如何获取API密钥.md 申请一把。两个地方都没填 key:config.properties 的 api_key,或 设置.properties 的【1】接口密钥。注意文件名别写成 config.example.properties |
| 连点几次都没反应 | 网络或 API 超时;timeout_ms 默认 30s,结果会出现在宿主日志里 |
| 弹出被系统截断 | 缩短内容:情绪条数 改成 A、附带老四项 改成 B |
| 引用气泡是空白的 | 设置里「引用块字段」改成 B. des(某些宿主版本不渲染 title) |
| 设置改了没生效 | 确认改的是插件目录的 设置.properties,字母必须是 A/B/C…(写错会回落到第一个选项并记日志) |
更多排查手法(含"阶梯自检"调试法)见 docs/详细文档.md。
main.java 插件本体(单文件,拷进插件目录的就是它)
info.prop 插件元信息(名称/作者/版本)
config.example.properties 配置模板 → 复制成 config.properties 再填 key
设置.properties 首次长按自动生成(选项面板,本地文件不入库)
docs/如何获取API密钥.md ⭐ 没有 key 先看这个:官网注册 → 建 key → 填进插件
docs/详细文档.md 全部实跑数据、关系对照、bsh 踩坑记录
test/ 本地离线测试(不用手机就能跑完整流程)
tools/package_release.py 打 Release 安装包:一条命令 → dist/JevIntent-v<版本>.zip
python tools/package_release.py # 先跑密钥自检,不干净直接中止产物 dist/JevIntent-v1.9.0.zip(约 30 KB):main.java / info.prop /
config.example.properties / README.md / LICENSE / docs/ —— 就是"拷到手机插件目录就能用"的那几个文件,
然后把 zip 拖到 GitHub Release 的 assets 里即可。
(GitHub 每个 Release 自动生成的 Source code (zip) 是整仓源码,跟这个安装包不是一回事。)
插件是 bsh(BeanShell)脚本,可以直接用 bsh 2.0b6 在 PC 上加载跑通全流程:
见 test/README.md。其中 test/lex_audit.py 是专门防止
"中文 + 反斜杠转义"混写字面量把 bsh 词法器搞崩 的静态检查(这个坑不可捕获,
详见详细文档)。
test/test_speed.bsh 是 v1.9 的速度专项测试:真打接口,验证连接复用(第二次握手应 <80ms)、
预判能提前拿到结果、缓存 40 条上限 —— 输出里会直接打印「握手 Xms + 服务端 Yms」。
PC 上用 JDK 17 跑 bsh 需要放行两个内部包(安卓真机不需要):
java --add-exports java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-exports java.base/sun.net.www.protocol.http=ALL-UNNAMED --add-opens java.base/sun.net.www.protocol.http=ALL-UNNAMED -cp "bsh-2.0b6.jar;." bsh.Interpreter test_speed.bsh
- 只做判定,不生成回复文案。
- 设置只能改文件(宿主没有弹窗 API)。
- 关系/性别是"每会话"的,只能用菜单循环切换,或直接编辑
presets.properties。 - 取上下文最多前后各 7 句。
- 依赖第三方 API(TypeSafe Jev),需要自备 key。
- 速度下限由服务端决定:算法本身要 250
330ms,且约 3% 的请求会抖到 1.51.8s。 预判只能把这 300ms 藏进"你挑菜单"的时间里,消不掉服务端抖动(想要更稳可以自己加重试)。
Jev 判定能力来自 TypeSafe(jev-latest)。本项目为个人自用插件,MIT License。