🐂🐎 牛马专列 – 第三辑:7日天气趋势卡片 + 每日星期提醒(含飞书图片上传链路)

第二辑之后,我把牛马专列继续往“更像一个可长期运行的小系统”推进了一步。
这次核心不是再加几条文案,而是把卡片能力做完整:支持图片上传、行内温度条、星期主题提醒、配置统一和主流程接入。

代码地址:https://github.com/rainding0311/lark_webhook_reminder/tree/main

本次新增能力

  1. 墨迹天气 7 日趋势卡片(行内温度条图片版)
  2. 每日星期提醒(周一到周五文案 + assets 配图)
  3. 飞书图片上传链路打通(本地图片 -> image_key -> 卡片 img)
  4. 配置统一(webhook 多群、墨迹参数、飞书应用参数)
  5. 主流程定时接入(天气提醒后 5 分钟发送新卡片)

新功能一:墨迹天气 7 日趋势卡片

相比第二辑只发“今日/明日天气”,这版新增了 7 天卡片,核心点是:

  • 数据源改为墨迹接口(15 天接口里取前 7 天)
  • 卡片展示“日期 / 天气 / 低温 / 温度条 / 高温”
  • 温度条采用图片方式渲染(支持渐变、圆角、中点)
  • 卡片底部注明数据来源

主流程触发时间:

  • 08:35(晚于 08:30 天气提醒 5 分钟)
  • 18:05(晚于 18:00 天气提醒 5 分钟)

新功能二:每日星期提醒(周一到周五)

新增了 weekday_theme_reminder(),按工作日自动选择文案和配图:

  • 周一到周五固定三段文案
  • 配图来自 assets/monday.jpg … friday.jpg
  • 图片上传失败时自动回退为纯文字卡片(不中断发送)

示例文案(周五):

  • 周五不加班,快乐很简单。
  • 今日任务:准时下班,拒绝内卷。
  • 周五到,烦恼跑,快乐马上到。

默认触发时间:

  • 09:05(可在配置中调整)

关键实现:飞书图片上传链路

很多人一开始会以为 webhook 可以直接发本地文件。实际上不行。
正确链路是:

  1. 用 app_id/app_secret 换 tenant_access_token
  2. 调用图片上传接口,把本地图片传到飞书,拿到 image_key
  3. 在消息卡片里通过 img_key 引用图片

1) 获取 token

resp = requests.post(
    "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
    headers={"Content-Type": "application/json"},
    data=json.dumps({"app_id": app_id, "app_secret": app_secret}),
    timeout=8
)
tenant_access_token = resp.json()["tenant_access_token"]

2) 上传图片

files = {"image": ("friday.jpg", open(image_path, "rb"), "image/jpeg")}
data = {"image_type": "message"}
resp = requests.post(
    "https://open.feishu.cn/open-apis/im/v1/images",
    headers={"Authorization": f"Bearer {tenant_access_token}"},
    data=data,
    files=files,
    timeout=12
)
image_key = resp.json()["data"]["image_key"]

3) 卡片引用图片

{
  "tag": "img",
  "img_key": image_key,
  "alt": {"tag": "plain_text", "content": "周五提醒配图"},
  "custom_width": 260
}

配置统一

这版把配置收敛到了 reminder_config.json,主流程和测试脚本都读同一套配置。

{
  "webhook_urls": [
    "https://open.feishu.cn/open-apis/bot/v2/hook/xxx1",
    "https://open.feishu.cn/open-apis/bot/v2/hook/xxx2"
  ],
  "moji_weather": {
    "id": "10007609",
    "key": "your-moji-key",
    "sheng": "上海",
    "place": "上海市",
    "days": 7,
    "style": "apple"
  },
  "feishu_app": {
    "app_id": "cli_xxx",
    "app_secret": "xxx"
  },
  "weekday_reminder": {
    "enabled": true,
    "time": "09:05"
  }
}

定时点总览(工作日)

时间内容
08:30今日天气提醒
08:35墨迹 7 日天气趋势卡片
09:05星期提醒卡片(周一到周五)
10:50午餐提醒(按钮卡片)
13:00 / 15:00 / 17:00下班倒计时
17:50下班前提醒
18:00明日天气提醒
18:05墨迹 7 日天气趋势卡片

单次测试脚本

这次也补了三个 once 脚本,方便你每次改完先验效果:

  • moji_weather_once.py:单次发 7 日天气卡片
  • weekday_reminder_once.py:单次发星期提醒
  • feishu_image_once.py:单次测试图片上传链路

运行方式

pip install requests apt-get install -y python3-pil 
nohup python3 work_reminder_v3.py > nohup.out 2>&1 &

这版踩过的坑

  1. 双发消息:不是 webhook 重复,是两台服务器同时跑了进程。
  2. 锁文件失效:相对路径锁文件在不同启动目录会失效,已改为脚本绝对路径。
  3. Pillow 未安装:会导致图片温度条不可用,已做自动降级到文本温度条。
  4. 多行命令参数报错:\ 后面有空格会让 shell 断行失败。

小结

第三辑的重点是把“提醒”做成“可维护的卡片系统”:

  • 体验层:天气趋势和星期提醒更完整
  • 技术层:飞书图片上传链路打通
  • 工程层:配置统一、主流程接入、故障降级完善