README 使用说明
多设备自媒体发布系统 MVP
FastAPI + SQLite 的任务/设备管理服务,支持 Mock 编排、任务调度和 Android ADB/Appium 适配骨架。运行时默认 PUBLISHER_MODE=mock、AUTO_CONFIRM_PUBLISH=false。Mock 成功只表示流程模拟,不表示任何平台真实发布。
当前交付状态
- 已实现:任务与设备持久化、REST API、到期调度、7 路本机执行池、Outbound Control Agent(Windows/Mac/Linux)、逐节点认证与任务 lease、素材下载/截图回传、单设备互斥、安全确认、ADB/Appium 接入骨架、Dashboard、同源写请求检查、安全 webhook、Mac
transfer_only ADB 传输验证路径、Agent 素材限额与终态暂存清理、UI 任务超时和持久化设备隔离。40 项自动测试通过。
- 实机验证:Mac 控制节点通过 HTTPS 接收任务,并向 vivo V2324A 推送测试图片;服务器任务
1 为 TRANSFER_TEST_PASSED。测试没有启动平台 App 或发布内容;Appium UI 操作尚未实测。控制 Agent 停止后设备会按心跳超时显示离线。
- 尚需实机开发验证/实现:Douyin、小红书、视频号适配器仍是安全骨架;App 包名/Activity、发布页面 selector、素材选择和表单填写、验证码/人脸/风控页面识别、发布成功校验尚未实测。模板 selector 不可用于生产。真实视频任务要求安装 ffprobe(ffmpeg 提供)。
- 当前服务器检查:Ubuntu 24.04、Python 3.12、Node 22、Docker 已有;Java/ADB/Appium/ffprobe 未安装在服务器上(手机由 Mac 控制)。项目已初始化 Git 仓库。
快速启动
cd /home/makemoney/ai-social-publisher
scripts/install.sh
scripts/start.sh
访问 https://x.jishengai.com/dashboard;项目无需操作员账号密码,打开即进入。页面和任务 API 对所有能访问该网址的人开放;请仅在可信网络中使用。服务已接入 HTTPS 域名。
后台中的“项目使用说明”入口打开 /guide,可阅读 README、架构、开发待办、开发节奏和人工测试清单。README 也可直接通过 /readme 查看,人工测试清单位于 /guide/document/MANUAL_TESTS。接口使用说明在 /docs,OpenAPI JSON 定义在 /openapi.json。当前服务器 HTTPS 入口为 https://x.jishengai.com;使用 https://x.jishengai.com/dashboard、/guide、/readme 和 /guide/document/MANUAL_TESTS。
停止:scripts/stop.sh。日志:logs/api.log。自动测试:.venv/bin/python -m pytest -q。
手工启动
cp .env.example .env
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000
.env 默认 HOST=127.0.0.1。docker compose up -d 只容器化 API/scheduler,不含 ADB/Appium/USB 设备桥接。宿主机直连 USB 手机时用本地 venv 运行。Compose 的宿主端口只绑定 loopback。
REST API
创建任务
curl -X POST http://127.0.0.1:8000/jobs \
-H 'Content-Type: application/json' \
-d '{"platform":"douyin","device_id":"phone01","content_type":"video","media_files":["/absolute/path/001.mp4"],"title":"软件公司投标为什么经常需要ITSS?","description":"今天聊一个软件企业经常遇到的问题。","hashtags":["ITSS","软件公司","招投标"],"scheduled_at":"2026-09-27T19:30:00+08:00"}'
支持 GET /jobs, GET /jobs/{id}, POST /jobs/{id}/cancel, POST /jobs/{id}/retry, POST /jobs/{id}/confirm, GET /devices, GET /health。详见 /docs。即时任务省略 scheduled_at。素材必须位于服务进程可读的本机路径。GET /devices 首次读取时同步 devices/*.yaml 到数据库。素材校验失败直接 FAILED,不自动重试。
Dashboard、文档、截图和普通任务 API 无需登录。跨站写请求会被拒绝;Control Agent 的 /agent/* 仍要求独立节点 Bearer Token。生产访问通过 HTTPS 域名。由于操作 API 不需要登录,请勿在不可信网络使用,也不要分享管理入口;请勿把 .env 提交到 Git。
Android 设备接入
- 在 Android 开启开发者选项与 USB 调试;仅连接自己拥有并已登录的手机,在手机上人工确认 RSA 调试授权。
- 安装 Android SDK Platform Tools (
adb) 和 Java 17;运行 scripts/check_devices.sh,确认序列号状态为 device(unauthorized 需在手机上人工授权)。
- 修改
devices/phone01.yaml:序列号、名称、enabled: true、平台列表与账号别名。配置文件提交前不要写真实账号个人信息。
- 运行
scripts/setup_appium.sh,以可访问 ADB 的同一宿主用户启动 Appium 2:appium --address 127.0.0.1 --port 4723。安装 UiAutomator2 所需 Android SDK,并用授权设备校验 session。
- 使用 Appium Inspector 实测无障碍树,更新
selectors/<platform>.yaml。selector 优先 resource-id / accessibility id / text;不稳定时先停止并人工处理。
- 仅在真实设备完成全流程验证后设置
PUBLISHER_MODE=android。先保持 AUTO_CONFIRM_PUBLISH=false,确认截图、账号、文案、素材正确。
手机不在服务器旁边:Android 无线调试
若服务器与手机处在同一个可信局域网/VPN,Android 11+ 可在开发者选项打开“无线调试”,用配对端口进行一次性人工配对,再用连接端口建立 ADB 会话:
scripts/connect_wireless_device.sh 192.168.1.80 37123 41657
端口以手机“无线调试”页面实际显示为准;配对端口和连接端口通常不同。只在你拥有并已解锁的手机上确认配对码。之后 adb devices -l 会显示 192.168.1.80:41657,把这个完整序列写入该设备 YAML 的 adb_serial。手机与服务器断线或 IP/端口变化时需重新连接并更新配置。此方案不需要向公网开放 ADB 端口;不要在路由器上做端口转发。
如果手机位于办公室、服务器在云上,推荐 USB 接在办公室 Windows/Mac/Linux 电脑上运行本项目的 Control Agent。手机不连接 Linux 服务器;Agent 在本地使用 ADB/Appium,并通过 HTTPS 主动向服务器领取任务、下载素材、回传截图和状态。ADB 不需要开放到网络。
Control Agent 配置
- 在服务器
devices/phone01.yaml 中填写唯一的 device_id,设 enabled: true,配置平台/账号,并将 control_node 设为例如 office01。服务器端 adb_serial 只需填唯一占位值,例如 AGENT-office01-phone01;真实 USB 序列号只放在控制电脑配置中。
- 服务器
.env 配置每节点独立随机令牌,例如:
```dotenv AGENT_TOKENS_JSON='{"office01":"替换为至少32字节随机令牌"}' ```
Agent 只支持 HTTPS 服务地址(localhost 开发除外),例如 https://x.jishengai.com。/agent/* 继续使用独立 Bearer Token;不要通过明文 HTTP 传递 Token。
- 把项目代码部署到手机旁边的 Windows/Mac/Linux 控制电脑,在该电脑安装 Python 3.11+、Node.js、Java、Android Platform Tools、ffmpeg/ffprobe 和 Appium 2 + UiAutomator2(Node.js/npm 可用后运行
scripts/setup_appium.sh;Windows 可执行 npm install --global appium 和 appium driver install uiautomator2)。手机 USB 接入后,在手机上人工确认 USB 调试授权;本机 adb devices -l 必须显示 device。
- 控制电脑的
devices/phone01.yaml 使用同一个 device_id 和 control_node: office01,adb_serial 填本机看到的真实 USB 序列号;Appium URL 用本机地址(通常 http://127.0.0.1:4723)。需要为每台手机配置真实 selector 前,先保持人工确认模式。
- 控制电脑
.env 设置 PUBLISHER_MODE=android、AUTO_CONFIRM_PUBLISH=false、AGENT_NODE_ID=office01、AGENT_SERVER_URL=https://你的服务器域名、AGENT_TOKEN(与服务器映射一致)。确保 MEDIA_ROOT 下的任务素材可被服务器读取。
- Mac/Linux 执行
scripts/run_agent.sh;Windows PowerShell 执行 scripts/run_agent.ps1。Agent 可在同一控制电脑上并发处理最多 7 台已授权手机;同一手机仍串行。服务器 Dashboard 的设备状态会显示 Agent 心跳。Linux 控制节点可使用 systemd/ai-social-publisher-agent.service;Windows/macOS 自启动模板见 deploy/agent/windows/ 和 deploy/agent/macos/。需要用户登录,USB RSA 授权仍由人手工确认。
Mac + vivo phone01 安全连接/素材传输验证
当前控制节点为 mac01,服务器设备 phone01 已启用,测试平台标识为 transfer_test。专用素材任务设置 transfer_only: true 后,只下载测试素材、通过 ADB 推送并检查文件;不会启动平台 App、不会点击发布,也不要求 Appium。
当前版本项目包:https://x.jishengai.com/downloads/ai-social-publisher-mac-agent-2026-09-27.tar.gz。在 Mac 浏览器打开下载,保存后解压:
tar -xzf ai-social-publisher-mac-agent-2026-09-27.tar.gz
cd ai-social-publisher
./scripts/install_mac_agent.sh
cp deploy/agent/macos/phone01.yaml.example devices/phone01.yaml
adb devices -l
将 devices/phone01.yaml 中的 REPLACE_WITH_MAC_ADB_SERIAL 替换为 adb devices -l 看到的 vivo 序列号。将后续发给你的加密节点配置解密为项目根目录 .env(私钥只留在 Mac):
age -d -i ~/.config/age/keys.txt agent-mac01.env.age > .env
chmod 600 .env
./scripts/start_mac_agent.sh
手机保持解锁,确认 USB 调试授权。启动后看服务器后台的设备心跳;无需在 Mac 启动 Appium。素材传输测试步骤、任务 JSON 和手机端验证命令见 /guide/document/MANUAL_TESTS 中的 T-06。测试完成后可在手机上人工删除测试图片。
任务的 media_files 必须位于服务器配置的 MEDIA_ROOT 目录内,Agent 才能下载。示例:若素材在 /data/videos,服务器 .env 设 MEDIA_ROOT=/data/videos;否则将素材放入项目 media/incoming/ 并提交该绝对路径。默认单素材上限 5 GiB、单任务素材总量上限 8 GiB、单任务最多 20 个素材;可通过 MAX_AGENT_ASSET_BYTES、MAX_AGENT_JOB_ASSET_BYTES、MAX_AGENT_ASSETS_PER_JOB 调整。Mac Agent 仅在任务进入安全终态满 168 小时后清理本地下载素材;截图、日志、数据库、服务器源素材和 NEEDS_HUMAN 任务材料不会被自动删除。
Agent 为每个任务领取有时效语义的随机 lease;Agent 掉线后,服务器会在心跳超时后将执行中任务标记 NEEDS_HUMAN 并撤销 lease,避免旧 Agent 继续覆盖服务器任务状态。服务重启和失联后的真实发布结果仍应由人工核对。
增加手机:复制 devices/phone01.yaml 为 phone02.yaml…phone07.yaml,改唯一 device_id 与 adb_serial,设置平台与账号映射;确认 adb devices -l 全部授权。多个 worker 可并行处理不同设备,同设备由数据库 claim + 进程内锁串行。多台服务器共享同一 SQLite 文件不受支持;要横向分布任务前请迁移 PostgreSQL 并采用数据库 advisory/行锁。
n8n
在 n8n HTTP Request 节点向 POST /jobs 发送 JSON;轮询 GET /jobs/{id},或在创建任务时传 callback_url。接口无需 Basic Auth。callback 仅允许 HTTPS,主机名必须与 CALLBACK_ALLOWED_HOSTS 精确匹配;发送前 DNS 解析并固定公网 IP,拒绝私网/环回/链路本地目标和重定向。设置 CALLBACK_SIGNING_SECRET 后会附加 HMAC 签名。callback 是至少一次投递,接收端按 Idempotency-Key 去重;失败指数退避并最多尝试 5 次。job 详情可查看投递次数和最后错误。私网 n8n 不能直接使用此 webhook,继续轮询 API 或部署受控公网 HTTPS 接收器。预期 payload:
{"job_id":1001,"status":"SUCCESS","device_id":"phone01","platform":"douyin","finished_at":"2026-09-27T11:40:00Z","screenshot":"/screenshots/1001/05_result.png","error":null}
在服务器 .env 配置 CALLBACK_ALLOWED_HOSTS=hooks.example.com(精确主机名,逗号分隔)后方可创建对应 callback 任务。投递失败在 15 秒起步的指数退避后重试。
服务部署
systemd/ai-social-publisher.service 是服务模板。它假定安装到 /opt/ai-social-publisher 并由 publisher 用户运行;当前工作区在 /home/makemoney,没有写入 /opt 或系统 systemd,也未启用 unit。管理员部署时需复制项目、创建受限服务用户、调整路径/属主,再执行 systemctl enable --now ai-social-publisher。不配置公网监听或防火墙规则。
安全边界与限制
系统只针对用户授权账号和设备。禁止验证码、人脸验证、登录验证、风控和权限绕过;检测到异常必须停止并由人检查。任何 selector 或结果无法确认时,将任务放入 NEEDS_HUMAN,不要盲目重试或声称发布成功。默认确认发布关闭;自动确认只适用于明确允许且完成实测的平台/账号。SQLite 适合单机 MVP;多服务器生产前仍需 Alembic、PostgreSQL 锁、审计、备份和压测。