飞书自定义机器人 (lark_custom_bot)

pywayne.lark_custom_bot 面向 webhook 机器人场景,适合:

  • 已经有飞书群里的自定义机器人 webhook

  • 只需要“主动发消息到某个群”

  • 不需要监听消息

  • 不需要引用回复、撤回、reaction、已读、群管理

它和 LarkBot 的边界非常明确:

  • LarkCustomBot: webhook 推送器,轻量,配置简单

  • LarkBot: 应用机器人,能力完整,适合双向交互

如果你需要“收到消息后自动回复”、“给某条消息加表情”、“更新卡片”、“监听按钮点击”,请直接使用 LarkBot + LarkBotListener

能力概览

LarkCustomBot 当前支持:

  • 文本消息

  • post 富文本

  • 分享群聊

  • 图片消息

  • interactive 卡片消息

  • 本地图片上传

  • OpenCV 图像直接上传

  • 签名校验

它当前不负责:

  • 监听消息

  • 回复某条已有消息

  • reaction

  • 撤回 / 编辑消息

  • 查询历史消息

  • 群管理

LarkCustomBot 类

class LarkCustomBot(webhook: str, secret: str = '', bot_app_id: str = '', bot_secret: str = '')

创建一个飞书自定义机器人实例。

参数

  • webhook: 群自定义机器人的 webhook 地址

  • secret: 如果群机器人开启签名校验,则填写 secret

  • bot_app_id: 图片上传用的应用 app id,可选

  • bot_secret: 图片上传用的应用 secret,可选

其中 bot_app_id / bot_secret 主要用于:

  • upload_image

  • upload_image_from_cv2

因为图片上传不走 webhook,而是走开放平台鉴权接口。

主要方法

send_text

send_text(text: str, mention_all: bool = False)

发送纯文本消息。

示例:最简单的文本通知

from pywayne.lark_custom_bot import LarkCustomBot

bot = LarkCustomBot(
    webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
)
bot.send_text("Hello, Feishu")

示例:@ 所有人

bot.send_text("请注意查看今日值班安排", mention_all=True)

send_post

send_post(content: List[List[Dict]], title: str | None = None)

发送 post 富文本消息。

content 是二维结构:

  • 外层列表表示“多行”

  • 内层列表表示“同一行内的多个元素”

send_share_chat

send_share_chat(share_chat_id: str)

发送分享群聊卡片。

send_image

send_image(image_key: str)

发送图片消息。图片一般配合 upload_imageupload_image_from_cv2 使用。

send_interactive

send_interactive(card: Dict)

发送 interactive 卡片消息。

upload_image

upload_image(file_path: str) str

上传本地图片并返回 image_key

upload_image_from_cv2

upload_image_from_cv2(cv2_image: np.ndarray) str

直接上传 OpenCV 图像矩阵。

适合“算法生成结果图,然后直接推送到群里”的场景。

辅助函数

模块级辅助函数用于构造 send_postcontent 元素。

  • create_text_content(text, unescape=False)

  • create_link_content(href, text)

  • create_at_content(user_id, user_name)

  • create_image_content(image_key, width=None, height=None)

示例:手工构造一条 post

from pywayne.lark_custom_bot import (
    LarkCustomBot,
    create_text_content,
    create_link_content,
    create_at_content,
    create_image_content,
)

bot = LarkCustomBot(
    webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
    bot_app_id="cli_xxx",
    bot_secret="sec_xxx"
)

img_key = bot.upload_image("/tmp/report.png")
content = [
    [
        create_text_content("巡检完成"),
        create_at_content("all", "所有人"),
    ],
    [
        create_link_content("https://example.com", "查看详情"),
    ],
    [
        create_image_content(img_key, width=300, height=200),
    ],
]
bot.send_post(content, title="巡检报告")

典型场景示例

场景 1:定时任务往群里推送一条纯文本通知

bot = LarkCustomBot(webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx")
bot.send_text("每日 09:00 自动巡检已开始")

场景 2:构造 richer 的 post 公告

content = [
    [create_text_content("发布完成", unescape=False)],
    [create_link_content("https://example.com/release", "查看发布记录")],
    [create_text_content("请研发和测试同学及时确认。")],
]
bot.send_post(content, title="版本播报")

场景 3:上传本地图片后发到群里

image_key = bot.upload_image("/tmp/chart.png")
bot.send_image(image_key)

场景 4:OpenCV 结果图直接推送

import cv2
import numpy as np

image = np.zeros((400, 600, 3), dtype=np.uint8)
cv2.putText(image, "PASS", (120, 220), cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 255, 0), 6)

image_key = bot.upload_image_from_cv2(image)
bot.send_image(image_key)

场景 5:文本 + 图片 + 链接组合为一条 post

image_key = bot.upload_image("/tmp/dashboard.png")
content = [
    [create_text_content("监控快照如下:")],
    [create_image_content(image_key)],
    [create_link_content("https://grafana.example.com", "打开大盘")],
]
bot.send_post(content, title="监控日报")

场景 6:交互卡片做一个轻量审批提醒

card = {
    "config": {"wide_screen_mode": True},
    "header": {
        "title": {"tag": "plain_text", "content": "审批提醒"}
    },
    "elements": [
        {"tag": "markdown", "content": "**工单 #1234** 等待审批"},
        {
            "tag": "action",
            "actions": [
                {
                    "tag": "button",
                    "text": {"tag": "plain_text", "content": "打开审批页"},
                    "type": "primary",
                    "url": "https://example.com/ticket/1234"
                }
            ]
        }
    ]
}
bot.send_interactive(card)

场景 7:带签名校验的安全发送

bot = LarkCustomBot(
    webhook="https://open.feishu.cn/open-apis/bot/v2/hook/xxx",
    secret="your_sign_secret"
)
bot.send_text("这条消息会自动带 timestamp 和 sign")

场景 8:运维值班报告,一次发文本、图片、卡片三连

bot.send_text("今晚值班巡检开始")

image_key = bot.upload_image("/tmp/nightly.png")
bot.send_image(image_key)

bot.send_interactive({
    "header": {"title": {"tag": "plain_text", "content": "值班报告"}},
    "elements": [
        {"tag": "markdown", "content": "- 巡检: 已完成\n- 异常: 0\n- 待处理: 1"}
    ]
})

场景 9:把群链接分享给另一个群

bot.send_share_chat("oc_xxx")

场景 10:日常构造器复用,封一个发布函数

def send_release_report(bot: LarkCustomBot, title: str, report_url: str, image_path: str):
    image_key = bot.upload_image(image_path)
    content = [
        [create_text_content("发布完成")],
        [create_link_content(report_url, "查看详情")],
        [create_image_content(image_key)],
    ]
    bot.send_post(content, title=title)

和 LarkBot 的取舍

优先用 LarkCustomBot 的场景:

  • 只要往固定群发消息

  • 不想配置应用事件订阅

  • 不需要监听和消息生命周期管理

  • 用 webhook 足够

优先用 LarkBot 的场景:

  • 需要引用回复

  • 需要撤回或编辑消息

  • 需要 reaction / 置顶 / 已读

  • 需要监听群聊和私聊

  • 需要按钮点击回调

  • 需要群管理

注意事项

  1. upload_image / upload_image_from_cv2 需要 bot_app_idbot_secret,否则只能发纯 webhook 文本 / post / card,不能上传图片。

  2. send_postcontent 必须是飞书要求的二维结构,不是普通字符串。

  3. send_interactive 只能发卡片消息,不负责接收卡片按钮点击;按钮回调要走应用机器人监听体系。

  4. 如果你的业务开始出现“收到消息后处理再回复”的诉求,说明应该切到 LarkBot + LarkBotListener,而不是继续堆 webhook 逻辑。