把 pingmike2/freebuff2api-wokers 的 worker.js(v1.8.9)零改动部署到 Appwrite Functions(免费计划 75 万次执行/月,美国区域 NYC/SFO)。
把 freebuff/codebuff 的免费模型暴露成 OpenAI-compatible API,运行在 Appwrite 上(无 Cloudflare 边缘标记,规避上游 README 提示的 CF 部署封号风险)。
⚠️ Appwrite 平台硬限制(请先读)
- 同步 HTTP 执行 30 秒硬超时(Appwrite 平台强制,代码无法绕过)——慢推理请求可能超时,
stream=true的流式请求会等待上游完整结束后一次性返回,不是真流式- 响应必须完整构建后返回,不支持 SSE 流式输出
- 请求体上限 20MB
- 免费计划:2 个函数/项目、75 万次执行/月、5GB 带宽、15 分钟构建超时;函数需设置 Execute access = Any 才能公开访问
| 文件 | 状态 | 说明 |
|---|---|---|
src/worker.js |
✅ 零改动 | 上游原版 v1.8.9(pingmike2/freebuff2api-wokers commit d65d435,md5 2275333388bdd0dcbc694585bd89e00b) |
src/index.js |
🆕 新增(唯一改动点) | Appwrite 适配器:把 context.req/res 桥接为 worker.fetch(request, env) |
appwrite.config.json |
🆕 新增 | Appwrite CLI 部署配置(runtime node-22.0、entrypoint、execute=any、timeout 900) |
package.json |
🆕 新增 | Node 项目声明(type: module,无任何依赖) |
test/test-local.mjs |
🆕 新增 | 本地模拟 Appwrite context 验证(18 项断言) |
README.md |
🆕 新增 | 本说明 |
LICENSE |
✅ 上游 AGPL-3.0 | 同上游 |
改动原则:src/worker.js 一字未改,所有适配逻辑集中在 src/index.js,升级上游只需替换该文件并重新部署。
客户端 HTTP 请求
→ Appwrite 函数域名 (.appwrite.run) → context.req
→ src/index.js:
env = { FREEBUFF_TOKEN, FREEBUFF_API_KEY, API_KEY, FREEBUFF_DEBUG } ← process.env
req = new Request(context.req.url, { method, headers, body }) ← 重建 CF 兼容 Request
resp = worker.fetch(req, env) ← 调用原版 worker
→ 完整读取 resp 后 res.binary(body, status, headers) ← Appwrite 无流式
→ context.res → 客户端
- 环境变量键名与上游 CF 版完全一致(
FREEBUFF_TOKEN/FREEBUFF_API_KEY/API_KEY/FREEBUFF_DEBUG) - 自动剔除
x-open-runtimes-*系统头与transfer-encoding/content-length等 hop-by-hop 头 - 路由、鉴权、CORS、多账号切换、会话复用等全部逻辑在 worker.js 内原样生效
- 无 token 时返回
503 config_error;worker 异常时返回502 proxy_error
- 在 Appwrite Console 创建项目,选择美国区域(NYC 或 SFO)
- Functions → Create function → Connect Git repository,选择本仓库(GitHub)
- 配置:
- Runtime:
Node.js 22(node-22.0) - Root directory:
/(仓库根目录) - Entrypoint:
src/index.js - Build commands:
npm install --omit=dev - Timeout: 按需(同步执行受平台 30s 硬限,设大无意义;默认即可)
- Runtime:
- 创建后进入函数 Settings:
- Execute access → 设为 Any(否则外部请求全部被拒)
- Environment variables 添加(Secret 勾选):
FREEBUFF_TOKEN(必需,多账号逗号分隔)API_KEY或FREEBUFF_API_KEY(可选,自定义密钥)FREEBUFF_DEBUG(可选,true开调试日志)
- 保存后触发重新部署(变量变更需 redeploy 生效),push 到
main分支会自动构建部署 - 在函数 Domains 标签页复制生成的域名(如
https://xxx.fra.appwrite.run或.appwrite.run区域域名)
验证:
# 健康检查(免鉴权)
curl https://<FUNCTION_DOMAIN>/healthz
# 模型列表(带 key)
curl -H "Authorization: Bearer <YOUR_API_KEY>" https://<FUNCTION_DOMAIN>/v1/models
# OpenAI 兼容对话(注意 30s 超时限制)
curl -X POST https://<FUNCTION_DOMAIN>/v1/chat/completions \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}]}'npm i -g appwrite-cli
appwrite login
# 编辑 appwrite.config.json 填入你的 projectId / endpoint
appwrite init project
appwrite push functions # 推送函数配置 + 部署代码
appwrite functions create-variable --function-id suibuff --key FREEBUFF_TOKEN --value <token> --secretnode test/test-local.mjs
# 期望: 18 passed, 0 failed(healthz/OPTIONS/401/models/503/404/头透传)| 方法 | 路径 | 鉴权 |
|---|---|---|
| GET | /healthz |
免鉴权 |
| OPTIONS | 任意 | 免鉴权(CORS 预检) |
| GET | /v1/models、/models |
需 key |
| POST | /v1/chat/completions、/chat/completions |
需 key |
| POST | /v1/responses、/responses |
需 key |
| POST | /v1/messages、/messages、count_tokens |
需 key |
- 上游: https://github.com/pingmike2/freebuff2api-wokers (AGPL-3.0,Copyright pingmike2 / XxxXTeam)
- Appwrite Functions 文档: https://appwrite.io/docs/products/functions
- 配套仓库: vercel-suibuff / render-suibuff