
Wecom Automation
- 425 installs
- 82 repo stars
- Updated August 2, 2026
- aaaaqwq/claude-code-skills
wecom-automation is a Claude Code skill that automates WeCom (WeChat Work) messaging, notifications, and group workflows for developers who integrate enterprise chat into product features.
About
wecom-automation is a skill from aaaaqwq/claude-code-skills that helps developers wire WeCom (WeChat Work) into product integrations. It covers automated messaging, team notifications, and group workflow triggers so engineering teams can push alerts, onboarding messages, or ops updates through enterprise WeChat instead of building ad-hoc scripts. Reach for wecom-automation when a SaaS or internal tool must notify Chinese enterprise users on WeCom during deployment hooks, billing events, or support escalations. The skill assumes familiarity with WeCom bot or app credentials and enterprise approval flows typical in China-based org stacks.
- WeCom bot messaging
- group notification flows
- webhook integration
- approval alerts
- enterprise workflow automation
Wecom Automation by the numbers
- 425 all-time installs (skills.sh)
- Ranked #438 of 2,719 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aaaaqwq/claude-code-skills --skill wecom-automationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 425 |
|---|---|
| repo stars | ★ 82 |
| Last updated | August 2, 2026 |
| Repository | aaaaqwq/claude-code-skills ↗ |
How do you automate WeCom messaging in product integrations?
Automate WeCom (WeChat Work) messaging, notifications, and group workflows for enterprise teams during product integration.
Who is it for?
Developers shipping SaaS or internal tools for Chinese enterprise teams who need WeChat Work messaging wired into CI, billing, or support flows.
Skip if: Skip wecom-automation when the audience uses Slack or Discord only, or when no WeCom enterprise app credentials are available.
When should I use this skill?
The user asks to send WeCom messages, automate WeChat Work group notifications, or integrate enterprise WeChat into a product.
What you get
WeCom notification handlers, group message workflows, and integrated enterprise chat automation scripts.
- WeCom notification handlers
- group workflow automation
- messaging integration code
Files
企业微信个人账号直连自动化
基于 Wechaty 框架连接企业微信个人账号,实现完整的 AI 助手功能。适用于企业微信机器人、自动化客服、个人助手等场景。
核心功能
1. 自动同意好友添加
- 监听好友请求事件
- 自动通过好友验证
- 发送个性化欢迎消息
- 标注用户信息和来源
2. 智能问答(基于知识库)
- 向量知识库存储企业知识
- 语义搜索匹配问题
- LLM 生成专业回复
- 支持多轮对话上下文
3. 人工介入提醒
- 置信度阈值自动判断
- 通过 Telegram/飞书通知人工
- 记录未解决问题用于优化
- 平滑转接到人工客服
4. 消息类型支持
- 文本消息(问答、对话)
- 图片消息(OCR、识别)
- 文件消息(DOCX、PDF 等)
- 语音消息(转文字、语音交互)
- 链接消息(预览、摘要)
- 名片消息(保存、处理)
技术架构
┌──────────────┐
│ 企业微信 │
│ 个人账号 │
└──────┬───────┘
│
▼
┌──────────────────┐
│ Wechaty │
│ (PadLocal) │
└──────┬───────────┘
│
▼
┌────────────────────┐
│ OpenClaw Gateway │
│ (消息分发、处理) │
└──────┬─────────────┘
│
├──────────────┬──────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 向量知识库 │ │ LLM API │ │ 通知服务 │
│(PG+pgvec)│ │ (Kimi/GPT)│ │(Telegram)│
└──────────┘ └──────────┘ └──────────┘快速开始
方案选择
企业微信个人账号直连有两种方案:
方案 A:Wechaty + PadLocal(推荐,适合个人)
优点:
- 配置简单,快速上手
- 稳定性高,官方维护
- 支持所有消息类型
- 适合个人使用
缺点:
- PadLocal 需要付费(约 50 元/月)
- 单账号限制
适用场景:个人助手、小规模客服
方案 B:企业微信内部应用 API(适合企业)
优点:
- 官方 API,免费使用
- 稳定性最高
- 支持大规模部署
缺点:
- 需要企业认证
- 配置相对复杂
- 功能受限于 API
适用场景:企业客服、大规模应用
本技能使用方案 A(Wechaty + PadLocal)
第一步:申请 PadLocal Token
1. 访问 https://github.com/wechaty/wechaty 2. 选择 "PadLocal" 协议 3. 注册账号并获取 Token 4. 保存 Token 到 pass:
pass insert api/wechaty-padlocal第二步:安装依赖
# 1. 安装 Node.js 依赖
cd ~/clawd/skills/wecom-automation
npm install
# 2. 安装 Python 依赖
pip3 install -r requirements.txt
# 3. 配置环境变量
cp .env.example .env第三步:配置环境变量
编辑 ~/clawd/skills/wecom-automation/.env:
# Wechaty 配置
WECHATY_PUPPET=padlocal
WECHATY_TOKEN=$(pass show api/wechaty-padlocal)
WECHATY_LOG_LEVEL=info
# 企业微信账号配置
WECOM_NAME="企业微信机器人"
WECOM_QR_CODE_PATH=/tmp/wecom_qrcode.png
# 知识库配置
KB_DB_URL=postgresql://postgres@localhost/wecom_kb
KB_SIMILARITY_THRESHOLD=0.7
KB_TOP_K=3
# LLM 配置
LLM_PROVIDER=kimi
LLM_API_KEY=$(pass show api/kimi)
LLM_API_BASE=https://api.moonshot.cn/v1
LLM_MODEL=moonshot-v1-8k
# 人工介入通知
NOTIFICATION_CHANNEL=telegram:REDACTED_TG_USER_ID
NOTIFICATION_ENABLED=true
# OpenClaw Gateway 配置
GATEWAY_URL=http://localhost:8080
GATEWAY_TOKEN=$(pass show api/openclaw-gateway)第四步:初始化数据库
# 创建数据库
sudo -u postgres createdb wecom_kb
# 初始化表结构
psql wecom_kb < ~/clawd/skills/wecom-automation/schema.sql
# 导入示例知识库
python3 ~/clawd/skills/wecom-automation/scripts/import_kb.py \
--input ~/clawd/skills/wecom-automation/knowledge/sample.md \
--category "常见问题" \
--key "$(pass show api/kimi)"第五步:启动机器人
# 方式 1:直接运行
cd ~/clawd/skills/wecom-automation
npm start
# 方式 2:通过 PM2(推荐)
pm2 start ~/clawd/skills/wecom-automation/ecosystem.config.js
# 查看日志
pm2 logs wecom-bot第六步:扫码登录
启动机器人后会显示二维码:
██████████████████████████████████
██ ██
██ 1. 打开企业微信 → 扫一扫 ██
██ 2. 扫描下方二维码登录 ██
██ ██
██████████████████████████████████
[二维码图片]使用企业微信扫码登录后,机器人即可正常工作。
使用方法
场景 1:新好友自动欢迎
// workflows/on_friend_add.js
const { Contact } = require('wechaty')
bot.on('friendship', async friendship => {
if (friendship.type() === Friendship.Type.Receive) {
const contact = friendship.contact()
// 自动通过好友请求
await friendship.accept()
// 发送欢迎消息
await contact.say(`👋 欢迎来到${contact.name()}!
我是智能助手小a,可以帮您:
• 解答常见问题
• 处理售后请求
• 查询订单状态
如有复杂问题,我会转接人工客服为您服务。`)
// 添加到数据库
await saveUser(contact)
}
})场景 2:知识库问答
// workflows/answer_question.js
const { Message } = require('wechaty')
bot.on('message', async msg => {
if (msg.type() === Message.Type.Text) {
const text = msg.text()
const from = msg.from()
// 搜索知识库
const results = await searchKnowledge(text)
// 生成答案
const answer = await generateAnswer(text, results)
// 判断是否需要人工介入
if (answer.confidence < 0.7) {
await escalateToHuman(from, text, answer)
} else {
await msg.say(answer.text)
}
}
})场景 3:文件处理(DOCX/PDF)
// workflows/handle_file.js
const { Message } = require('wechaty')
bot.on('message', async msg => {
if (msg.type() === Message.Type.Attachment) {
const file = await msg.toFileBox()
// 下载文件
const filePath = `/tmp/${file.name}`
await file.toFile(filePath)
// 处理文件(提取内容、分析等)
const content = await extractFileContent(filePath)
// 发送回复
await msg.say(`✅ 已收到文件:${file.name}\n\n正在处理...`)
// 处理后回复
await processAndReply(msg, content)
}
})场景 4:人工介入提醒
// workflows/escalate.js
async function escalateToHuman(contact, question, answer) {
// 1. 发送用户消息
await contact.say('⏳ 已为您转接人工客服,请稍候...')
// 2. 通过 Telegram 通知人工客服
const notification = `🚨 需要人工介入
用户:${contact.name()}
问题:${question}
时间:${new Date().toLocaleString()}
请及时处理。`
await sendTelegramNotification(notification)
// 3. 记录未解决问题
await saveUnknownQuestion(contact, question)
}目录结构
~/clawd/skills/wecom-automation/
├── SKILL.md # 本文件
├── package.json # Node.js 依赖
├── requirements.txt # Python 依赖
├── ecosystem.config.js # PM2 配置
├── .env.example # 环境变量模板
├── schema.sql # 数据库表结构
├── bot.js # Wechaty 机器人主文件
├── config/
│ ├── knowledge.js # 知识库配置
│ └── escalation.js # 人工介入规则
├── workflows/
│ ├── on_friend_add.js # 好友添加处理
│ ├── answer_question.js # 问答处理
│ ├── handle_file.js # 文件处理
│ └── escalate.js # 人工介入
├── lib/
│ ├── knowledge.js # 知识库操作
│ ├── llm.js # LLM 调用
│ ├── notification.js # 通知服务
│ └── database.js # 数据库操作
└── knowledge/
└── sample.md # 示例知识文档API 参考文档
企业微信 API 文档
Wechaty 文档
Kimi API 文档
高级功能
1. 多轮对话记忆
// 使用 Redis 存储会话上下文
const redis = require('redis')
const client = redis.createClient()
async function getConversationHistory(userId) {
const history = await client.get(`conv:${userId}`)
return history ? JSON.parse(history) : []
}
async function appendMessage(userId, role, content) {
const history = await getConversationHistory(userId)
history.push({ role, content, timestamp: Date.now() })
await client.set(`conv:${userId}`, JSON.stringify(history))
}2. 文件处理
// 提取 DOCX 内容
const docx = require('docx')
async function extractDocx(filePath) {
const doc = await docx.Document.read(filePath)
const text = doc.paragraphs.map(p => p.text).join('\n')
return text
}
// 提取 PDF 内容
const pdf = require('pdf-parse')
async function extractPdf(filePath) {
const data = await fs.readFile(filePath)
const result = await pdf(data)
return result.text
}3. 语音转文字
# 使用 Whisper API
import openai
def transcribe_audio(audio_path):
with open(audio_path, "rb") as audio:
transcript = openai.Audio.transcribe(
model="whisper-1",
file=audio
)
return transcript["text"]4. 图片 OCR
# 使用 Kimi Vision
import openai
def ocr_image(image_path):
with open(image_path, "rb") as image:
result = openai.chat.completions.create(
model="gemini-2.5-pro",
messages=[{
"role": "user",
"content": "识别图片中的文字"
}],
image=image
)
return result.choices[0].message.content监控与维护
日志查看
# PM2 日志
pm2 logs wecom-bot
# 错误日志
pm2 logs wecom-bot --err
# 实时日志
pm2 logs wecom-bot --lines 100性能监控
// 添加自定义指标
const prometheus = require('prom-client')
const messageCounter = new prometheus.Counter({
name: 'wecom_messages_total',
help: 'Total messages received',
labelNames: ['type']
})
const answerLatency = new prometheus.Histogram({
name: 'wecom_answer_latency_seconds',
help: 'Answer generation latency',
buckets: [0.1, 0.5, 1, 2, 5, 10]
})人工介入统计
-- 查看未解决问题分布
SELECT
COUNT(*) as count,
SUBSTRING(question, 1, 30) as question_preview
FROM unknown_questions
GROUP BY question_preview
ORDER BY count DESC
LIMIT 10;
-- 查看每日介入次数
SELECT
DATE(created_at) as date,
COUNT(*) as escalations
FROM escalation_log
GROUP BY DATE(created_at)
ORDER BY date DESC
LIMIT 7;故障排查
问题 1:无法扫码登录
# 检查 Wechaty 日志
pm2 logs wecom-bot --lines 50
# 重启机器人
pm2 restart wecom-bot
# 清理缓存
rm -rf /tmp/wechaty*
pm2 restart wecom-bot问题 2:消息不回复
# 检查知识库连接
psql wecom_kb -c "SELECT COUNT(*) FROM knowledge_chunks;"
# 测试 LLM API
curl -X POST https://api.moonshot.cn/v1/chat/completions \
-H "Authorization: Bearer $KIMI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"moonshot-v1-8k","messages":[{"role":"user","content":"测试"}]}'
# 检查环境变量
cat ~/clawd/skills/wecom-automation/.env | grep -E "^(LLM|KB|NOTIFICATION)"问题 3:文件无法接收
# 检查临时目录权限
ls -la /tmp/
# 创建日志目录
mkdir -p ~/clawd/skills/wecom-automation/logs
chmod 755 ~/clawd/skills/wecom-automation/logs
# 检查磁盘空间
df -h安全最佳实践
1. 密钥管理
- 所有密钥使用
pass存储 - 环境变量引用,不硬编码
- 定期轮换 Token
2. 数据隐私
- 客户信息加密存储
- 定期清理敏感日志
- 遵守数据保护法规
3. 访问控制
- API 接口鉴权
- IP 白名单限制
- 请求频率限制
4. 审计日志
- 记录所有人工介入
- 定期审查访问日志
- 异常行为告警
扩展功能
1. 主动营销
// 定期推送优惠信息
const schedule = require('node-schedule')
schedule.scheduleJob('0 10 * * 1-5', async () => {
const users = await getActiveUsers(7)
for (const user of users) {
await user.say('🎉 今日特惠:...')
}
})2. 群组管理
// 自动邀请用户加入群组
bot.on('friendship', async friendship => {
const contact = friendship.contact()
const room = await bot.Room.find({ topic: '客户群' })
if (room) {
await room.add(contact)
await contact.say('已邀请您加入客户群')
}
})3. 数据统计
// 每日生成报表
async function generateDailyReport() {
const stats = {
newUsers: await countNewUsers(),
questions: await countQuestions(),
escalations: await countEscalations()
}
await sendReportToAdmin(stats)
}相关技能
- wecom-cs-automation: 企业微信客服 API 方式
- feishu-automation: 飞书平台自动化
- notion-automation: Notion 知识库集成
- telegram-automation: Telegram 通知集成
成本对比
| 方案 | 月成本 | 适用场景 |
|---|---|---|
| Wechaty + PadLocal | ~50元 | 个人、小团队 |
| 企业微信内部应用 | 免费 | 企业、大规模 |
| 企业微信客服 API | 按量 | 企业客服 |
参考资源
#!/usr/bin/env node
/**
* 企业微信个人账号机器人 - 主文件
* 基于 Wechaty + PadLocal
*/
require('dotenv').config({ path: __dirname + '/.env' });
const { Wechaty } = require('wechaty');
const { PuppetPadlocal } = require('wechaty-puppet-padlocal');
const winston = require('winston');
// 导入工作流
const {
handleFriendAdd,
handleRoomJoin,
handleRoomLeave
} = require('./workflows/on_event');
const {
handleTextMessage,
handleFileMessage,
handleImageMessage,
handleVoiceMessage
} = require('./workflows/handle_message');
// 日志配置
const logger = winston.createLogger({
level: process.env.WECHATY_LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message }) => {
return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
})
),
transports: [
new winston.transports.Console(),
new winston.transports.File({
filename: __dirname + '/logs/error.log',
level: 'error'
}),
new winston.transports.File({
filename: __dirname + '/logs/combined.log'
})
]
});
// 创建 Wechaty 实例
const bot = new Wechaty({
name: process.env.WECOM_NAME || 'WeCom-Bot',
puppet: new PuppetPadlocal({
token: process.env.WECHATY_TOKEN,
}),
puppetOptions: {
uos: true, // 使用 uos 协议
},
});
/**
* 启动机器人
*/
async function startBot() {
logger.info('🤖 正在启动机器人...');
try {
// 事件监听
bot.on('scan', onScan);
bot.on('login', onLogin);
bot.on('logout', onLogout);
bot.on('friendship', onFriendship);
bot.on('room-join', onRoomJoin);
bot.on('room-leave', onRoomLeave);
bot.on('message', onMessage);
// 启动
await bot.start();
logger.info('✅ 机器人已启动');
} catch (error) {
logger.error(`❌ 启动失败: ${error.message}`);
process.exit(1);
}
}
/**
* 扫码登录事件
*/
function onScan(qrcode, status) {
if (status === 2 || status === 3) {
require('qrcode-terminal').generate(qrcode, { small: true });
logger.info(`[${status === 2 ? '扫描中' : '已扫描'}] 请使用企业微信扫描二维码登录`);
logger.info(`或访问 https://wechaty.js.org/qrcode/${qrcode}`);
}
}
/**
* 登录成功事件
*/
async function onLogin(user) {
logger.info(`✅ 登录成功: ${user.name()} (${user.id})`);
// 发送启动通知到管理员
if (process.env.ADMIN_WECHATY_NAME) {
const admin = await bot.Contact.find({ name: process.env.ADMIN_WECHATY_NAME });
if (admin) {
await admin.say('🤖 机器人已启动,随时为您服务!');
}
}
}
/**
* 登出事件
*/
function onLogout(user) {
logger.info(`👋 登出: ${user.name()} (${user.id})`);
}
/**
* 好友关系事件
*/
async function onFriendship(friendship) {
logger.info(`👥 好友事件: ${friendship.type()}`);
switch (friendship.type()) {
case bot.Friendship.Type.Receive:
// 收到好友请求
await handleFriendAdd(friendship);
break;
case bot.Friendship.Type.Confirm:
// 好友关系确认
logger.info('✅ 好友关系已确认');
break;
default:
logger.debug(`其他好友事件: ${friendship.type()}`);
}
}
/**
* 进群事件
*/
async function onRoomJoin(room, inviteeList, inviter) {
logger.info(`🚪 进群事件: ${room.topic()}`);
try {
await handleRoomJoin(room, inviteeList, inviter);
} catch (error) {
logger.error(`处理进群事件失败: ${error.message}`);
}
}
/**
* 退群事件
*/
async function onRoomLeave(room, leaverList) {
logger.info(`🚪 退群事件: ${room.topic()}`);
try {
await handleRoomLeave(room, leaverList);
} catch (error) {
logger.error(`处理退群事件失败: ${error.message}`);
}
}
/**
* 消息事件
*/
async function onMessage(msg) {
try {
const from = msg.from();
const room = msg.room();
const text = msg.text();
const type = msg.type();
// 忽略自己发的消息
if (msg.self()) {
return;
}
// 记录消息
if (room) {
logger.info(`📨 [群聊 ${room.topic()}] ${from ? from.name() : '未知'}: ${text}`);
} else {
logger.info(`📨 [私聊] ${from ? from.name() : '未知'}: ${text}`);
}
// 路由处理
switch (type) {
case bot.Message.Type.Text:
await handleTextMessage(msg);
break;
case bot.Message.Type.Attachment:
case bot.Message.Type.Video:
case bot.Message.Type.Audio:
await handleFileMessage(msg);
break;
case bot.Message.Type.Image:
await handleImageMessage(msg);
break;
case bot.Message.Type.Url:
await handleUrlMessage(msg);
break;
case bot.Message.Type.MiniProgram:
await handleMiniProgram(msg);
break;
default:
logger.debug(`未处理的消息类型: ${type}`);
}
} catch (error) {
logger.error(`处理消息失败: ${error.message}`);
await msg.say('😔 处理消息时遇到错误,请稍后再试');
}
}
/**
* 处理 URL 消息
*/
async function handleUrlMessage(msg) {
const urlLink = await msg.toUrlLink();
logger.info(`🔗 URL: ${urlLink.url()} - ${urlLink.title()}`);
// 可以进一步处理 URL 内容
await msg.say(`✅ 已收到链接:${urlLink.title()}`);
}
/**
* 处理小程序消息
*/
async function handleMiniProgram(msg) {
const miniProgram = await msg.toMiniProgram();
logger.info(`📱 小程序: ${miniProgram.appid()}`);
await msg.say('✅ 已收到小程序消息');
}
// 异常处理
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
// 启动机器人
startBot();
module.exports = {
apps: [{
name: 'wecom-bot',
script: './bot.js',
cwd: '/home/aa/clawd/skills/wecom-automation',
interpreter: 'node',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '500M',
env: {
NODE_ENV: 'production',
WECHATY_LOG_LEVEL: 'info'
},
error_file: './logs/error.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
autorestart: true,
max_restarts: 10,
min_uptime: '10s'
}]
};
#!/bin/bash
# 企业微信个人账号机器人 - 一键安装脚本
set -e
echo "🚀 开始安装企业微信个人账号机器人..."
echo ""
# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# 检查依赖
check_dependencies() {
echo -e "${YELLOW}检查系统依赖...${NC}"
# Node.js
if ! command -v node &> /dev/null; then
echo -e "${RED}❌ 未安装 Node.js${NC}"
echo "请安装 Node.js 16+:curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -"
exit 1
fi
# npm
if ! command -v npm &> /dev/null; then
echo -e "${RED}❌ 未安装 npm${NC}"
exit 1
fi
# Python 3
if ! command -v python3 &> /dev/null; then
echo -e "${RED}❌ 未安装 Python 3${NC}"
exit 1
fi
# pip
if ! command -v pip3 &> /dev/null; then
echo -e "${RED}❌ 未安装 pip3${NC}"
exit 1
fi
# PostgreSQL
if ! command -v psql &> /dev/null; then
echo -e "${YELLOW}⚠️ 未安装 PostgreSQL,正在安装...${NC}"
sudo apt update
sudo apt install -y postgresql postgresql-contrib
fi
echo -e "${GREEN}✓ 依赖检查完成${NC}"
echo ""
}
# 安装 Node.js 依赖
install_node_packages() {
echo -e "${YELLOW}安装 Node.js 依赖...${NC}"
cd ~/clawd/skills/wecom-automation
npm install || {
echo -e "${RED}❌ Node.js 包安装失败${NC}"
exit 1
}
echo -e "${GREEN}✓ Node.js 包安装完成${NC}"
echo ""
}
# 安装 Python 包
install_python_packages() {
echo -e "${YELLOW}安装 Python 依赖...${NC}"
pip3 install --user -r requirements.txt || {
echo -e "${RED}❌ Python 包安装失败${NC}"
exit 1
}
echo -e "${GREEN}✓ Python 包安装完成${NC}"
echo ""
}
# 配置数据库
setup_database() {
echo -e "${YELLOW}配置数据库...${NC}"
# 启动 PostgreSQL
sudo service postgresql start
# 创建数据库
sudo -u postgres createdb wecom_kb 2>/dev/null || echo "数据库已存在"
# 启用 pgvector 扩展
echo -e "${YELLOW}检查 pgvector 扩展...${NC}"
if ! sudo -u postgres psql -d wecom_kb -c "SELECT * FROM pg_extension WHERE extname = 'vector';" | grep -q vector; then
echo -e "${YELLOW}安装 pgvector...${NC}"
# 检测 PostgreSQL 版本
PG_VERSION=$(sudo -u postgres psql -t -c "SELECT version()" | grep -oP 'PostgreSQL \K[0-9.]+' | head -1)
PG_MAJOR=$(echo $PG_VERSION | cut -d. -f1)
echo "检测到 PostgreSQL $PG_VERSION"
# 安装 pgvector
if [ ! -d "/tmp/pgvector" ]; then
cd /tmp
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
cd pgvector
sudo apt install -y build-essential libpq-dev
make
sudo make install
fi
# 启用扩展
sudo -u postgres psql -d wecom_kb -c "CREATE EXTENSION vector;"
echo -e "${GREEN}✓ pgvector 扩展已启用${NC}"
else
echo -e "${GREEN}✓ pgvector 扩展已存在${NC}"
fi
# 初始化表结构
echo -e "${YELLOW}初始化数据库表...${NC}"
sudo -u postgres psql -d wecom_kb -f schema.sql
echo -e "${GREEN}✓ 数据库配置完成${NC}"
echo ""
}
# 配置环境变量
setup_env() {
echo -e "${YELLOW}配置环境变量...${NC}"
ENV_FILE="$HOME/clawd/skills/wecom-automation/.env"
if [ -f "$ENV_FILE" ]; then
echo -e "${YELLOW}⚠️ .env 文件已存在,跳过${NC}"
else
cp .env.example "$ENV_FILE"
# 自动填入 Kimi API Key
if pass show api/kimi &> /dev/null; then
sed -i "s|LLM_API_KEY=.*|LLM_API_KEY=$(pass show api/kimi)|" "$ENV_FILE"
fi
echo -e "${GREEN}✓ 已创建 .env 模板${NC}"
echo -e "${YELLOW}⚠️ 请编辑 $ENV_FILE 填入以下配置:${NC}"
echo ""
echo "必填项:"
echo " 1. WECHATY_TOKEN - PadLocal Token (https://github.com/wechaty/puppet-service)"
echo " 2. TELEGRAM_BOT_TOKEN - 用于人工介入通知"
echo ""
echo "可选项(已自动填入):"
echo " 3. LLM_API_KEY - Kimi API Key (已自动配置)"
fi
echo ""
}
# 创建必要目录
setup_directories() {
echo -e "${YELLOW}创建必要目录...${NC}"
mkdir -p logs
mkdir -p tmp
echo -e "${GREEN}✓ 目录创建完成${NC}"
echo ""
}
# 导入示例知识库
import_sample_kb() {
echo -e "${YELLOW}导入示例知识库...${NC}"
KB_FILE="$HOME/clawd/skills/wecom-automation/knowledge/sample.md"
if [ -f "$KB_FILE" ]; then
python3 scripts/import_kb.py \
--input "$KB_FILE" \
--category "示例知识" \
--tags "示例,测试" \
--key "$(pass show api/kimi)" || {
echo -e "${RED}❌ 知识库导入失败(可能需要先配置 Kimi API Key)${NC}"
echo "可以稍后手动导入:"
echo "python3 ~/clawd/skills/wecom-automation/scripts/import_kb.py --input knowledge/sample.md --key YOUR_KIMI_KEY"
}
echo -e "${GREEN}✓ 知识库导入完成${NC}"
else
echo -e "${YELLOW}⚠️ 示例知识库文件不存在${NC}"
fi
echo ""
}
# 打印后续步骤
print_next_steps() {
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✅ 安装完成!${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo "📋 后续步骤:"
echo ""
echo "1️⃣ 申请 PadLocal Token"
echo " - 访问 https://github.com/wechaty/wechaty"
echo " - 选择 PadLocal 协议"
echo " - 注册并获取 Token"
echo ""
echo "2️⃣ 填写环境变量"
echo " - 编辑 ~/clawd/skills/wecom-automation/.env"
echo " - 填入 WECHATY_TOKEN"
echo " - 填入 TELEGRAM_BOT_TOKEN"
echo ""
echo "3️⃣ 启动机器人"
echo " cd ~/clawd/skills/wecom-automation"
echo " npm start"
echo ""
echo " 或使用 PM2(推荐):"
echo " pm2 start ecosystem.config.js"
echo ""
echo "4️⃣ 扫码登录"
echo " - 启动后会显示二维码"
echo " - 打开企业微信 → 扫一扫"
echo " - 扫描二维码登录"
echo ""
echo "5️⃣ 测试功能"
echo " # 测试问答"
echo " python3 ~/clawd/skills/wecom-automation/workflows/answer_question.py \\"
echo " --user-id test_user --question \"如何退款?\""
echo ""
echo " # 测试人工介入"
echo " python3 ~/clawd/skills/wecom-automation/workflows/escalate.py \\"
echo " --user-id test_user --name \"测试用户\" --question \"测试问题\""
echo ""
echo "📚 更多信息:"
echo " cat ~/clawd/skills/wecom-automation/SKILL.md"
echo ""
}
# 主流程
main() {
check_dependencies
install_node_packages
install_python_packages
setup_database
setup_env
setup_directories
import_sample_kb
print_next_steps
}
# 运行安装
main
企业客服知识库示例
售后服务
退款政策
我们支持 7 天无理由退款。在商品签收后 7 天内,如对商品不满意,可申请全额退款。
退款流程: 1. 联系客服申请退款 2. 填写退款申请表 3. 寄回商品(需保持包装完好) 4. 我们在收到退货后 3 个工作日内处理退款
退款将原路返回到您的支付账户,到账时间根据支付方式不同,通常为 1-7 个工作日。
退换货流程
如果商品存在质量问题或运输损坏,我们提供免费换货服务。
换货条件:
- 商品有质量缺陷
- 运输过程中损坏
- 发错商品
换货流程: 1. 拍照取证(质量问题需拍摄清晰照片) 2. 联系客服说明情况 3. 我们安排快递上门取件 4. 收到退货后 24 小时内发出换货商品
发票问题
所有订单均可开具电子发票,发票类型为增值税普通发票。
开具发票请提供:
- 发票抬头(公司名称)
- 纳税人识别号
- 发票内容(商品明细或类别)
电子发票将在订单完成后自动发送至您的邮箱,也可在订单详情页下载。
物流配送
配送时间
- 标准快递:订单确认后 48 小时内发货,3-5 天到达
- 加急快递:当日发货,1-2 天到达
- 预约配送:可指定日期配送
偏远地区可能需要额外 1-3 天配送时间。
物流查询
您可以通过以下方式查询物流: 1. 登录账户查看订单详情 2. 使用订单号在快递公司官网查询 3. 联系客服协助查询
配送前会通过短信或微信通知您,请保持手机畅通。
配送范围
我们覆盖全国所有省市县,不包括:
- 港澳台地区
- 偏远岛屿
- 部分军事管理区
国际配送暂不支持。
订单管理
修改订单
订单未发货前可申请修改:
- 更改收货地址
- 更改商品规格
- 增减商品数量
已发货订单无法修改,如需更改可申请退货后重新下单。
取消订单
- 未支付订单:自动取消
- 已支付未发货:联系客服取消,款项 3-5 个工作日退回
- 已发货订单:无法取消,可申请退货
订单状态说明
- 待支付:订单已创建,等待付款
- 待发货:已付款,等待仓库发货
- 配送中:商品已在途中
- 已签收:配送完成
- 已完成:订单结束,确认收货
- 已取消:订单取消
产品相关
产品保修
所有产品享受 1 年质保服务,涵盖:
- 非人为损坏的质量问题
- 零件故障
- 性能异常
不在保修范围:
- 人为损坏
- 自然磨损
- 未按说明书使用
产品使用指导
我们提供详细的产品使用指南:
- 产品包装内含说明书
- 官网提供电子版手册
- 可观看视频教程
如需一对一指导,可预约我们的产品专家进行在线培训。
账户与支付
支付方式
我们支持以下支付方式:
- 微信支付
- 支付宝
- 银行卡支付
- 企业对公转账
对公转账需提前联系客服获取账户信息。
发票与账单
企业客户可申请月结账单,需提供:
- 营业执照
- 授权委托书
- 企业信用代码
月结客户享有信用额度,额度内可先消费后付款。
积分与优惠
注册会员即可享受积分奖励:
- 消费 1 元 = 1 积分
- 积分可抵扣现金(100 积分 = 1 元)
- 生日月双倍积分
定期推出优惠券、满减活动,请关注我们的公告。
常见问题
忘记密码
点击登录页面"忘记密码",通过手机号或邮箱重置密码。
无法支付
可能原因:
- 网络问题
- 支付余额不足
- 银行风控限制
建议:
- 切换支付方式
- 更换网络环境
- 联系银行客服
联系方式
- 客服电话:400-XXX-XXXX
- 在线客服:企业微信搜索
- 邮箱:service@company.com
- 工作时间:周一至周五 9:00-18:00
紧急情况请直接致电客服电话。
{
"name": "wecom-automation",
"version": "1.0.0",
"description": "企业微信个人账号直连自动化 - 基于 Wechaty",
"main": "bot.js",
"scripts": {
"start": "node bot.js",
"dev": "node --watch bot.js",
"test": "node test/test.js"
},
"keywords": [
"wechaty",
"wecom",
"bot",
"automation"
],
"author": "OpenClaw",
"license": "MIT",
"dependencies": {
"wechaty": "^1.20.2",
"wechaty-puppet-padlocal": "^1.0.0",
"wechaty-puppet-service": "^1.0.0",
"dotenv": "^16.3.1",
"axios": "^1.6.0",
"pg": "^8.11.3",
"node-schedule": "^2.1.1",
"winston": "^3.11.0"
},
"devDependencies": {
"nodemon": "^3.0.1"
},
"engines": {
"node": ">=16.0.0"
}
}
# Python 依赖
# LLM
openai>=1.0.0
# 数据库
psycopg2-binary>=2.9.9
pgvector>=0.2.4
# HTTP 请求
requests>=2.31.0
# 文件处理
python-docx>=1.1.0
PyPDF2>=3.0.1
pdfplumber>=0.10.3
# 图片处理
Pillow>=10.1.0
# 环境变量
python-dotenv>=1.0.0
# 日志
colorlog>=6.8.0
/**
* 消息处理工作流
*/
const { spawn } = require('child_process');
const path = require('path');
/**
* 处理文本消息(核心问答逻辑)
*/
async function handleTextMessage(msg) {
const from = msg.from();
const room = msg.room();
const text = msg.text();
try {
// 调用 Python 问答处理
const result = await runPythonScript('answer_question.py', [
'--user-id', from.id,
'--user-name', from.name(),
'--question', text,
...(room ? ['--room-name', room.topic()] : [])
]);
// 发送回复
if (result.success) {
if (result.escalated) {
// 已转人工,发送提示
await msg.say(result.answer);
} else {
// 自动回复
await msg.say(result.answer);
}
} else {
throw new Error('问答处理失败');
}
} catch (error) {
console.error('处理文本消息失败:', error);
await msg.say('😔 处理消息时遇到错误,已为您转接人工客服');
await escalateToHuman(from, text, error.message);
}
}
/**
* 处理文件消息
*/
async function handleFileMessage(msg) {
const from = msg.from();
const fileBox = await msg.toFileBox();
try {
// 下载文件
const fileName = fileBox.name;
const filePath = path.join(__dirname, '../tmp', fileName);
await fileBox.toFile(filePath);
console.log(`文件已保存: ${filePath}`);
// 发送确认
await msg.say(`✅ 已收到文件:${fileName}\n\n正在处理,请稍候...`);
// 调用 Python 处理文件
const result = await runPythonScript('process_file.py', [
'--file-path', filePath,
'--user-id', from.id,
'--user-name', from.name()
]);
if (result.success) {
await msg.say(result.answer);
} else {
throw new Error(result.error || '文件处理失败');
}
} catch (error) {
console.error('处理文件失败:', error);
await msg.say(`😔 文件处理失败:${error.message}\n\n已为您转接人工客服`);
}
}
/**
* 处理图片消息
*/
async function handleImageMessage(msg) {
const from = msg.from();
const fileBox = await msg.toFileBox();
try {
// 下载图片
const fileName = `image_${Date.now()}.png`;
const filePath = path.join(__dirname, '../tmp', fileName);
await fileBox.toFile(filePath);
console.log(`图片已保存: ${filePath}`);
await msg.say('📸 正在识别图片内容...');
// 调用 Python OCR
const result = await runPythonScript('ocr_image.py', [
'--image-path', filePath,
'--user-id', from.id
]);
if (result.success && result.text) {
await msg.say(`识别结果:\n\n${result.text}`);
} else {
await msg.say('😔 无法识别图片内容,已为您转接人工客服');
}
} catch (error) {
console.error('处理图片失败:', error);
await msg.say('😔 图片处理失败,已为您转接人工客服');
}
}
/**
* 处理语音消息
*/
async function handleVoiceMessage(msg) {
const from = msg.from();
const fileBox = await msg.toFileBox();
try {
// 下载语音
const fileName = `voice_${Date.now()}.sil`;
const filePath = path.join(__dirname, '../tmp', fileName);
await fileBox.toFile(filePath);
console.log(`语音已保存: ${filePath}`);
await msg.say('🎤 正在转换语音为文字...');
// 调用 Python 语音识别
const result = await runPythonScript('transcribe_voice.py', [
'--voice-path', filePath,
'--user-id', from.id
]);
if (result.success && result.text) {
await msg.say(`识别结果:\n\n${result.text}`);
// 如果识别出文字,可以继续走问答流程
await handleTextMessage({
from: () => from,
text: () => result.text,
say: async (text) => msg.say(text)
});
} else {
await msg.say('😔 无法识别语音内容,已为您转接人工客服');
}
} catch (error) {
console.error('处理语音失败:', error);
await msg.say('😔 语音处理失败,已为您转接人工客服');
}
}
/**
* 辅助函数:运行 Python 脚本
*/
function runPythonScript(scriptName, args = []) {
return new Promise((resolve, reject) => {
const scriptPath = path.join(__dirname, '..', 'workflows', scriptName);
const python = spawn('python3', [scriptPath, ...args], {
env: {
...process.env,
PYTHONPATH: path.join(__dirname, '..')
}
});
let stdout = '';
let stderr = '';
python.stdout.on('data', (data) => {
stdout += data.toString();
});
python.stderr.on('data', (data) => {
stderr += data.toString();
});
python.on('close', (code) => {
if (code === 0) {
try {
const result = JSON.parse(stdout);
resolve(result);
} catch (error) {
reject(new Error(`解析输出失败: ${stdout}`));
}
} else {
reject(new Error(`脚本执行失败: ${stderr}`));
}
});
python.on('error', (error) => {
reject(error);
});
});
}
/**
* 辅助函数:转人工客服
*/
async function escalateToHuman(contact, question, reason = '') {
const result = await runPythonScript('escalate.py', [
'--user-id', contact.id,
'--name', contact.name(),
'--question', question,
'--reason', reason
]);
return result.success;
}
module.exports = {
handleTextMessage,
handleFileMessage,
handleImageMessage,
handleVoiceMessage
};
/**
* 事件处理工作流
* 好友添加、进群、退群等
*/
const { spawn } = require('child_process');
const path = require('path');
/**
* 处理好友添加
*/
async function handleFriendAdd(friendship) {
const contact = friendship.contact();
try {
console.log(`收到好友请求: ${contact.name()} (${contact.id})`);
console.log(`验证信息: ${friendship.hello()}`);
// 自动通过好友请求
await friendship.accept();
console.log('✅ 已通过好友请求');
// 等待一下,确保好友关系建立
await new Promise(resolve => setTimeout(resolve, 1000));
// 发送欢迎消息
const welcomeMsg = `👋 欢迎来到${contact.name()}!
我是智能助手小a 🤖,可以帮您:
📋 查询订单状态
❓ 解答常见问题
🔄 处理售后问题
📁 处理文件(DOCX、PDF等)
🖼️ 图片识别(OCR)
🎤 语音转文字
如需帮助,请直接发送消息或文件。
如有复杂问题,我会自动转接人工客服为您服务。
💡 提示:您可以随时发送"帮助"查看更多功能`;
await contact.say(welcomeMsg);
console.log('✅ 已发送欢迎消息');
// 调用 Python 脚本保存用户信息
await saveUser(contact);
// 发送通知给管理员
await notifyAdmin(`🆕 新好友:${contact.name()} (${contact.id})`);
} catch (error) {
console.error('处理好友添加失败:', error);
}
}
/**
* 处理进群事件
*/
async function handleRoomJoin(room, inviteeList, inviter) {
const topic = room.topic();
const inviterName = inviter ? inviter.name() : '未知';
console.log(`🚪 进群事件: ${topic}`);
console.log(`邀请人: ${inviterName}`);
try {
// 欢迎新成员
for (const invitee of inviteeList) {
await room.say(`👋 欢迎 ${invitee.name()} 加入群聊!`, invitee);
console.log(`✅ 已欢迎 ${invitee.name()}`);
}
// 发送群聊功能说明
await room.say(`我是智能助手小a 🤖,可以在群聊中帮您:
• 回答常见问题
• 识别图片内容
• 处理文档文件
@我即可使用,或直接在群内提问`);
} catch (error) {
console.error('处理进群事件失败:', error);
}
}
/**
* 处理退群事件
*/
async function handleRoomLeave(room, leaverList) {
const topic = room.topic();
console.log(`🚪 退群事件: ${topic}`);
for (const leaver of leaverList) {
console.log(`成员退出: ${leaver.name()}`);
// 记录退群日志
await logEvent('room_leave', {
room: topic,
user: leaver.name(),
user_id: leaver.id,
timestamp: new Date().toISOString()
});
}
}
/**
* 保存用户到数据库
*/
async function saveUser(contact) {
return runPythonScript('save_user.py', [
'--user-id', contact.id,
'--name', contact.name(),
'--avatar', await contact.avatar() || '',
'--source', 'we_com'
]);
}
/**
* 通知管理员
*/
async function notifyAdmin(message) {
// 通过 Telegram 通知
return runPythonScript('notify_admin.py', [
'--message', message
]);
}
/**
* 记录事件
*/
async function logEvent(eventType, data) {
return runPythonScript('log_event.py', [
'--event-type', eventType,
'--data', JSON.stringify(data)
]);
}
/**
* 运行 Python 脚本
*/
function runPythonScript(scriptName, args = []) {
return new Promise((resolve, reject) => {
const scriptPath = path.join(__dirname, '..', 'workflows', scriptName);
const python = spawn('python3', [scriptPath, ...args], {
env: {
...process.env,
PYTHONPATH: path.join(__dirname, '..')
}
});
let stdout = '';
let stderr = '';
python.stdout.on('data', (data) => {
stdout += data.toString();
});
python.stderr.on('data', (data) => {
stderr += data.toString();
});
python.on('close', (code) => {
if (code === 0) {
try {
const result = JSON.parse(stdout);
resolve(result);
} catch (error) {
resolve({ success: true, data: stdout });
}
} else {
reject(new Error(`脚本执行失败: ${stderr}`));
}
});
python.on('error', (error) => {
reject(error);
});
});
}
module.exports = {
handleFriendAdd,
handleRoomJoin,
handleRoomLeave
};
Related skills
FAQ
What does wecom-automation do?
wecom-automation automates WeCom (WeChat Work) messaging, notifications, and group workflows for enterprise product integrations. Developers use it to push alerts, onboarding messages, and ops updates through WeChat Work instead of manual chat administration.
Who should use wecom-automation?
wecom-automation suits developers building SaaS or internal tools for Chinese enterprise teams that standardize on WeChat Work. Teams on Slack-only stacks or without WeCom app credentials should choose a different messaging integration skill.