# cf-image-gen **Repository Path**: hais/cf-image-gen ## Basic Information - **Project Name**: cf-image-gen - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-20 - **Last Updated**: 2026-09-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # cf-image-gen · 派达智枢 中文 GPT Image 2 生图与图片编辑工具。输入提示词生成图片;上传参考图后同一个表单切换成编辑模式。作品按任务铺在「作品台」上,可复用参数、再次编辑或下载。 TypeScript + React + Vite。上游走 OpenAI 兼容的**异步图片任务**规范(提交拿任务号 → 轮询进度),因此不受 Cloudflare 524 之类的 CDN 响应超时影响。 **两种用法**:本地运行,或部署到 Cloudflare Workers。两者的 `/api` 逻辑是同一份代码(`shared/`),所以本地跑通就等于线上跑通。 --- ## 目录 - [三分钟决定用哪种方式](#三分钟决定用哪种方式) - [一、本地运行](#一本地运行) - [二、部署到 Cloudflare Workers](#二部署到-cloudflare-workers) - [部署后验证](#部署后验证) - [日常更新](#日常更新) - [⚠️ 中国大陆访问不了?](#️-中国大陆访问不了) - [配置:一个文件搞定](#配置一个文件搞定) - [请求是怎么走的](#请求是怎么走的) - [项目结构](#项目结构) - [常见问题](#常见问题) - [安全说明](#安全说明) --- ## 三分钟决定用哪种方式 | | 本地运行 | 部署到 Workers | | --- | --- | --- | | 需要 Cloudflare 账号 | 否 | 是 | | 访问范围 | 只有你自己这台机器 | 任何设备,公网可访问 | | 上游 Key 存放 | `.env`(本地文件) | Worker secret | | 启动命令 | `npm run dev` | `npm run deploy` | | 适合 | 自己用、改代码 | 分享给别人用 | **两条路的配置项名字完全一样**,所以本地调好的参数可以直接搬到线上。 --- ## 一、本地运行 ### 前置要求 - **Node.js 20 或更高**(`node -v` 确认) - 一个 OpenAI 兼容的**异步图片任务**上游网关地址 + token ### 步骤 ```bash # 1. 装依赖 npm install # 2. 建配置文件(.env 不在版本库里,必须自己复制) cp .env.example .env # Windows: copy .env.example .env # 3. 填 .env —— 至少这三项 # IMAGE_API_BASE_URL=https://你的网关地址 ← 不带 /v1,不带尾斜杠 # IMAGE_API_TOKEN=你的token # IMAGE_MODELS=[{"GPT Image 2":{"model":"gpt-image-2","message":"通用生图"}}] # 4. 启动 npm run dev ``` 浏览器打开 **http://localhost:5173**,选模型、填提示词即可生成。 > `.env` 是**本地和线上共用的唯一配置文件** —— 同一个值写一次,两边自动一致。详见[配置:一个文件搞定](#配置一个文件搞定)。 > **端口被占用?** Vite 默认用 5173,被占了会自动顺延到 5174 并打印实际地址 —— 以终端输出的为准。若想固定端口:`npx vite --port 5199`。 ### 全部命令 | 命令 | 作用 | | --- | --- | | `npm run dev` | 启动开发服务器(含 `/api` 代理),http://localhost:5173 | | `npm run build` | 类型检查 + 构建到 `dist/` | | `npm run typecheck` | 只做类型检查(含 Worker,见下) | | `npm run preview` | 预览构建产物 | | `npm run deploy:dry` | 类型检查 + 构建 + 校验部署(**不上传**) | | `npm run deploy` | 类型检查 + 构建 + **正式部署** | > `npm run preview` **只有静态文件,代理不在里面**,所以连不上上游,只能看界面。要完整功能请用 `npm run dev`。 ### 本地是怎么工作的 `npm run dev` 会把 `shared/proxy.ts` 注册成一个 Vite 中间件,它接管所有 `/api/*` 请求,在**同源**下转发到上游并注入 `Bearer` token。 这样做的唯一原因是:**Key 必须留在服务端**。Key 一旦进前端打包产物,任何人打开控制台都能拿走盗刷额度。同源还顺带免掉了 CORS 配置。 ### 依赖要装两处 根目录和 `worker/` 是**两个独立的包**,各有自己的 `package-lock.json`,要分别装: ```bash npm install # 根:Vite / React / TypeScript cd worker && npm install # worker:Wrangler ``` `worker/node_modules` 是**部署必需的** —— 部署脚本会检查 `worker/node_modules/wrangler/bin/wrangler.js` 是否存在,缺了会直接报「worker 依赖未安装」。 > 首次在 worker 里装依赖时,npm 会下载 Wrangler 和 workerd 的平台二进制(约 100 MB),耗时比根目录长一些。之后有缓存就很快。 --- ## 二、部署到 Cloudflare Workers Worker 同时提供静态页面和 `/api`,**页面与接口同源**,不需要额外的服务器或对象存储。 ### 前置要求 - Node.js 20+ - 一个 Cloudflare 账号(免费版够用) - 一个 OpenAI 兼容的异步图片上游网关地址 + token ### 步骤 1 · 安装依赖 ```bash npm install cd worker && npm install && cd .. ``` ### 步骤 2 · 登录 Cloudflare ```bash cd worker npx wrangler login # 浏览器里点授权 ``` 验证登录成功: ```bash npx wrangler whoami # 能列出账号和权限即可 ``` ### 步骤 3 · 填写配置(一个文件) 线上配置**全部来自项目根目录的 `.env`** —— 和本地开发用的是同一个文件,不需要再单独编辑 `wrangler.jsonc`: ```bash cp .env.example .env # 如果本地运行时已经建过,跳过这步 ``` 至少填这三项: ```dotenv IMAGE_API_BASE_URL=https://你的网关地址 # 不带 /v1,不带尾斜杠 IMAGE_API_TOKEN=你的上游token IMAGE_MODELS=[{"GPT Image 2":{"model":"gpt-image-2","message":"通用生图"}}] ``` `npm run deploy` 会读取它,并按**键名后缀**自动分流: | 键名 | 上传方式 | 说明 | | --- | --- | --- | | 以 `_TOKEN` / `_KEY` / `_SECRET` 结尾 | `--secrets-file` | 加密上传,不会出现在部署输出或面板里 | | 其余 | `--var` | 普通变量,面板可见,便于排查 | 所以 `IMAGE_API_TOKEN` / `ACCESS_TOKEN` 天然走加密通道,其余走普通变量 —— **你不需要手动判断哪个该加密**。 > **密钥留空 = 保留 Cloudflare 上的现有值。** 部署脚本会跳过空值,所以不会把已经在线的 token 覆盖成空字符串。 > **没设 `IMAGE_API_TOKEN` 时,所有生图请求返回 HTTP 503。** ⚠️ **不要绕过 `npm run deploy` 直接跑 `wrangler deploy`。** wrangler 的行为是"先删除所有变量,再写入配置里的那些",而配置现在来自命令行参数 —— 绕过脚本直接部署会**把所有变量清空**,得到一个全站 503 的 Worker。 ### 步骤 4 · 干跑校验(建议) ```bash npm run deploy:dry ``` 它会依次做:**读取 `.env` → 类型检查 → 构建前端 → Wrangler 校验打包结果(不上传)**。 看到这样的输出就说明没问题: ``` > 读取 .env 普通变量 7 个 加密密钥 0 个 留空跳过 2 个(保留 Cloudflare 上的现有值):IMAGE_API_TOKEN, ACCESS_TOKEN > 类型检查 > 构建前端 > 校验 Worker 部署(不上传) env.ASSETS Assets env.IMAGE_API_BASE_URL ("(hidden)") Environment Variable env.IMAGE_MODELS ("(hidden)") Environment Variable env.IMAGE_DEFAULT_MODEL ("(hidden)") Environment Variable 校验通过。去掉 --dry-run 即可正式部署。 ``` ⚠️ **重点看开头的「读取 .env」三行**: - 「普通变量 0 个」→ `.env` 没读到,检查文件是否存在 - 「加密密钥」里应该有 `IMAGE_API_TOKEN`(除非你打算沿用 Cloudflare 上的旧值) - 如果 `.env` 里没写 `IMAGE_API_BASE_URL`,脚本会直接警告 > 变量值显示为 `(hidden)` 是正常的 —— 通过命令行传入的值 wrangler 不会回显。 ### 步骤 5 · 正式部署 ```bash npm run deploy ``` 成功输出: ``` Uploaded cf-image-gen (3.62 sec) Deployed cf-image-gen triggers (1.09 sec) https://cf-image-gen.<你的子域>.workers.dev Current Version ID: 66dd7617-3b73-4bda-ace1-e2311e0ee744 ``` `npm run deploy` **会自动先构建前端再部署**,所以改了 `src/` 不用手动 build。它做三件事: 1. 读取项目根目录的 `.env`,按需分流成普通变量和加密密钥 2. `tsc -b --force` —— 类型检查,**不通过就直接中断**,不会部署半成品 3. `vite build` —— 构建前端到 `dist/` 4. `wrangler deploy` —— 把 Worker 代码 + `dist/` + 变量 + 密钥一起上传 > **部署不需要挂代理。** `wrangler` 走的是 `api.cloudflare.com`,国内可直连。 ### 步骤 6 · 设置访问口令(强烈建议) Worker 在公网上,**谁知道域名谁就能用**,而它会带上**你的**上游 token —— 不加口令等于把额度公开。 在 `.env` 里填上口令,然后重新部署: ```dotenv ACCESS_TOKEN=你的口令 ``` ```bash npm run deploy ``` 然后访问一次: ``` https://cf-image-gen.<你的子域>.workers.dev/?token=你的口令 ``` 口令会存进 `localStorage` 并**立即从地址栏抹掉**,之后正常使用即可。 --- ## 部署后验证 部署完**别只看首页能不能打开** —— 首页是静态资源,即使 `/api` 完全坏掉它也是 200。要验证 `/api`: ```bash # 1. 配置是否真的生效(最关键的一条) curl -s https://cf-image-gen.<你的子域>.workers.dev/api/config # 期望输出里带 "configured":true # {"models":[{"label":"GPT Image 2",...}],"defaultModel":"gpt-image-2",...,"configured":true} ``` `"configured":false` 说明 `IMAGE_API_BASE_URL` 没生效 —— 回去看步骤 3。 ```bash # 2. 各路径状态码 curl -o /dev/null -w "%{http_code}\n" https://cf-image-gen.<你的子域>.workers.dev/ curl -o /dev/null -w "%{http_code}\n" https://cf-image-gen.<你的子域>.workers.dev/api/config # 3. 看当前部署版本 cd worker && npx wrangler deployments list # 4. 看实时日志(排错用) cd worker && npx wrangler tail ``` **排错速查:** | 现象 | 原因 | | --- | --- | | 整站返回 `500` + `error code: 1101` | Worker 代码运行时抛异常。用 `npx wrangler tail` 抓真实错误;重新 `npm run deploy` 通常能解决"版本损坏"类问题 | | 页面能开,但生成时报「服务端未配置 IMAGE_API_BASE_URL」 | `vars` 里还是占位符地址 | | 生成时报「服务端未配置 IMAGE_API_TOKEN」 | secret 没设,或设在了错误的目录 | | 返回 `401 访问口令不正确` | 设了 `ACCESS_TOKEN` 但浏览器没带,用 `?token=口令` 访问一次 | | 浏览器打不开、连接超时 | **看下一节** | > `npx wrangler tail` 连的域名和 `api.cloudflare.com` 不是同一个,**国内需要挂代理**才能用(部署本身不用)。 --- ## 日常更新 改完代码,一条命令: ```bash npm run deploy ``` 前端和 Worker 会一起更新。只改 `worker/wrangler.jsonc` 的 `vars` 也一样走这条命令。 **回滚**:Cloudflare 保留历史版本。 ```bash cd worker npx wrangler deployments list # 找到要回滚的版本 ID npx wrangler versions deploy # 交互式确认 ``` --- ## ⚠️ 中国大陆访问不了? **`*.workers.dev` 在中国大陆被墙。** 这不是配置问题,部署再多次也没用。 典型症状:浏览器一直转圈最后超时,`curl` 报 `Failed to connect ... port 443: Timed out`。用 `nslookup` 或 `Resolve-DnsName` 查这个域名,会拿到一堆**明显不对的 IP**(Twitter、Facebook 的地址段,甚至 IPv6 里带 `face:b00c`)—— 这是典型的 DNS 污染,不同解析器会给出不同的假 IP。 **注意区分**:被封的只是 `workers.dev` 这个域名,**Cloudflare 边缘本身在国内是可直连的**(`cloudflare.com`、`dash.cloudflare.com` 都能正常访问)。所以有三个解法: **方案 A · 挂代理访问**(最快) 你已有的代理直接访问即可。缺点是自己方便,分享给别人不方便。 **方案 B · 绑定自定义域名**(推荐,一劳永逸) 前提是你有一个托管在**同一个 Cloudflare 账号**下的域名。在 `worker/wrangler.jsonc` 加: ```jsonc "routes": [ { "pattern": "pdai.你的域名.com", "custom_domain": true } ] ``` 然后 `npm run deploy`。Cloudflare 会自动建好 DNS 记录和证书,之后用自定义域名访问即可 —— **不需要代理**。 **方案 C · 换托管平台** Vercel、Netlify 等在国内的可达性同样不稳定,通常不比方案 B 好。 --- ## 配置:一个文件搞定 **本地和线上共用项目根目录的 `.env`。** 同一个值写一次,两边自动一致。 ``` 你只编辑这一个文件 │ .env ← 从 .env.example 复制 ┌────────┴────────┐ ▼ ▼ npm run dev npm run deploy │ │ Vite 直接读取 deploy.mjs 读取后按 (零配置) 键名后缀自动分流 ┌───────────┴───────────┐ ▼ ▼ _TOKEN/_KEY/_SECRET 其余键 │ │ --secrets-file --var (加密上传) (明文普通变量) ``` | 键名 | 上传方式 | 面板可见 | 典型用途 | | --- | --- | --- | --- | | 以 `_TOKEN` / `_KEY` / `_SECRET` 结尾 | `--secrets-file` | 否(加密) | 上游 token、访问口令 | | 其余 | `--var` | 是 | 网关地址、模型列表、限流参数 | `worker/wrangler.jsonc` **故意不再声明 `vars`** —— 保留一份副本会形成第二个真相来源,而它会静默覆盖 `.env`,正是这套设计要避免的漂移。 ### 变量表 | 变量 | 作用 | 默认值 | 上传方式 | | --- | --- | --- | --- | | `IMAGE_API_BASE_URL` | 上游网关根地址(不带 `/v1`、不带尾斜杠) | 空(未配置时返回 503) | 普通变量 | | `IMAGE_API_TOKEN` | 上游 Bearer token | 空 | **加密** | | `IMAGE_MODELS` | 可用模型,JSON 数组 | 空(下拉框显示「未配置模型」) | 普通变量 | | `IMAGE_DEFAULT_MODEL` | 默认选中的模型,必须在上面的列表里 | 列表第一项 | 普通变量 | | `IMAGE_SIZES` | 可选尺寸,JSON 数组 | 自动 / 1024×1024 / 1536×1024 / 1024×1536 | 普通变量 | | `RATE_LIMIT_WINDOW_SECONDS` | 限流窗口 | `60` | 普通变量 | | `RATE_LIMIT_MAX_REQUESTS` | 窗口内最大请求数 | `180` | 普通变量 | | `REQUEST_TIMEOUT_SECONDS` | 上游超时 | `120` | 普通变量 | | `MAX_REQUEST_BYTES` | 请求体上限 | `33554432`(32 MB) | 普通变量 | | `ACCESS_TOKEN` | 部署版 `/api` 访问口令 | 不设即完全开放 | **加密** | | `PROXY_LOOPBACK_ONLY` | 本地代理只接受本机请求 | 关闭 | 仅本地(不上传) | > 想新增一个加密变量,把键名以 `_TOKEN` / `_KEY` / `_SECRET` 结尾即可,不需要改任何代码。 > 反过来,如果某个普通变量名恰好以这些后缀结尾,它会被当成密钥上传 —— 这是唯一需要注意的命名约定。 ### 三条必须记住的规则 1. **改完线上配置要重新部署** —— `.env` 只在 `npm run deploy` 时上传,本地改完线上不会自动生效。 2. **密钥留空 = 保留现有值** —— 部署脚本会跳过空密钥,不会把线上正在用的 token 覆盖成空字符串。 3. **不要绕过 `npm run deploy`** —— 直接跑 `wrangler deploy` 会清空所有变量(原因见下)。 ### 为什么不能直接跑 `wrangler deploy` `wrangler deploy` 的默认行为是**先删除该 Worker 上的所有变量,再写入它这次知道的那些**(`--keep-vars` 默认 `false`)。 配置搬进 `.env` 后,变量是通过命令行参数传进去的。所以绕过脚本直接部署时,wrangler 看到"这次没有任何变量",就会**把线上已有的全部删掉** —— 页面能打开(静态资源照常上传),但每次生成都返回 503。 这条限制只影响 `deploy`。以下命令不受影响,可以正常单独使用: ```bash cd worker npx wrangler tail # 看实时日志 npx wrangler deployments list # 看部署历史 npx wrangler versions deploy # 回滚到指定版本 ``` ### `IMAGE_MODELS` 怎么写 它是一段 **JSON 数组**。下面几种写法等价: ```jsonc // 1) 以显示名为键的映射(最省事) [{"GPT Image 2":{"model":"gpt-image-2","message":"高质量通用生图,支持文生图与参考图编辑"}}] // 2) 带 label 的数组 [{"label":"GPT Image 2","model":"gpt-image-2","description":"高质量通用生图"}] // 3) 多个模型 [{"GPT Image 2":{"model":"gpt-image-2","message":"通用"}}, {"GPT Image 1":{"model":"gpt-image-1","message":"上一代"}}] // 4) 只写 id ["gpt-image-2","gpt-image-1"] // 5) 逗号分隔(不是合法 JSON 时按这个解析) gpt-image-2,gpt-image-1 ``` 字段别名: | 用途 | 可用键名 | | --- | --- | | 显示名 | `label` / `title` / `display` / `display_name`,或映射写法的键 | | 模型 id | `model` / `id` / `value` | | 描述 | `description` / `message` / `desc` / `note` | 下拉框显示**显示名**,请求里发送 **model**。`IMAGE_DEFAULT_MODEL` 必须是列表里出现过的 id,否则被忽略并回退到第一项。 --- ## 请求是怎么走的 ``` 浏览器 ──▶ /api/images/generations/async (文生图,JSON) ──▶ /api/images/edits/async (参考图编辑,multipart) ──▶ /api/images/tasks/{task_id} (轮询进度) │ │ 同源请求,不带任何密钥 ▼ Worker(线上) / Vite 中间件(本地) │ │ 注入 Authorization: Bearer ▼ ${IMAGE_API_BASE_URL}/v1/images/generations/async ${IMAGE_API_BASE_URL}/v1/images/edits/async ${IMAGE_API_BASE_URL}/v1/images/tasks/{task_id} ``` **上游就是你配的那一个地址,直连**,没有任何第三方中转。 异步任务的生命周期: ``` 提交 ──▶ 202 Accepted { task_id: "imgtask_...", status: "processing", poll_url: "..." } │ ▼ 轮询 GET /api/images/tasks/{task_id} │ ┌───────────┼────────────┐ ▼ ▼ ▼ processing completed failed (继续轮询) result.data[] error.message [].url ``` - 默认**每 3 秒轮询一次,最多 600 次**(约 30 分钟,与上游任务上限一致) - 上游返回 `Retry-After` 时按它给的时间轮询 - 轮询遇到限流或瞬时网络错误会自动重试,不会中断其实还在跑的任务 - 完成时取 `result.data[].url`(上游已把图片落到对象存储,返回直链) --- ## 项目结构 ``` shared/ 两端共用的代理层 core.ts 配置解析、限流、上游调用工具 api.ts /api 路由:config、images/*、download-image proxy.ts 本地适配层:Node req/res ↔ Request/Response(仅 Vite 开发服务器) deploy.mjs 构建前端 + 部署 Worker(一条命令) worker/ Cloudflare Worker src/index.ts 入口:静态资源 + /api,可选 ACCESS_TOKEN wrangler.jsonc 资源绑定与 run_worker_first(**故意不含 vars**,配置来自 .env) tsconfig.json 用 @cloudflare/workers-types 检查,**故意不含 DOM lib** src/ 前端(React) lib/ 端点常量、类型、/api 客户端、存储、图片处理 hooks/ useWorkspace(表单/任务队列/轮询引擎)、useConfig、useLightbox… components/ 品牌头、生图表单、任务卡、大图预览、推广弹窗 App.tsx 组装各模块并处理持久化 styles.css .env 唯一配置源:本地 + 线上(含密钥,不进版本库) .env.example 配置模板(进版本库) public/ Vite 约定目录,内容原样复制到 dist/ 根 index.html Vite 入口 vite.config.ts 注册 React 插件与本地 /api 中间件 tsconfig.json 解决方案文件,引用下面三个 project tsconfig.app.json src/ —— DOM + JSX tsconfig.server.json shared/ + vite.config.ts —— node 类型 ``` ### 关于 tsconfig 三个 project 的编译选项**故意不同**,不要合并: - **`tsconfig.app.json`** 有 DOM 和 JSX,但**没有 node 类型** —— 防止前端误用 `process`、`fs` - **`tsconfig.server.json`** 有 node 类型,覆盖 `shared/` 和 `vite.config.ts` - **`worker/tsconfig.json`** 用 `@cloudflare/workers-types` 且**故意不含 DOM** —— 这样 Worker 代码里误用 `document`、`window`、`localStorage` 会直接**编译报错**,而不是等上线后 500 `npm run deploy` 里的 `tsc -b --force` 会**同时检查这三个**,包括 Worker。所以类型错误拦得住,不会部署上去。 > `worker/tsconfig.json` 的 `include` 是**显式列出** `../shared/core.ts` 和 `../shared/api.ts` 的,不能用 `../shared/**/*.ts` 通配 —— 因为 `shared/` 里还有 Node-only 的 `proxy.ts`,通配会让 Worker 的类型检查因为 Node API 而失败。 --- ## 常见问题 ### 运行相关 **`npm run dev` 起来了但页面不对 / 是别的项目** 端口被占了。5173 上可能已经有另一个 Vite 项目在跑,请求会被它接走。看终端打印的实际端口,或指定一个:`npx vite --port 5199`。 **生成时提示「服务端未配置 IMAGE_API_BASE_URL」** 本地:`.env` 里没填(注意 `.env` 不在版本库里,要自己从 `.env.example` 复制)。 线上:`.env` 里填了但**没有重新部署** —— 跑一次 `npm run deploy`。 **提示「服务端未配置 IMAGE_API_TOKEN」** 在 `.env` 里填 `IMAGE_API_TOKEN=`,然后 `npm run deploy`。 **部署后线上配置全是空的 / 生成全部 503** 多半是绕过脚本直接跑了 `wrangler deploy`,变量被清空了。跑一次 `npm run deploy` 即可恢复(原因见[为什么不能直接跑 `wrangler deploy`](#为什么不能直接跑-wrangler-deploy))。 **下拉框显示「未配置模型」** `IMAGE_MODELS` 为空或 JSON 写错了。它是一个 **JSON 数组**;写错时会被当作逗号分隔的 id 列表处理。 **`npm run deploy:dry` 显示「普通变量 0 个」** `.env` 没读到 —— 检查文件是否存在于项目根目录(不是 `worker/` 下),以及有没有从 `.env.example` 复制。 **想把某个变量改成加密上传** 把键名改成以 `_TOKEN` / `_KEY` / `_SECRET` 结尾即可,不需要改代码。 ### 部署相关 **`npm run deploy` 报「worker 依赖未安装」** ```bash cd worker && npm install ``` **部署成功但打不开 / 连接超时** 先确认是不是[中国大陆的 `workers.dev` 封锁](#️-中国大陆访问不了)。 **整站 500 / `error code: 1101`** Worker 运行时抛异常。`cd worker && npx wrangler tail` 抓真实错误(国内需挂代理)。若本地 `npm run dev` 正常、线上不正常,多半是线上版本损坏,重新 `npm run deploy` 即可。 **上游返回 404** 异步图片任务在上游默认是关闭的,需要网关侧开启对象存储后才生效。另外 API Key 所属分组必须是 OpenAI 或 Grok。 **图片加载失败** 上游返回的是对象存储直链(可能是预签名 URL,有时效)。链接过期重新生成即可。 **`npx wrangler tail` 超时** 它连的域名和 `api.cloudflare.com` 不同,国内需要挂代理。**部署本身不需要代理。** --- ## 安全说明 - **上游 token 从不进入浏览器。** 页面只和同源的 `/api` 通信,token 由 Worker / 本地代理注入。`/api/config` 只返回模型与尺寸,**不含任何密钥**。 - **Key 只存在于 Worker secret 或本地 `.env`**,两者都不会被打包进前端。 - **默认不落盘。** `localStorage` 只存工作区状态(提示词、参数、模型选择、任务与图片 URL),不存密钥。 - **部署版无状态。** Worker 不写 KV、不写 D1、不绑 R2。限流窗口只在 isolate 内存里,冷启动即消失。 - **建议设 `ACCESS_TOKEN`**,否则你的域名就是一个公网可达、且带着你 token 的中继。 - **`?token=` 会从地址栏移除**,但仍可能留在浏览器历史里 —— 敏感场景请用无痕窗口。 - **本地代理默认不限制来源。** 若用 `--host` 暴露到局域网,请设 `PROXY_LOOPBACK_ONLY=1`。 --- ## 功能 - 中文 Prompt 生图,可选**模型**、数量(1–4 张)、风格(8 种预设)、尺寸 - 上传参考图后自动切换到图片编辑接口,多张参考图按顺序上传 - **作品台**:每个任务一张卡片,显示缩略图、状态、参数与进度;最多同时 3 个任务 - 失败任务一键重试;页面刷新后自动接管未完成的任务(用任务号继续轮询) - **大图预览**:方向键切换、Escape 关闭、底部操作条(复用参数 / 作为参考图 / 下载 / 删除) - 参数复用:把某张图的 Prompt、风格、尺寸、模型填回表单 - 加载进度条:模糊缩略图垫底,真实图片载入后跳到 100% - 优选推荐、每日推广弹窗 - 明暗主题,跟随系统并记住手动选择 - 明确的空状态、错误状态与各类失败提示