From 6aebc60bfdc1af9b7751635812207f5d7cdaeafc Mon Sep 17 00:00:00 2001 From: cirry <812852553@qq.com> Date: Tue, 9 Jun 2026 14:50:53 +0800 Subject: [PATCH] first commit --- .data/wechat/messages.jsonl | 16 + .dockerignore | 2 + .env.example | 130 +++++++ .gitignore | 10 + .husky/pre-commit | 1 + .npmrc | 1 + .prettierrc.cjs | 23 ++ .vscode/settings.json | 3 + Dockerfile | 58 +++ Dockerfile.alpine | 45 +++ LICENSE.md | 9 + README.md | 526 ++++++++++++++++++++++++++ RECORD.md | 30 ++ cli.js | 4 + docs/pi-im-agent.md | 219 +++++++++++ package.json | 75 ++++ sponsors/91api.jpg | Bin 0 -> 71930 bytes sponsors/shenfengwl.png | Bin 0 -> 3860596 bytes src/302ai/__test__.js | 9 + src/302ai/index.js | 41 ++ src/adapters/lark.js | 79 ++++ src/adapters/opencli.js | 27 ++ src/adapters/pi.js | 39 ++ src/analysis/__test__.js | 56 +++ src/analysis/wechatAnalyzer.js | 95 +++++ src/chatgpt/index.js | 35 ++ src/claude/index.js | 72 ++++ src/config/env.js | 50 +++ src/deepseek-free/__test__.js | 9 + src/deepseek-free/index.js | 49 +++ src/deepseek/__test__.js | 9 + src/deepseek/index.js | 36 ++ src/dify/__test__.js | 9 + src/dify/index.js | 39 ++ src/doubao/__test__.js | 12 + src/doubao/index.js | 53 +++ src/index.js | 259 +++++++++++++ src/kimi/__test__.js | 8 + src/kimi/index.js | 94 +++++ src/ollama/__test__.js | 9 + src/ollama/index.js | 45 +++ src/openai/__test__.js | 9 + src/openai/index.js | 37 ++ src/pi/index.js | 13 + src/platforms/wechat/bot.js | 75 ++++ src/platforms/wechat/commandRouter.js | 81 ++++ src/platforms/wechat/messageStore.js | 96 +++++ src/tongyi/index.js | 42 ++ src/utils/process.js | 53 +++ src/wechaty/sendMessage.js | 136 +++++++ src/wechaty/serve.js | 42 ++ src/wechaty/testMessage.js | 105 +++++ src/xunfei/__test__.js | 9 + src/xunfei/index.js | 9 + src/xunfei/xunfei.js | 133 +++++++ 55 files changed, 3126 insertions(+) create mode 100644 .data/wechat/messages.jsonl create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 .husky/pre-commit create mode 100644 .npmrc create mode 100644 .prettierrc.cjs create mode 100644 .vscode/settings.json create mode 100644 Dockerfile create mode 100644 Dockerfile.alpine create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 RECORD.md create mode 100644 cli.js create mode 100644 docs/pi-im-agent.md create mode 100644 package.json create mode 100644 sponsors/91api.jpg create mode 100644 sponsors/shenfengwl.png create mode 100644 src/302ai/__test__.js create mode 100644 src/302ai/index.js create mode 100644 src/adapters/lark.js create mode 100644 src/adapters/opencli.js create mode 100644 src/adapters/pi.js create mode 100644 src/analysis/__test__.js create mode 100644 src/analysis/wechatAnalyzer.js create mode 100644 src/chatgpt/index.js create mode 100644 src/claude/index.js create mode 100644 src/config/env.js create mode 100644 src/deepseek-free/__test__.js create mode 100644 src/deepseek-free/index.js create mode 100644 src/deepseek/__test__.js create mode 100644 src/deepseek/index.js create mode 100644 src/dify/__test__.js create mode 100644 src/dify/index.js create mode 100644 src/doubao/__test__.js create mode 100644 src/doubao/index.js create mode 100644 src/index.js create mode 100644 src/kimi/__test__.js create mode 100644 src/kimi/index.js create mode 100644 src/ollama/__test__.js create mode 100644 src/ollama/index.js create mode 100644 src/openai/__test__.js create mode 100644 src/openai/index.js create mode 100644 src/pi/index.js create mode 100644 src/platforms/wechat/bot.js create mode 100644 src/platforms/wechat/commandRouter.js create mode 100644 src/platforms/wechat/messageStore.js create mode 100644 src/tongyi/index.js create mode 100644 src/utils/process.js create mode 100644 src/wechaty/sendMessage.js create mode 100644 src/wechaty/serve.js create mode 100644 src/wechaty/testMessage.js create mode 100644 src/xunfei/__test__.js create mode 100644 src/xunfei/index.js create mode 100644 src/xunfei/xunfei.js diff --git a/.data/wechat/messages.jsonl b/.data/wechat/messages.jsonl new file mode 100644 index 0000000..5d56257 --- /dev/null +++ b/.data/wechat/messages.jsonl @@ -0,0 +1,16 @@ +{"id":"8176687339562140017","timestamp":"2026-06-09T06:25:33.164Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"6001436733549628695","timestamp":"2026-06-09T06:25:33.779Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"5974728366622606792","timestamp":"2026-06-09T06:25:33.780Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"4991830149134227925","timestamp":"2026-06-09T06:25:46.748Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"你好啊","self":false} +{"id":"4480028056455094172","timestamp":"2026-06-09T06:25:59.073Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"你会说话吗","self":false} +{"id":"1771518838726007766","timestamp":"2026-06-09T06:29:19.414Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"你好啊","self":false} +{"id":"3554307033158000287","timestamp":"2026-06-09T06:29:32.316Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"???","self":false} +{"id":"5224657246230665616","timestamp":"2026-06-09T06:29:50.240Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"2477581012569855746","timestamp":"2026-06-09T06:30:06.335Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"!?","self":false} +{"id":"6196330599325256651","timestamp":"2026-06-09T06:36:53.739Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"5837753676322003487","timestamp":"2026-06-09T06:36:53.740Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"3492185411778314662","timestamp":"2026-06-09T06:36:59.966Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"你好","self":false} +{"id":"8895573730091772400","timestamp":"2026-06-09T06:39:01.591Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"啊","self":false} +{"id":"3571933861420079183","timestamp":"2026-06-09T06:39:02.246Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"8010648486659081543","timestamp":"2026-06-09T06:39:02.246Z","type":0,"typeName":"Unknown","isText":false,"isRoom":false,"roomName":"","talkerName":"菜小猪","talkerAlias":"","receiverName":"菜小猪","text":"","self":true} +{"id":"6422080270206561680","timestamp":"2026-06-09T06:43:24.642Z","type":7,"typeName":"Text","isText":true,"isRoom":false,"roomName":"","talkerName":"AnShooter","talkerAlias":"","receiverName":"菜小猪","text":"啊","self":false} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bb6de05 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ + +node_modules/ \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ebab9e7 --- /dev/null +++ b/.env.example @@ -0,0 +1,130 @@ +# .env + +# OpenAi 的api key, 去 https://beta.openai.com/account/api-keys 中生成一个即可,OPENAI_MODEL不填则默认gpt-4o,OPENAI_SYSTEM_MESSAGE为默认角色设定 +OPENAI_API_KEY='' +OPENAI_PROXY_URL='https://openai.xxxx.com/v1/' +OPENAI_MODEL='' +OPENAI_SYSTEM_MESSAGE='You are a personal assistant.' + +# doubao, model和api-key, 去 https://console.volcengine.com/ark/apiKey +DOUBAO_API_KEY='' +DOUBAO_URL="https://ark.cn-beijing.volces.com/api/v3" +DOUBAO_MODEL='doubao-seed-1-6-thinking-250615' + +# deepseek, model和api-key, 去 https://platform.deepseek.com/usage 或者 https://cloud.siliconflow.cn/models (deepseek官方api暂时停止使用,可以用siliconflow的api) +DEEPSEEK_API_KEY='' +DEEPSEEK_URL="https://api.siliconflow.cn/v1" +DEEPSEEK_MODEL='deepseek-ai/DeepSeek-R1' +DEEPSEEK_SYSTEM_MESSAGE='# 角色定义 +role: "AI Assistant (DeepSeek-R1-Enhanced)" +author: "DeepSeek" +description: > + 通用型智能助手,通过结构化思考流程提供可靠服务, + 知识截止2023年12月,不处理实时信息。 +# 交互协议 +interaction_rules: + thinking_flow: # 新增思考流程规范 + - 步骤1: 问题语义解析(意图/实体/上下文) + - 步骤2: 知识库匹配(学科分类/可信度评估) + - 步骤3: 逻辑验证(矛盾检测/边界检查) + - 步骤4: 响应结构设计(分点/示例/注意事项) + safety_layer: + - 自动激活场景: [政治, 医疗建议, 隐私相关] + - 响应模板: "该问题涉及[领域],建议咨询专业机构" +# 输出规范 +output_schema: + thinking_section: # 强制思考段落 + required: true + tags: "思考内容:{content} +" + content_rules: + - 使用Markdown列表格式 + - 包含至少2个验证步骤 + - 标注潜在不确定性 + - 复杂概念使用类比解释' + +# Kimi 的api key, 去 https://platform.moonshot.cn/console/api-keys +KIMI_API_KEY='' + +# 科大讯飞, 去 https://console.xfyun.cn/services +XUNFEI_APP_ID='' +XUNFEI_API_KEY='' +XUNFEI_API_SECRET='' +# 使用的模型版本,默认填写 v4.0 或需要的版本号(如: v3.5, max-32k, pro-128k),参考src/xunfei.js中modelVersionMap +XUNFEI_MODEL_VERSION='v4.0' +# 系统角色描述,支持个性化定制 +XUNFEI_PROMPT='你是一个专业的智能助手,能够回答用户提出的各种问题。' + +# deepseek-free, model必须为deepseek-chat或deepseek-coder,去 https://platform.deepseek.com/usage或者https://github.com/LLM-Red-Team/deepseek-free-api +# 在DEEPSEEK_SYSTEM_MESSAGE中设置系统提示词 +DEEPSEEK_FREE_URL='https://api.deepseek.com/chat/completions' +DEEPSEEK_FREE_TOKEN='' +DEEPSEEK_FREE_MODEL='deepseek-chat' +DEEPSEEK_FREE_SYSTEM_MESSAGE='You are a personal assistant.' + +# 302AI +_302AI_API_KEY = '' +_302AI_MODEL= 'gpt-4o-mini' + +# dify, URL不包含uri路径 +DIFY_API_KEY = '' +DIFY_URL = 'https://api.dify.ai' + +# 通义千问, URL 包含 uri 路径 +TONGYI_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1" + +# 通义千问的 API_KEY +TONGYI_API_KEY = '' + +# 通义千问使用的模型 +TONGYI_MODEL='qwen-plus' + +# claude +CLAUDE_API_VERSION = '2023-06-01' +CLAUDE_API_KEY = '' +CLAUDE_MODEL = 'claude-sonnet-4-5-20250929' +CLAUDE_BASE_URL = 'https://api.anthropic.com/v1/messages' +# 系统人设 +CLAUDE_SYSTEM = '' + +# ollama +OLLAMA_URL='http://127.0.0.1:11434/api/chat' +OLLAMA_MODEL='' +OLLAMA_SYSTEM_MESSAGE='You are a personal assistant.' + +# 白名单配置 +#定义机器人的名称,这里是为了防止群聊消息太多,所以只有艾特机器人才会回复, +#这里不要把@去掉,在@后面加上你启动机器人账号的微信名称 +BOT_NAME='@可乐' +#联系人白名单 +ALIAS_WHITELIST='微信名1,备注名2' +#群聊白名单 +ROOM_WHITELIST='XX群1,群2' +#自动回复前缀匹配,文本消息匹配到指定前缀时,才会触发自动回复,不配或配空串情况下该配置不生效(适用于用大号,不期望每次被@或者私聊时都触发自动回复的人群) +#匹配规则:群聊消息去掉${BOT_NAME}并trim后进行前缀匹配,私聊消息trim后直接进行前缀匹配 +AUTO_REPLY_PREFIX='' + +# 默认服务 302AI,ChatGPT、Kimi、Xunfei、deepseek-free, ollama, dify, tongyi 八选一,不填则键盘交互 +SERVICE_TYPE='' + +# 本地微信消息捕获与命令 +# 默认只记录扫码登录后收到的消息,用于后续本地统计/分析;设为 false 可关闭记录 +WECHAT_DATA_DIR='.data/wechat' +WECHAT_STORE_MESSAGES='true' +BOT_COMMAND_PREFIX='/' +# 出于安全考虑,微信聊天中远程执行 OpenCLI 默认关闭;仅在你确认需要时开启 +ENABLE_REMOTE_OPENCLI='false' + +# 飞书 IM 通过 lark-cli 接入。首次使用可执行:npm run lark:login +LARK_CLI_BIN='lark-cli' +LARK_DEFAULT_IDENTITY='user' + +# OpenCLI 透传。留空时会使用 npx --yes @jackwener/opencli +OPENCLI_BIN='' +OPENCLI_NPM_PACKAGE='@jackwener/opencli' + +# Pi coding agent 透传。留空时会使用 npx --yes @earendil-works/pi-coding-agent +PI_BIN='' +PI_NPM_PACKAGE='@earendil-works/pi-coding-agent' +# Pi 作为 IM 回复 agent 时使用的参数。默认非交互、单轮回复。 +PI_AGENT_ARGS='--print --no-session' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4ee56c --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules +WechatEveryDay.memory-card.json +.env +test.js +package-lock.json +yarn.lock +Chromium.app + +.DS_Store +.idea \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..d0a7784 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..bf8922a --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +# puppeteer_download_host=https://registry.npmmirror.com/-/binary/ \ No newline at end of file diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..9a21c15 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,23 @@ +/** + * 参考 https://prettier.io/docs/en/options.html + */ +module.exports = { + tabWidth: 2, // 空格数 + useTabs: false, // 是否开启tab + printWidth: 150, // 换行的宽度 + semi: false, // 是否在语句末尾打印分号 + singleQuote: true, // 是否使用单引号 + quoteProps: 'as-needed', // 对象的key仅在需要时用引号 as-needed|consistent|preserve + trailingComma: 'all', // 多行时尽可能打印尾随逗号 |all|es5|none + rangeStart: 0, // 每个文件格式化的范围是文件的全部内容 + bracketSpacing: true, // 对象文字中的括号之间打印空格 + jsxSingleQuote: true, // 在JSX中是否使用单引号 + bracketSameLine: false, // 将HTML元素的闭括号放在最后一行的末尾(不适用于自闭合元素)。 + arrowParens: 'always', // 箭头函数,只有一个参数的时候,也需要括号 always|avoid + htmlWhitespaceSensitivity: 'ignore', // html中换行规则 css|strict|ignore,strict会强制在标签周围添加空格 + vueIndentScriptAndStyle: false, // vue中script与style里的第一条语句是否空格 + singleAttributePerLine: false, // 每行强制单个属性 + endOfLine: 'lf', // 换行符 + proseWrap: 'never', // 当超出print width时就折行 always|never|preserve .md文件? + embeddedLanguageFormatting: 'auto', +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..978009b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cSpell.words": ["kimi", "xunfei"] +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ea50c45 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +ARG APT_SOURCE="default" + +FROM node:19 as builder-default +ENV NPM_REGISTRY="https://registry.npmjs.org" + +FROM node:19 as builder-aliyun + +ENV NPM_REGISTRY="https://registry.npmmirror.com" +RUN sed -i s/deb.debian.org/mirrors.aliyun.com/g /etc/apt/sources.list \ + && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone + +FROM builder-${APT_SOURCE} AS builder +# Instal the 'apt-utils' package to solve the error 'debconf: delaying package configuration, since apt-utils is not installed' +# https://peteris.rocks/blog/quiet-and-unattended-installation-with-apt-get/ +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-utils \ + autoconf \ + automake \ + bash \ + build-essential \ + ca-certificates \ + chromium \ + coreutils \ + curl \ + ffmpeg \ + figlet \ + git \ + gnupg2 \ + jq \ + libgconf-2-4 \ + libtool \ + libxtst6 \ + moreutils \ + python-dev \ + shellcheck \ + sudo \ + tzdata \ + vim \ + wget \ + && apt-get purge --auto-remove \ + && rm -rf /tmp/* /var/lib/apt/lists/* + +FROM builder + +ENV CHROME_BIN="/usr/bin/chromium" \ + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true" + +RUN mkdir -p /app +WORKDIR /app + +COPY package.json ./ +RUN npm config set registry ${NPM_REGISTRY} && npm i + +COPY *.js ./ +COPY src/ ./src/ + +CMD ["npm", "run", "dev"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..4288be4 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,45 @@ +ARG APT_SOURCE="default" + +FROM node:19-alpine as base +RUN apk update && \ + apk upgrade && \ + apk add --no-cache bash \ + ca-certificates \ + chromium-chromedriver \ + chromium \ + coreutils \ + curl \ + ffmpeg \ + figlet \ + jq \ + moreutils \ + ttf-freefont \ + udev \ + vim \ + xauth \ + xvfb \ + && rm -rf /tmp/* /var/cache/apk/* + + +FROM base as builder-default +ENV NPM_REGISTRY="https://registry.npmjs.org" + +FROM base as builder-aliyun +ENV NPM_REGISTRY="https://registry.npmmirror.com" + + +FROM builder-${APT_SOURCE} + +ENV CHROME_BIN="/usr/bin/chromium-browser" \ + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true" + +RUN mkdir -p /app +WORKDIR /app + +COPY package.json ./ +RUN npm config set registry ${NPM_REGISTRY} && npm i + +COPY *.js ./ +COPY src/ ./src/ + +CMD ["npm", "run", "dev"] diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f92b339 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2020-present, 荣顶 and wechat-bot contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..24bfaf1 --- /dev/null +++ b/README.md @@ -0,0 +1,526 @@ +# WeChat Bot + +一个基于 `Wechaty` 的微信 / IM agent 项目。 + +它可以把微信扫码登录后的 IM 消息交给 ChatGPT、DeepSeek、Ollama、Claude、Pi 等服务处理;也可以通过 OpenCLI 的 `wx-cli` 访问本机微信聊天、联系人、群成员、收藏、朋友圈缓存,并对群聊或某个好友做统计和分析。飞书 IM 目前提供登录、读消息、搜消息和发消息的 CLI 通道。 + +如果你希望把 Pi 作为本项目的 agent,用微信作为外部通信渠道,直接看:[Pi Agent + IM 使用说明](./docs/pi-im-agent.md)。 + +## 能力概览 + +| 能力 | 命令入口 | 当前状态 | +| ------------------------------ | ------------------------------------------------------------ | -------------------------------------------- | +| 微信扫码 IM | `wb agent --im wechat --agent pi` / `wb start --serve pi` | 已接入,可扫码登录并回复白名单消息 | +| Pi 作为项目 agent | `wb agent --im wechat --agent pi` | 已接入,默认单轮非交互回复 | +| 本地微信聊天 / 联系人 / 群成员 | `wb wx sessions`、`wb wx history`、`wb wx members` | 通过 OpenCLI `wx-cli` 接入 | +| 本地朋友圈缓存 | `wb wx sns-feed`、`wb wx sns-search` | 通过 OpenCLI `wx-cli` 接入 | +| 群 / 好友分析 | `wb analyze --room "群名"`、`wb analyze --friend "好友备注"` | 支持本地统计和 AI 深度分析 | +| 飞书 IM | `wb lark login`、`wb lark messages`、`wb lark send` | 支持登录、读、搜、发;暂未做实时事件自动回复 | +| 多模型回复 | `--serve ChatGPT/deepseek/ollama/pi/...` | 复用现有 provider 机制 | + +## 快速开始:Pi + 微信 IM + +```sh +npm i +cp .env.example .env +npm link +``` + +在 `.env` 中至少配置: + +```env +BOT_NAME='@你的微信昵称' +ALIAS_WHITELIST='允许私聊你的好友备注' +ROOM_WHITELIST='允许接入的群名' + +PI_BIN='pi' +PI_AGENT_ARGS='--print --no-session' +WECHAT_STORE_MESSAGES='true' +``` + +启动: + +```sh +wb agent --im wechat --agent pi +``` + +终端出现二维码后,用微信扫码。消息链路是: + +```text +微信扫码登录 -> Wechaty 收消息 -> 本地 JSONL 捕获 -> Pi agent 回复 -> 微信 IM 发回 +``` + +触发规则: + +- 私聊:好友备注或昵称需要在 `ALIAS_WHITELIST`。 +- 群聊:群名需要在 `ROOM_WHITELIST`,并且消息里需要 `@BOT_NAME`。 +- 非文本消息不会自动进入回复链路。 + +> 注意:微信 Web 协议存在风控和封号风险。请只在你明确接受风险的账号和场景中使用,优先控制白名单和使用范围。 + +
+ +## 贡献者们 + + +
|
+| --- | --- |
+
+### 运行报错等问题
+
+首先你需要做到以下几点:
+
+- 拉取最新代码,重新安装依赖(删除 lock 文件,删除 node_modules)
+- 安装依赖时最好不要设置 npm 镜像
+- 遇到 puppeteer 安装失败设置环境变量:
+
+ ```
+ # Mac
+ export PUPPETEER_SKIP_DOWNLOAD='true'
+
+ # Windows
+ SET PUPPETEER_SKIP_DOWNLOAD='true'
+ ```
+
+- 如果使用云端模型,确保终端网络可以访问对应模型服务(开全局代理,或者手动设置终端代理)
+
+ ```sh
+ # 设置代理
+ export https_proxy=http://127.0.0.1:你的代理服务端口号;export http_proxy=http://127.0.0.1:你的代理服务端口号;export all_proxy=socks5://127.0.0.1:你的代理服务端口号
+ # 然后执行对应服务测试,或先查看 CLI 是否正常
+ node ./cli.js --help
+ ```
+
+ 
+
+- 如果使用 OpenAI / Claude / Kimi 等云端模型,确认 API Key、余额、模型名和代理配置正确
+- 配置好 `.env` 文件,尤其是 `BOT_NAME`、白名单和当前 `--serve` 服务所需参数
+- 执行 `npm run test:analysis` 验证本地分析模块,执行 `node ./cli.js --help` 验证 CLI
+- 执行 `wb agent --im wechat --agent pi` 或 `wb start --serve <服务名>` 启动微信扫码
+
+也可以参考这条 [issue](https://github.com/wangrongding/wechat-bot/issues/54#issuecomment-1347880291)
+
+- 怎么玩? 完成自定义修改后,群聊时,在白名单中的群,有人 @你 时会触发自动回复,私聊中,联系人白名单中的人发消息给你时会触发自动回复。
+- 运行报错?检查 node 版本是否符合,如果不符合,升级 node 版本即可,检查依赖是否安装完整,如果不完整,大陆推荐切换下 npm 镜像源,然后重新安装依赖即可。(可以用我的 [prm-cli](https://github.com/wangrongding/prm-cli) 工具快速切换)
+- 调整对话模式?优先通过 `--serve` 切换服务;需要定制业务逻辑时看 [sendMessage.js](./src/wechaty/sendMessage.js)、[commandRouter.js](./src/platforms/wechat/commandRouter.js) 和对应 provider 实现。
+
+## 使用 Docker 部署
+
+```sh
+$ docker build . -t wechat-bot
+
+$ docker run -d --rm --name wechat-bot -v $(pwd)/.env:/app/.env wechat-bot
+```
+
+- 如果docker build过程中node反复下载超时,可先下载nodejs镜像到本地镜像库,并将DockerFile中的'node:19'修改为本地nodejs镜像版本
+
+## Star History Chart
+
+该项目于 2023/2/13 日成为 Github Trending 榜首。
+
+[](https://star-history.com/#wangrongding/wechat-bot&Date)
+
+## License
+
+[MIT](./LICENSE).
diff --git a/RECORD.md b/RECORD.md
new file mode 100644
index 0000000..738d58d
--- /dev/null
+++ b/RECORD.md
@@ -0,0 +1,30 @@
+# 使用最近很火的 OpenAi ChatGPT 配合 Wechaty 实现一个 微信聊天機器人
+
+## 前言
+
+使用 OpenAi ChatGPT 和 Wechaty 可以实现一个微信聊天机器人。OpenAi ChatGPT 是一个大型语言模型,能够模拟人类聊天对话,并回答用户的问题。Wechaty 是一个 Node.js 库,可以让开发者轻松地接入微信并实现聊天机器人功能。
+
+首先,需要安装 Node.js 和 npm(Node.js 包管理器)。安装完成后,使用 npm 安装 Wechaty 和 OpenAi ChatGPT。
+
+## 什么是 OpenAi ChatGPT
+
+OpenAI ChatGPT 是一个语言模型,由 OpenAI 开发。它是基于 GPT-3(Generative Pretrained Transformer-3)架构的,用于对话和聊天的自然语言处理(NLP)任务。它的目的是通过模仿人类的语言方式来生成文本。
+
+与其他语言模型不同,OpenAI ChatGPT 可以记忆之前的对话内容,并根据上下文和预先学习的知识来生成自然的回复。它可以用于支持机器人,聊天机器人和其他应用程序,以提供更加人性化和自然的对话体验。
+
+OpenAI ChatGPT 模型使用了大量的语料数据进行预训练,并通过机器学习算法来优化其生成文本的能力。它具有出色的自然语言理解能力,可以模拟人类的语言特征,如句子结构、语法和修辞手法。
+
+总的来说,OpenAI ChatGPT 是一个非常强大的语言模型,可以用于实现多种 NLP 应用程序,以提高对话和聊天的自然语言处理能力。
+
+## 什么是 Wechaty
+
+## 一些相关链接
+
+- [OpenAI ChatGPT](https://openai.com/blog/chatting/)
+- [Wechaty](https://wechaty.js.org/)
+- [Wechaty Chatbot](https://wechaty.js.org/docs/examples/chatbot/)
+- [Wechaty Chatbot Tutorial](https://wechaty.js.org/docs/tutorials/chatbot-tutorial/)
+
+- https://openai.com/blog/chatgpt/
+- https://download-chromium.appspot.com/?platform=Mac_Arm&type=snapshots
+- https://registry.npmmirror.com/binary.html?path=chromium-browser-snapshots/Mac_Arm/
diff --git a/cli.js b/cli.js
new file mode 100644
index 0000000..f1bf3f8
--- /dev/null
+++ b/cli.js
@@ -0,0 +1,4 @@
+#! /usr/bin/env node
+
+'use strict'
+import('./src/index.js')
diff --git a/docs/pi-im-agent.md b/docs/pi-im-agent.md
new file mode 100644
index 0000000..797ba9a
--- /dev/null
+++ b/docs/pi-im-agent.md
@@ -0,0 +1,219 @@
+# Pi Agent + IM 使用说明
+
+这份文档说明如何把当前项目作为 Pi agent 的运行壳,用 IM 作为外部通信渠道。
+
+## 目标链路
+
+```text
+外部 IM 消息 -> wechat-bot -> Pi agent -> IM 回复
+```
+
+当前已实现:
+
+- 微信 IM:扫码登录后接收/回复消息。
+- Pi agent:作为 `serve` 类型处理微信消息。
+- 本地微信数据:通过 OpenCLI `wx-cli` 访问聊天、群成员、统计和朋友圈缓存。
+- 飞书 IM:通过 `lark-cli` 登录、发消息、读消息、搜索消息。
+
+## 安装命令
+
+如果希望直接使用 `wb` 命令,在项目根目录执行:
+
+```sh
+npm link
+```
+
+也可以不用 `wb`,直接使用:
+
+```sh
+npm run start -- DczQt4GyMCisp5yK0`CVW7i
z)+={~-)hvH!#M6>kL{!Ex#D8ID;w(;?q3~`Y)(w BoFjEDH5EZ-c9(k5Qu;isnutioREtN;j+<~yjIFtJ2)_3mpACC4e0VjUS
ze`m!Cz3Nmd!LhEsmmVUT@3EY#lp=~iMu(G|JU?=K%ltS=N*j%8Ayodw%?wcW3;Dl?0eZ#Q)dJ6t>8lq%MXB@Fk?)GdWYH()>c?
zIsyD6{3Ed^M_Pj5m5=;Kb3Xx8nAZoH#zH6B={)$!RCj#&E-WWplxKSJa_i!Bar{=d
z=IwKO64>aSRiytF#Ly~SDgbK$`Z%nhSWwUth
ZQXTPUWl>g);7UHILoq2x7d=7UU*CQIP!`7x%2pX{H%QO
z(ij{OFl3;nO$0Bsn+GS(uR}=lKLdj7t~N;&X>M%4;BwDP8x*Tv5Xvzo;(mZ
zr?Vh;JhB@;r+bSyZfRykel*tDf-gHQ%tHm`cDNBHuw*W4mOV@6)rh>2op)Jr_B)W<)2YZi-_?7KTl)j@
zzfkP3s4HhN0aEQ`?ux^j;^MWtHY-#4l%VCa^~18x&ANVnI+ms7qQ?4UNNb1UOHtM#
z0)k<&<&$3?2nm`*!=$z`%y6e*M>_KH2kmi0kT;8OvVy}k_2Vkkp2;!htH#lmu8+6P
zIqU!8c
hz(xvR#IImq!C%Z6
zXlGp&e%X666j+;K7LRaiyJA>NyOT}UDCboX`E%3JV?)ty14+Lbo=x-^?T=1*$YXvI
zP=b)#9ReGr HBLz))=Q00&Q0O;buHm3kIj|+{&8uyU9kZ6dyUgLO@5Vq^jZGO1r*aaey
zy4|AwOH$za7Xa{z<)i9<6CAZ6PhlOWJAlCWB@EtH3fj$flDo|?lq8KEianaaAM?Yl
zwBVquA%IZ_S;_bVza$4g{^Npo52GwJ{=tq5r;JlReB(?G>n=LA?)XDgyunrt&rZep
zo<-zu0#UXzs9Z`;W2L)>W6FfnpI&|E75`Fc=W*f{WxsZ!eE8IvbG)PgKk*NI#D5?}
ztqdF>chA{Q5}(IzX@Sq6^(Z)}joR^%#%>`lCQ6_cvnGqqfT;Qd25mwsEaCq!*a`g)
zgBR^Y*%ta^2j?b5^FRuTtqq