Skip to content

nick3/ImgEditWorker

Repository files navigation

ImgEditWorker - OpenAI 图片编辑 API 代理服务

一个基于 Cloudflare Workers 的高性能代理服务,提供 OpenAI 图片编辑接口到火山引擎的兼容性转换,支持 FormData 图片上传到 R2 临时存储并自动转换 API 格式。

✨ 特性

  • 🔄 API 格式转换: OpenAI 图片编辑接口 ↔ 火山引擎 API 无缝转换
  • 📁 临时文件存储: FormData 图片自动上传至 Cloudflare R2 存储桶
  • 🔑 灵活认证: 支持客户端提供的 API Key,无需预配置
  • 🗂️ 智能文件处理: 自动保留原始文件扩展名,支持 MIME 类型推断
  • 🕒 自动清理: Cron 定时任务清理过期临时文件(24小时)
  • 🧪 全面测试: 完整的单元测试和集成测试覆盖

🏗️ 架构

graph LR
    A[客户端应用] --> B[ImgEditWorker]
    B --> C[Cloudflare R2]
    B --> D[火山引擎 API]

    B --> E[定时清理任务]
    E --> C
Loading

🚀 快速开始

环境变量

项目需要设置以下环境变量:

变量名 类型 必需 描述 设置方式
AUTH_KEY_SECRET Secret 管理接口认证密钥 wrangler secret put AUTH_KEY_SECRET
WORKER_URL Secret Worker域名(用于临时文件URL) wrangler secret put WORKER_URL

安全注意事项:

  • ⚠️ 所有敏感信息均通过 wrangler secret 设置,不在代码中暴露
  • WORKER_URL 应设置为实际的 Worker 域名,如:https://your-worker.your-subdomain.workers.dev

前置要求

  • Node.js 18+
  • pnpm
  • Cloudflare 账号
  • 开通并创建 Cloudflare R2 存储桶
  • 火山引擎火山方舟 API 密钥

安装与配置

  1. 克隆仓库

    git clone https://github.com/nick3/ImgEditWorker.git
    cd ImgEditWorker
  2. 安装依赖

    pnpm install
  3. 配置环境

    # 设置管理认证密钥(用于清理接口)
    wrangler secret put AUTH_KEY_SECRET
    
    # 设置 Worker URL(用于生成临时文件访问链接)
    wrangler secret put WORKER_URL
    
    # 创建 R2 存储桶
    wrangler r2 bucket create img-temp-storage
  4. 配置验证

    确保已设置必需的环境变量:

    # 验证 secrets 设置
    wrangler secret list

本地开发

# 启动开发服务器
pnpm dev

# 运行测试
pnpm test

# 测试监视模式
pnpm test --watch

部署

项目支持两种部署方式:命令行部署和 Web 界面部署。

方式一:命令行部署(推荐给开发者)

# 部署到 Cloudflare
pnpm deploy

方式二:Cloudflare Web 界面部署(适合所有用户)

这种方式无需本地环境配置,适合没有技术背景的用户。

步骤 1:Fork 项目到您的 GitHub
  1. 访问项目页面

  2. Fork 仓库

    • 点击页面右上角的 "Fork" 按钮
    • 选择您的 GitHub 账户作为目标
    • 等待 Fork 完成
步骤 2:在 Cloudflare 中创建 Worker
  1. 登录 Cloudflare Dashboard

  2. 创建新 Worker

    • 在左侧菜单中选择 "Workers"下的"Workers & Pages"
    • 点击 "Create application" 按钮
    • 选择 "Workers" 标签页
    • 点击 "Import a repository"
  3. 连接 GitHub 仓库

    • 选择 "GitHub" 作为 Git 提供商
    • 如果是首次连接,需要授权 Cloudflare 访问您的 GitHub
    • 在仓库列表中找到并选择您刚才 Fork 的 ImgEditWorker 仓库
    • 点击 "Begin setup"
步骤 3:配置部署设置
  1. 基本设置

    • Project name: 输入项目名称(如:my-imgedit-worker
    • Production branch: 选择 mainmaster
    • Framework preset: 选择 "None"
    • Build command: 留空
    • Build output directory: 留空
  2. 环境变量配置

    • 点击 "Environment variables (advanced)" 展开高级设置
    • 添加以下环境变量:
    变量名 描述
    NODE_VERSION 18 指定 Node.js 版本

    点击 "Save and Deploy"

步骤 4:配置 R2 存储桶
  1. 创建 R2 存储桶

    • 在 Cloudflare Dashboard 中选择 "R2 Object Storage"
    • 点击 "Create bucket"
    • 存储桶名称输入:img-temp-storage
    • 选择合适的位置(建议选择离用户最近的区域)
    • 点击 "Create bucket"
  2. 绑定存储桶到 Worker

    • 回到 "Workers & Pages" 页面
    • 找到您刚创建的项目,点击进入
    • 选择 "Settings" 标签页
    • 在左侧菜单选择 "Functions"
    • 滚动到 "R2 bucket bindings" 部分
    • 点击 "Add binding"
      • Variable name: img_temp_storage
      • R2 bucket: 选择 img-temp-storage
    • 点击 "Save"
步骤 5:配置环境密钥
  1. 设置认证密钥

    • 在项目设置页面,选择 "Environment variables"
    • 点击 "Add variable"
    • 添加以下变量:
    变量名 类型 描述
    AUTH_KEY_SECRET Secret your-auth-key-here 管理接口认证密钥,请设置为强密码
    WORKER_URL Secret https://your-worker-domain.pages.dev 您的 Worker 域名

    ⚠️ 重要提示:

    • AUTH_KEY_SECRET 请设置为一个强密码,用于保护管理接口
    • WORKER_URL 需要等部署完成后获取实际的 Worker 域名再设置
  2. 保存并重新部署

    • 点击 "Save" 保存环境变量
    • 系统会自动触发重新部署
步骤 6:获取 Worker 域名
  1. 查看部署状态

    • 在项目概览页面查看部署状态
    • 等待状态变为 "Success"
  2. 获取域名

    • 部署成功后,您会看到生成的域名(如:https://my-imgedit-worker.pages.dev
    • 复制这个域名
  3. 更新 WORKER_URL

    • 回到 "Environment variables" 设置页面
    • 找到 WORKER_URL 变量,点击 "Edit"
    • 将值更新为实际的 Worker 域名
    • 点击 "Save"
步骤 7:测试部署
  1. 健康检查

    curl https://your-worker-domain.pages.dev/health

    预期响应:

    {
      "status": "ok",
      "timestamp": "2025-09-11T01:10:43.000Z"
    }
  2. API 测试

    # 使用您设置的 AUTH_KEY_SECRET 和火山引擎 API Key
    curl -X POST https://your-worker-domain.pages.dev/v1/images/edits \
      -H "Authorization: Bearer YOUR_AUTH_KEY_SECRET:YOUR_VOLC_API_KEY" \
      -F "prompt=编辑图片描述" \
      -F "image=@your-image.png"
🎉 部署完成!

现在您的 ImgEditWorker 已经成功部署到 Cloudflare。每当您在 GitHub 上更新代码时,Cloudflare 会自动重新部署您的应用。

💡 后续维护
  • 代码更新: 直接在 GitHub 上编辑代码或接受 Pull Request,Cloudflare 会自动部署
  • 查看日志: 在 Cloudflare Dashboard 的项目页面中查看实时日志
  • 监控使用: 在 "Analytics" 标签页中查看请求统计和性能指标
  • 域名绑定: 如需绑定自定义域名,在 "Custom domains" 中添加
🔧 故障排除

常见问题:

  1. 部署失败

    • 检查 GitHub 仓库是否正确 Fork
    • 确认构建设置是否正确(Framework preset 选择 "None")
  2. 环境变量未生效

    • 确认变量类型设置正确(敏感信息选择 "Secret")
    • 修改环境变量后需要重新部署才能生效
  3. R2 存储桶连接失败

    • 检查存储桶绑定的变量名是否为 img_temp_storage
    • 确认存储桶名称为 img-temp-storage
  4. API 调用失败

    • 检查 WORKER_URL 是否设置为正确的 Worker 域名
    • 确认 AUTH_KEY_SECRET 设置正确

📖 API 文档

图片编辑接口

端点: POST /v1/images/edits

兼容 OpenAI 图片编辑接口格式,支持 FormData 上传。

请求格式

POST /v1/images/edits
Content-Type: multipart/form-data
Authorization: Bearer AUTH_KEY_SECRET:VOLC_API_KEY

prompt: "编辑描述"
model: "model-name"
n: 1
response_format: "b64_json"
image: [图片文件]

认证格式说明:

  • Authorization 头部使用组合格式:Bearer AUTH_KEY_SECRET:VOLC_API_KEY
  • AUTH_KEY_SECRET:系统认证密钥(防止无效请求浪费存储)
  • VOLC_API_KEY:火山引擎 API 密钥(用于调用生成服务)
  • 两部分用冒号 : 分隔

支持的参数

参数 类型 必需 描述
prompt string 图片编辑的描述文本
image file 要编辑的图片文件
model string 使用的模型名称
n integer 生成图片数量(默认: 1)
response_format string 响应格式:urlb64_json(默认: b64_json

响应格式

{
  "created": 1234567890,
  "data": [
    {
      "url": "https://generated-image-url.com/image.png",
      "b64_json": "base64-encoded-image-data..."
    }
  ],
  "usage": {
    "total_tokens": 100,
    "input_tokens": 50,
    "output_tokens": 50
  }
}

临时文件访问

端点: GET /temp/{file-key}

访问上传到 R2 的临时文件。

GET /temp/temp_1234567890_abc123.png

健康检查

端点: GET /health

{
  "status": "ok",
  "timestamp": "2025-09-11T01:10:43.000Z"
}

管理接口

端点: POST /cron/cleanup

手动触发临时文件清理(需要管理权限)。

POST /cron/cleanup
X-Custom-Auth-Key: YOUR_AUTH_KEY_SECRET

🔧 技术细节

图片处理流程

  1. 接收请求: 解析 Authorization 头部的组合 API Key
  2. 认证验证: 先验证 AUTH_KEY_SECRET 是否正确
  3. FormData解析: 认证通过后解析图片和参数
  4. 文件验证: 检查文件类型(JPEG/PNG)和大小(最大 10MB)
  5. R2 上传: 上传到临时存储并生成访问 URL
  6. API 转换: 将 OpenAI 格式转换为火山引擎 API 格式
  7. 调用 API: 使用火山引擎 API Key 调用接口
  8. 响应转换: 将火山引擎响应转换回 OpenAI 格式

优势: 先验证认证密钥可以防止无效请求浪费 R2 存储空间

文件命名策略

临时文件使用以下命名规则:

  • 格式:temp_{timestamp}_{random}{extension}
  • 扩展名处理:
    • 有原始文件名:保留原始扩展名
    • 文件名为 "blob":通过 MIME 类型推断扩展名
    • 支持的格式:jpg, png, gif, webp, bmp, tiff, svg

自动清理机制

  • 执行时间: 每天凌晨 2:00(Cron: 0 2 * * *
  • 清理规则: 删除超过 24 小时的临时文件
  • 手动触发: 通过 /cron/cleanup 接口

🧪 测试

项目包含完整的测试套件,使用 Vitest 和 Cloudflare Workers 测试池。

测试覆盖

  • 认证测试: 组合 API Key 格式验证和双重认证流程
  • 文件上传: FormData 解析和 R2 存储
  • API 转换: OpenAI ↔ 火山引擎格式转换
  • 错误处理: 各种异常场景和安全验证
  • MIME 推断: blob 文件名的扩展名推断
  • 清理功能: 临时文件自动清理
  • 资源保护: 无效认证不消耗 R2 存储

运行测试

# 运行所有测试
pnpm test

# 详细输出
pnpm test --reporter=verbose

# 特定测试
pnpm test -t "图片编辑"

# 覆盖率报告
pnpm test --coverage

🔒 安全考虑

认证机制

  • 客户端 API: 使用组合格式 Authorization: Bearer AUTH_KEY:VOLC_API_KEY
  • 管理接口: 使用 X-Custom-Auth-Key 头部认证
  • 双重验证: 先验证系统密钥,通过后再上传文件到 R2,最后调用火山引擎 API
  • 资源保护: 无效认证请求不会消耗 R2 存储资源

文件安全

  • 类型限制: 仅允许特定图片格式(JPEG/PNG)
  • 大小限制: 文件最大 10MB
  • 临时存储: 文件自动过期,避免长期占用
  • 访问控制: 临时 URL 仅在有效期内可用

📊 性能与限制

Cloudflare Workers 限制

  • CPU 时间: 最大 10ms(免费版)/ 50ms(付费版)
  • 内存: 最大 128MB
  • 请求大小: 最大 100MB
  • 响应大小: 最大 100MB

优化策略

  • 异步处理: 全面使用 async/await
  • 流式上传: 使用 stream() 处理大文件
  • 错误处理: 快速失败,避免资源浪费
  • 缓存策略: 临时文件设置合适的缓存头

🛠️ 开发指南

项目结构

ImgEditWorker/
├── src/
│   └── index.js          # 主应用逻辑
├── test/
│   └── index.spec.js     # 测试套件
├── package.json          # 依赖配置
├── wrangler.jsonc        # Cloudflare 配置
├── vitest.config.js      # 测试配置
└── README.md            # 项目文档

核心类:ImageEditProxy

主要方法:

  • handleImageEdit(): 处理图片编辑请求
  • parseFormDataImages(): 解析 FormData 中的图片
  • uploadImageToR2(): 上传图片到 R2 存储
  • buildVolcEngineRequest(): 构建火山引擎 API 请求
  • callVolcEngineAPI(): 调用火山引擎 API
  • transformToOpenAIResponse(): 转换响应格式
  • cleanupExpiredFiles(): 清理过期文件

添加新功能

  1. 扩展 API: 在 ImageEditProxy 类中添加新方法
  2. 路由处理: 在主 fetch 函数中添加新路由
  3. 编写测试: 在 test/index.spec.js 中添加测试用例
  4. 更新文档: 同步更新 README.md

🐛 常见问题

Q: 如何设置 API Key?

A: 使用组合格式:AUTH_KEY_SECRET:VOLC_API_KEY,其中 AUTH_KEY_SECRET 是系统认证密钥,VOLC_API_KEY 是火山引擎 API 密钥。

Q: 为什么要使用组合 API Key?

A: 双重验证机制可以防止无效的火山引擎 API Key 浪费 R2 存储空间,先验证系统密钥再处理文件上传。

Q: 如何获取火山引擎 API Key?

A: 访问火山引擎开放平台,注册账号并在控制台创建 API Key。

Q: 为什么上传的图片没有扩展名?

A: 某些客户端会将文件名设为 "blob",系统会自动通过 MIME 类型推断正确的扩展名。

Q: 临时文件什么时候被删除?

A: 系统每天凌晨 2:00 自动清理超过 24 小时的临时文件,也可以手动调用清理接口。

Q: 支持哪些图片格式?

A: 当前支持 JPEG 和 PNG 格式,文件大小限制为 10MB。

Q: 如何调试 Worker?

A: 使用 wrangler dev 启动本地开发服务器,使用 console.log 输出调试信息。

📝 许可证

本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 创建 Pull Request

📞 支持

如果您遇到问题或有疑问,请:

  1. 查看 常见问题 部分
  2. 搜索现有的 Issues
  3. 创建新的 Issue 描述您的问题

注意: 本项目用于学习和演示目的。在生产环境中使用前,请确保充分测试并review安全配置。

About

一个基于 Cloudflare Workers 的高性能代理服务,提供 OpenAI 图片编辑接口到火山引擎的兼容性转换,支持 FormData 图片上传到 R2 临时存储并自动转换 API 格式。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors