fix: make xianyu notifications per-item with clickable links

This commit is contained in:
2026-05-06 23:30:25 +08:00
parent d5294a3f9b
commit ad48715664
13 changed files with 454 additions and 53 deletions
@@ -0,0 +1,85 @@
# Xianyu Per-Item Notifications + Feishu Clickable Links — 2026-05
## Context
BOSS reported two UX issues after initial link normalization:
1. Feishu still did not show reliable clickable product links.
2. Notifications should behave like the original project: each product should be pushed as its own message, not bundled into one long report-style message.
A key pitfall was that the running `server.mjs` process still used the old notifier module until the service was restarted. Always restart the Node service after patching notification rendering.
## Implemented pattern
`lib/notifier.mjs` now defaults to:
```json
{
"perItem": true,
"maxNotifyItems": 10
}
```
Notification rendering now:
- Selects candidates by `verdict === 'recommend' || score >= minScore`.
- Sends up to `maxNotifyItems` items.
- Sends one message per item when `perItem !== false`.
- Uses explicit Feishu-compatible Markdown link syntax:
```md
[🔗 打开闲鱼商品](https://h5.m.goofish.com/item?id=<id>)
备用链接:https://h5.m.goofish.com/item?id=<id>
```
The backup plain h5 URL is kept because Feishu/clients sometimes vary in Markdown rendering.
## Verification
After patching, run:
```bash
cd /Users/chick/.Hermes/workspace/research/xianyu-hunter
node --check lib/notifier.mjs && node --check server.mjs
```
Dry-run without sending:
```bash
node --input-type=module - <<'NODE'
import fs from 'fs';
import { buildAnalysis } from './lib/analyzer.mjs';
import { sendNotifications } from './lib/notifier.mjs';
const data = JSON.parse(fs.readFileSync('data/tasks.json','utf8'));
const task = data.at(-1);
const analysis = buildAnalysis(task, { limit: 3 });
const res = await sendNotifications(task, { ...analysis.summary, maxNotifyItems: 3 }, {
force: true,
config: { enabled: true, notifyOnlyGood: false, minScore: 0, perItem: true, maxNotifyItems: 3, channels: [] }
});
console.log(res.messages.join('\n\n---\n\n'));
NODE
```
Restart exact Node server process, then test through API:
```bash
# kill old node server.mjs PID, then start tracked/background process
PORT=3000 node server.mjs
curl -sS -X POST http://127.0.0.1:3000/api/notify-test \
-H 'Content-Type: application/json' \
-d '{"title":"xianyu-hunter 单商品链接测试"}' | python3 -m json.tool
```
Expected API response includes:
- `perItem: true`
- `messages: [ ... ]`
- message text contains `[🔗 打开闲鱼商品](https://h5.m.goofish.com/item?id=...)`
- `results[].itemIndex` for each individual pushed item
## Notes
- `cfg.perItem === false` can still be used to send a bundled message for webhook channels if needed.
- `chatUrl` should remain a desktop IM URL; only user-facing product links use h5 mobile URLs.