# WeChat Bot!

> Wechat bot

date:
|
read: 1min

背景

帮朋友调研微信机器人方案,发了个 GitHub 仓库 chatgpt-on-wechat 让我部署下 发现这个仓库是使用 Python 的 itchat 库实现的 web 版本的微信机器人,并且做了一些相关的 patch 处理 参见 lib/itchat

首先微信没有开放官方的 API, 社区上有一些三方库,主要实现有以下集中

  1. Web 协议,通过无头浏览器模拟 web 端发出请求和拦截请求
  1. Windows 协议,通过住
  1. iPad 协议
  1. 直接 Hack Android 手机,逆向微信

Dokploy

Dokploy 是一个基于 Docker 自动化部署平台,开源,免费自行部署

refs: https://www.reddit.com/r/SideProject/comments/1gq6o61/after_6_months_of_work_dokploy_cloud_is_live/

快速搭建一个微信机器人

基于 wechatbot-webhook 部署

部署到 Dokploy

version: '3.8'
services:
  wechat-webhook:
    image: dannicool/docker-wechatbot-webhook
    container_name: wechat-webhook
    volumes:
      - ./wechat-webhook-logs:/app/log
    ports:
      - "3001:3001"
    environment:
      - LOG_LEVEL=info
      # - DISABLE_AUTO_LOGIN=true
      - ACCEPT_RECVD_MSG_MYSELF=true
      - RECVD_MSG_API=https://wechat-callback.hz.yuler.dev
      - LOGIN_API_TOKEN=WEBHOOK_TOKEN # 登录地址Token访问地址: http://localhost:3001/login?token=[LOCAL_LOGIN_API_TOKEN]
    restart: unless-stopped

Callback

我们再创建一个服务接受上面的请求

import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()


app.post('/', async (ctx) => {
  const formData = await ctx.req.formData()
  const type = (formData.get('type') ?? '') as string
  let content = (formData.get('content') ?? '') as any
  let source = (formData.get('source') ?? '') as any
  const isMentioned = (formData.get('isMentioned') ?? '') as string
  const isMsgFromSelf = (formData.get('isMsgFromSelf') ?? '') as string
  const topic = source?.room?.payload?.topic ?? ''
  
  try {
    source = JSON.parse(source)
  } catch {
    console.log('source parse error')
  }

  // 非 `#dev` 群消息不处理
  if (!topic.startsWith('#dev')) {
    return ctx.json({})
  }

  console.log({ type, content, source, isMentioned, isMsgFromSelf })
  
  // 文本消息 'text' & @xxx
  if (type === 'text' && isMentioned === '1') {
    // TODO: 动态化 @xxx
    content = content.slice('@xxx '.length)
    if (content === 'ping')  {
      const mention = `@${source.from.payload.name}`
      return ctx.json({ success: true, data: { type: 'text', content: mention + ' pong' }})
    }
  }

  return ctx.json({})
})

集成 OCR

Umi-OCR 开源 OCR 免费并且离线

Docker 运行

Linux 版本

通过上面的仓库构建 image 并且 push 到 docker hub yule/umi-ocr-paddle

docker run -d --name umi-ocr -e HEADLESS=true -p 1224:1224 yule/umi-ocr-paddle

部署到到 Dokploy

services:
  wechat-ocr:
    image: yule/umi-ocr-paddle
    container_name: wechat-ocr
    # volumes:
    #   - ./wechat-ocr-logs:/app/log
    ports:
      - "1224:1224"
    environment:
      - HEADLESS=true
      - LOG_LEVEL=info 
    restart: unless-stopped

集成 AI

  1. proxy?

测试脚本

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'

由于 OpenAI 禁止大陆 IP 访问,所以需要使用代理

refs: https://github.com/justjavac/openai-proxy

  1. Node SDK
import OpenAI from 'openai'

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [
    { role: "system", content: 'You are a helpful assistant.' },
    { role: "user", '你好啊' }
  ],
  temperature: 0.8,
});

const answer = completion.choices[0].message.content
console.log({answer})

使用场景

  • 提供给外部接口,发送消息 (如:日志报警,定时通知等)
  • OCR 识别图片,更具解析内容做处理 (如:打卡识别后发送一句话,账单识别后落库记录等)
  • 记录群里面的消息,落库,然后每天定时总结
  • 社群运营等