让开发者无需关注成本、网络环境、模型接入和运维管理,通过统一 API 即可稳定调用全球主流 AI 模型。更低成本、更简单接入、更稳定服务、更高管理效率。
链路依赖外部号商、代理商和多级分发,成本、延迟、限流和故障点都会被放大。
官方直连,网络代理、线路优化、请求调度和平台计费都由 Wowfish 自己打通,稳定性和成本更可控。
Wowfish 直接对接各大官方模型厂商,不接第三方中转商、共享账号商或二级代理,减少层层转发带来的加价、限流、封号和不稳定风险。
从官方模型接入、自建网络代理、线路优化、缓存优化到平台计费统一打通,不依赖外部号商、网络代理商或层层分发中转。
减少多层代理和中间商加价后,平台可以把链路成本压得极低,承诺只收取 20% 的毛利。
平台自搭网络代理并持续优化可用线路,按延迟、稳定性和可用性调度请求,减少临时代理链路带来的超时、断流和波动。
针对高频请求、重复上下文和可缓存场景做链路级优化,相比普通临时拼接的中转方案,更容易获得稳定的缓存命中率,进一步降低延迟和重复消耗。
一个 API Key 统一接入多家主流模型,支持平台余额、订阅套餐、用量记录和团队 API Key 拆分,方便个人、团队和企业管理成本。
Codex App 需要从 Codex 官网下载并安装。部分网络环境可能打不开官网或下载速度较慢,如果你卡在下载、登录或安装步骤,可以直接联系 技术支持 协助处理。
~/.codex 配置。点击“下载脚本”后,不要直接双击脚本文件。先找到脚本保存在哪个文件夹,再按自己的系统选择下面对应步骤。
install-wowfish-codex.ps1,通常会在“下载”文件夹。Shift 右键,选择“在终端中打开”或“在 PowerShell 中打开”。dir 并回车;如果列表里能看到脚本文件,说明位置正确。powershell -ExecutionPolicy Bypass -File .\install-wowfish-codex.ps1install-wowfish-codex.sh。ls 并回车;如果列表里能看到脚本文件,说明位置正确。chmod +x ./install-wowfish-codex.sh
./install-wowfish-codex.shdir(Windows)或 ls(macOS / Linux)确认能看到脚本文件,再运行命令。config.toml 和 auth.json。不想运行脚本时,在当前系统用户目录下创建 ~/.codex/config.toml 和 ~/.codex/auth.json,填入下面的配置和自己的 API Key。
保存后退出并重新打开 Codex App 或 IDE 插件。新建一个简单对话,如果没有 401、认证失败或模型不可见,说明 Wowfish 配置已生效。
先从 CC Switch 官方 Releases 页面下载并安装适合自己系统的版本。安装完成后打开 CC Switch,准备好在 Wowfish API 控制台创建的 API Key。
WOWfishwowfishhttps://wowfish.mehttps://api.wowfish.meAnthropic Messages(原生)gpt-5.5gpt-5.6-terragpt-5.6-solhttps://api.wowfish.me,不要追加 /v1,末尾也不要加斜杠。
如果使用 Claude Code CLI,可以从 Wowfish API 控制台直接填入 CC Switch,不需要手动复制每一项配置。
进入任意项目目录启动 Codex,然后把下面整段提示词粘贴进去。真实 key 不需要发到 Codex 对话里。
帮我安装 OpenClaw,`curl -fsSL https://openclaw.ai/install.sh | bash` 这是它的一键安装命令。安装完成后帮我配置 Wowfish 服务商。baseUrl 使用 `https://api.wowfish.me/v1`,apiKey 先使用占位符,不要向我索要真实 key。全部完成后告诉我配置文件在哪里、如何替换真实 key,以及如何重启 gateway。http://localhost:18789 验证。~/.openclaw/openclaw.jsonC:\Users\你的用户名\.openclaw\openclaw.jsonhttps://api.wowfish.me/v1http://localhost:18789想少一步替换 key 时使用。密钥只在浏览器本地生成脚本,不会上传。
点击“下载脚本”后,把文件保存为 install-wowfish-openclaw.sh。这个脚本适合在 macOS / Linux 终端运行。
http://localhost:18789 验证。chmod +x ./install-wowfish-openclaw.sh
./install-wowfish-openclaw.sh
openclaw gateway stop
openclaw gateway --port 18789install-wowfish-openclaw.sh 再执行。脚本会备份已有 ~/.openclaw/openclaw.json。openclaw gateway stop
openclaw gateway --port 18789浏览器打开 http://localhost:18789。如果能看到 OpenClaw 管理界面,且模型列表中存在 wowfish/gpt-5.5,说明配置已生效。
CC-Switch 用来管理多套 AI 编程工具配置。你可以把 Wowfish、OpenAI 官方账号和其他服务商拆成多个供应商配置,需要时一键切换。
ccswitch:// 链接。先打开 Codex 的安装与配置,填入 API Key 后点击“导入 CC-Switch”。浏览器会调起 CC-Switch,并带入 Wowfish 的 API 请求地址、模型和 API Key。
codexWowfishhttps://api.wowfish.me/v1gpt-5.5Wowfish,API 请求地址填写 https://api.wowfish.me/v1。gpt-5.5 或你要用的模型。不要把官方账号和 Wowfish 写进同一个供应商配置。官方账号供应商配置用来保留 OpenAI 登录态;Wowfish 配置用来走 wowfish的API Key 和wowfish的中转 API 请求地址。需要恢复官方登录时,打开 切换回官方账号,或在ccswitch里切换回官方供应商。
ccswitch:// 导入链接发到公开聊天或截图里。有些用户希望保留 OpenAI 官方账号登录态,同时让模型请求走 Wowfish API。这个场景的关键是:官方登录态放在 auth.json,Wowfish 模型请求配置放在 config.toml。
保留官方登录生成的 auth.json,只把 config.toml 改成 Wowfish provider。这样 Codex 仍保留官方登录态,而模型请求使用 Wowfish 的 API 请求地址。
model_provider = "wowfish"
model = "gpt-5.5"
[model_providers.wowfish]
name = "wowfish"
base_url = "https://api.wowfish.me/v1"
wire_api = "responses"
requires_openai_auth = trueauth.json 发给任何人。如果你经常在官方账号、Wowfish 和其他第三方供应商之间切换,建议按 CC-Switch 的官方教程处理官方登录保留逻辑:切换第三方供应商时保留 Codex 官方登录。
图片生成不是普通文本对话消耗。参考教程提醒:图片模型通常按生成或编辑请求计费,并且 Agent 可能在自检后再次调用接口。本站接入改成 Wowfish 后,请以 Wowfish 控制台显示的余额、账单和模型价格为准。
wowfish-image 是平台自带的画图技能。装好后在 Codex 里输入 /image 就能调用,支持文生图和图生图(改图)。
不想手动建文件,可以让 Codex 自己装。把下面这句话复制给 Codex,它会按本文内容自动配置好。真实密钥不要发到对话里,最后自己替换 ~/.codex/.env 里的占位符。
请帮我按照https://wowfish.me/docs/index.html#codex-image这个页面的“手动安装”一节,把 wowfish-image 技能的 4 个文件分别创建到对应位置:SKILL.md、openai-image.sh、openai-image.ps1,以及 ~/.codex/.env。api_key 先留占位,最后提醒我换成自己的密钥。技能由 4 个文件组成,分别放在下面这些位置。
~/.codex/
├── .env
└── skills/
└── wowfish-image/
├── SKILL.md
└── scripts/
├── openai-image.sh
└── openai-image.ps1~/.codex/.envSKILL.mdopenai-image.shcurl、base64、grep、sed。openai-image.ps1~/.codex 是当前用户主目录下的隐藏目录。macOS Finder 可按 Command + Shift + G 后输入 ~/.codex。%USERPROFILE%\.codex。如果不存在,就在用户目录下新建 .codex。可以先用命令创建目录:
# macOS / Linux
mkdir -p ~/.codex/skills/wowfish-image/scripts
chmod 700 ~/.codex ~/.codex/skills ~/.codex/skills/wowfish-image 2>/dev/null || true# Windows PowerShell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\skills\wowfish-image\scripts" | Out-Null按上面的目录结构新建这 4 个文件,再把下面对应内容复制进去保存。装完后,把 ~/.codex/.env 里的 api_key 改成你自己的密钥。如果这个文件里已有 http_proxy 等代理设置,保留即可。
~/.codex/.env —— 接口地址和密钥:
base_url=https://api.wowfish.me/v1
api_key=sk-替换成你的真实-API-Key~/.codex/skills/wowfish-image/SKILL.md把下面内容保存为 SKILL.md。
---
name: wowfish-image
description: 用 OpenAI 兼容接口(curl 命令行)生成或编辑图片。当用户想“生成图片/画一张图/文生图/做张配图/帮我画/create an image/generate image”,或“改图/图生图/编辑这张图/换背景/给图片加东西/edit image”时使用本技能。它读取 ~/.codex/.env 里的 base_url 与 api_key,用 curl 调接口;Base64 结果会解码保存到本地,URL 结果会下载到 --out。无需安装任何 Python/环境。只要用户提到生成图片、画图、改图、图像编辑,即使没说“用 OpenAI 接口”,也应优先考虑用本技能。
---
# OpenAI 图像生成 / 编辑(curl 方式)
通过 OpenAI 兼容的 `/images/generations`(文生图)和 `/images/edits`(图生图 / 编辑)接口生成图片。本站默认接口地址即(base_url)使用`https://api.wowfish.me/v1`。
如果接口返回非空 `b64_json`,脚本会解码并保存到本地;如果没有非空 `b64_json` 但有 `url`,脚本会下载到 `--out` 指定路径。不依赖 Python,无需装环境。
技能自带两个脚本,直接调用即可,不要重写:
- `scripts/openai-image.sh` —— macOS / Linux
- `scripts/openai-image.ps1` —— Windows
## 工作流程
### 第 1 步:确认配置存在
脚本会读取 `~/.codex/.env`(Windows:`%USERPROFILE%\.codex\.env`)里的两行:
```text
base_url=https://api.wowfish.me/v1
api_key=sk-你的密钥
```
先快速检查这两个键是否存在:
```bash
grep -E '^\s*(base_url|api_key)\s*=' ~/.codex/.env 2>/dev/null
```
如果缺少 `base_url` 或 `api_key`,引导用户在 `~/.codex/.env` 里补全。`api_key` 必须由用户自己提供,不要编造,也不要要求用户把真实密钥发到对话里。
### 第 2 步:判断任务类型并收集参数
- 文生图(`generate`):只有文字描述时使用。
- 图生图 / 编辑(`edit`):用户给出一张或多张已有图片,并要求修改时使用,把图片路径作为 `--image` 传入。
需要的参数:
- `--prompt`:必填,图像描述,尽量把用户意图写清楚、具体。
- `--model`:默认 `gpt-image-2`。用户指定别的模型就用别的。
- `--size`:默认 `1024x1024`,也可用 `1536x1024`、`1024x1536`、`auto`。
- `--n`:生成数量,默认 1。
- `--out`:图片保存路径,默认当前目录 `image-时间戳.png`。多张时自动加 `_1`、`_2` 后缀。
- `--mask`:可选,局部重绘时使用。
### 第 3 步:调用脚本
macOS / Linux:
```bash
# 文生图
bash ~/.codex/skills/wowfish-image/scripts/openai-image.sh generate \
--prompt "一只戴贝雷帽、坐在木桌上的小水獭,柔和光线" \
--size 1024x1024 --out ./otter.png
# 图生图 / 编辑
bash ~/.codex/skills/wowfish-image/scripts/openai-image.sh edit \
--prompt "把背景换成下雪的雪山" \
--image ./otter.png --out ./otter-snow.png
```
Windows(PowerShell):
```powershell
# 文生图
powershell -ExecutionPolicy Bypass -File "$HOME\.codex\skills\wowfish-image\scripts\openai-image.ps1" `
generate -Prompt "一只戴贝雷帽的小水獭" -Out .\otter.png
# 图生图 / 编辑
pwsh -ExecutionPolicy Bypass -File "$HOME\.codex\skills\wowfish-image\scripts\openai-image.ps1" `
edit -Prompt "把背景换成雪山" -Image .\otter.png -Out .\otter-snow.png
```
Windows 的 `edit` 依赖 PowerShell 7+ 的 `Invoke-RestMethod -Form`。如果用户是自带的 Windows PowerShell 5,文生图可用,图生图建议安装 PowerShell 7。
### 第 4 步:报告结果
脚本会把 Base64 或 URL 返回的图片保存到本地,并打印保存路径。把保存的文件路径告诉用户,并尽量展示本地图片。
如果下载或解码失败,脚本会退出并打印明确错误;不要把 0B 文件当作成功结果。
## 接口与参数速查
| 接口 | 方法 | 用途 | 关键参数 |
| --- | --- | --- | --- |
| `/images/generations` | POST JSON | 文生图 | `model`、`prompt`、`n`、`size`、`quality` |
| `/images/edits` | POST multipart | 图生图 / 编辑 / 扩展 | `image[]`、`prompt`、`mask`、`n`、`size` |
要点:
- `gpt-image` 系列接口通常返回 `b64_json`,脚本会自动解码落地;部分中转或模型可能返回 `url`,脚本会立即下载保存。
- `dall-e-3` 不支持 `/images/edits` 编辑端点;要做图生图请用 `gpt-image-2` 或接口实际支持的图片编辑模型。
- `mask` 是掩码图片,透明区域表示要重绘的位置,必须是与原图同尺寸的 PNG。
## 常见问题
- 报错“未找到 base_url 或 api_key”:回到第 1 步,在 `.env` 里补全。
- 接口报错:常见原因是 api_key 错误、余额不足,或当前接口不支持所选模型。
- 保存出 0B 文件或下载失败:不要当作成功,检查接口返回是否有非空 `b64_json` 或 `url`。
- 想换模型:加 `--model 模型名`,例如 `--model dall-e-3` 仅适合文生图。
- 想减少扣费:明确告诉 Codex 只调用一次,不自动重试。~/.codex/skills/wowfish-image/scripts/openai-image.sh把下面内容保存为 ~/.codex/skills/wowfish-image/scripts/openai-image.sh,然后执行 chmod +x ~/.codex/skills/wowfish-image/scripts/openai-image.sh。
#!/usr/bin/env bash
set -euo pipefail
ENV_FILE="${OPENAI_IMAGE_ENV:-$HOME/.codex/.env}"
DEFAULT_MODEL="${OPENAI_IMAGE_MODEL:-gpt-image-2}"
err() { printf '%s\n' "$*" >&2; }
read_cfg() {
local key="$1" line value
[ -f "$ENV_FILE" ] || return 0
line="$(grep -E "^[[:space:]]*${key}[[:space:]]*=" "$ENV_FILE" 2>/dev/null | head -1 || true)"
[ -n "$line" ] || return 0
value="${line#*=}"
value="$(printf '%s' "$value" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
value="$(printf '%s' "$value" | sed -E 's/^"(.*)"$/\1/; s/^'\''(.*)'\''$/\1/')"
printf '%s' "$value"
}
BASE_URL="$(read_cfg base_url)"
API_KEY="$(read_cfg api_key)"
HTTP_PROXY_VALUE="$(read_cfg http_proxy)"
HTTPS_PROXY_VALUE="$(read_cfg https_proxy)"
[ -n "$HTTP_PROXY_VALUE" ] && export http_proxy="$HTTP_PROXY_VALUE" HTTP_PROXY="$HTTP_PROXY_VALUE"
[ -n "$HTTPS_PROXY_VALUE" ] && export https_proxy="$HTTPS_PROXY_VALUE" HTTPS_PROXY="$HTTPS_PROXY_VALUE"
if [ -z "$BASE_URL" ] || [ -z "$API_KEY" ]; then
err "ERROR: missing base_url or api_key in $ENV_FILE"
err "Add these lines:"
err " base_url=https://api.wowfish.me/v1"
err " api_key=sk-your-key"
exit 2
fi
BASE_URL="${BASE_URL%/}"
MODE="${1:-}"
if [ $# -gt 0 ]; then shift; fi
PROMPT=""
MODEL="$DEFAULT_MODEL"
SIZE="1024x1024"
N="1"
QUALITY=""
OUT=""
MASK=""
IMAGES=()
while [ $# -gt 0 ]; do
case "$1" in
--prompt) PROMPT="${2:-}"; shift 2 ;;
--model) MODEL="${2:-}"; shift 2 ;;
--size) SIZE="${2:-}"; shift 2 ;;
--n) N="${2:-}"; shift 2 ;;
--quality) QUALITY="${2:-}"; shift 2 ;;
--out) OUT="${2:-}"; shift 2 ;;
--mask) MASK="${2:-}"; shift 2 ;;
--image) IMAGES+=("${2:-}"); shift 2 ;;
*) err "Unknown argument: $1"; exit 2 ;;
esac
done
[ -n "$PROMPT" ] || { err "ERROR: missing --prompt"; exit 2; }
case "$N" in ''|*[!0-9]*) err "ERROR: --n must be a positive integer"; exit 2 ;; esac
[ "$N" -ge 1 ] || { err "ERROR: --n must be at least 1"; exit 2; }
if [ -z "$OUT" ]; then
OUT="./image-$(date +%Y%m%d-%H%M%S).png"
fi
mkdir -p "$(dirname "$OUT")"
RESP_FILE="$(mktemp -t wowfish-image.XXXXXX.json)"
trap 'rm -f "$RESP_FILE"' EXIT
json_escape() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | tr '\n' ' '
}
output_path_for_index() {
local index="$1" extension base
if [ "$index" -eq 0 ]; then
printf '%s' "$OUT"
return
fi
extension="${OUT##*.}"
if [ "$OUT" != "${OUT%.*}" ]; then
base="${OUT%.*}"
printf '%s_%s.%s' "$base" "$index" "$extension"
else
printf '%s_%s' "$OUT" "$index"
fi
}
commit_file() {
local tmp="$1" final="$2"
if [ ! -s "$tmp" ]; then
rm -f "$tmp"
err "ERROR: generated file is empty: $final"
return 1
fi
mv "$tmp" "$final"
printf 'Saved: %s\n' "$final"
}
save_b64() {
local b64="$1" final="$2" tmp
tmp="$(mktemp "${final}.XXXXXX")"
if printf '%s' "$b64" | base64 -d > "$tmp" 2>/dev/null; then
commit_file "$tmp" "$final"
elif printf '%s' "$b64" | base64 -D > "$tmp" 2>/dev/null; then
commit_file "$tmp" "$final"
else
rm -f "$tmp"
err "ERROR: base64 decode failed for $final"
return 1
fi
}
save_url() {
local url="$1" final="$2" tmp
tmp="$(mktemp "${final}.XXXXXX")"
if ! curl -fsSL "$url" -o "$tmp"; then
rm -f "$tmp"
err "ERROR: URL download failed: $url"
return 1
fi
commit_file "$tmp" "$final"
}
extract_field() {
local object="$1" field="$2" match
match="$(printf '%s' "$object" | grep -o "\"$field\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | head -1 || true)"
[ -n "$match" ] || return 0
printf '%s' "$match" | sed -E "s/.*\"$field\"[[:space:]]*:[[:space:]]*\"//; s/\"$//"
}
json_url_unescape() {
printf '%s' "$1" | sed -E 's#\\/#/#g; s#\\u0026#\g'
}
save_outputs() {
local compact objects object b64 url file index
compact="$(tr -d '\n' < "$RESP_FILE")"
objects="$(printf '%s' "$compact" | grep -o '{[^{}]*}' || true)"
index=0
if [ -n "$objects" ]; then
while IFS= read -r object; do
[ -n "$object" ] || continue
b64="$(extract_field "$object" b64_json)"
url="$(extract_field "$object" url)"
file="$(output_path_for_index "$index")"
if [ -n "$b64" ]; then
save_b64 "$b64" "$file" || exit 1
index=$((index + 1))
elif [ -n "$url" ]; then
url="$(json_url_unescape "$url")"
save_url "$url" "$file" || exit 1
index=$((index + 1))
fi
done <&2
exit 1
fi
}
case "$MODE" in
generate)
ESC_PROMPT="$(json_escape "$PROMPT")"
BODY="$(printf '{"model":"%s","prompt":"%s","n":%s,"size":"%s"' "$MODEL" "$ESC_PROMPT" "$N" "$SIZE")"
[ -n "$QUALITY" ] && BODY="${BODY},\"quality\":\"${QUALITY}\""
BODY="${BODY}}"
curl -sS "$BASE_URL/images/generations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "$BODY" \
-o "$RESP_FILE"
;;
edit)
[ "${#IMAGES[@]}" -gt 0 ] || { err "ERROR: edit mode requires at least one --image"; exit 2; }
ARGS=(-sS "$BASE_URL/images/edits" -H "Authorization: Bearer $API_KEY" -F "model=$MODEL" -F "prompt=$PROMPT" -F "n=$N" -F "size=$SIZE")
for img in "${IMAGES[@]}"; do
[ -f "$img" ] || { err "ERROR: image file not found: $img"; exit 2; }
ARGS+=(-F "image[]=@${img}")
done
if [ -n "$MASK" ]; then
[ -f "$MASK" ] || { err "ERROR: mask file not found: $MASK"; exit 2; }
ARGS+=(-F "mask=@${MASK}")
fi
[ -n "$QUALITY" ] && ARGS+=(-F "quality=$QUALITY")
curl "${ARGS[@]}" -o "$RESP_FILE"
;;
*)
err "Usage: openai-image.sh {generate|edit} --prompt \"...\" [--out image.png]"
exit 2
;;
esac
if grep -q '"error"' "$RESP_FILE"; then
if ! grep -q '"b64_json"\|"url"' "$RESP_FILE"; then
err "ERROR: API returned an error:"
cat "$RESP_FILE" >&2
exit 1
fi
fi
save_outputs ~/.codex/skills/wowfish-image/scripts/openai-image.ps1把下面内容保存为 %USERPROFILE%\.codex\skills\wowfish-image\scripts\openai-image.ps1。文生图可以用系统自带 PowerShell;图生图和编辑建议使用 pwsh,也就是 PowerShell 7+。
<#
Generate or edit images through the Wowfish OpenAI-compatible Images API.
Configuration is read from $HOME\.codex\.env by default, or from OPENAI_IMAGE_ENV when set.
#>
param(
[Parameter(Position = 0, Mandatory = $true)]
[ValidateSet('generate', 'edit')]
[string]$Mode,
[string]$Prompt,
[string]$Model = 'gpt-image-2',
[string]$Size = '1024x1024',
[int]$N = 1,
[string]$Quality = '',
[string]$Out = '',
[string]$Image = '',
[string]$Image2 = '',
[string]$Mask = ''
)
$ErrorActionPreference = 'Stop'
$EnvFile = if ($env:OPENAI_IMAGE_ENV) { $env:OPENAI_IMAGE_ENV } else { Join-Path $HOME '.codex\.env' }
function Read-Cfg([string]$Key) {
if (-not (Test-Path -LiteralPath $EnvFile)) { return '' }
foreach ($line in Get-Content -LiteralPath $EnvFile) {
if ($line -match "^\s*$([regex]::Escape($Key))\s*=\s*(.*)$") {
return $Matches[1].Trim().Trim('"').Trim("'")
}
}
return ''
}
function Set-ProxyFromCfg([string]$Key, [string]$Lower, [string]$Upper) {
$value = Read-Cfg $Key
if ($value) {
[Environment]::SetEnvironmentVariable($Lower, $value, 'Process')
[Environment]::SetEnvironmentVariable($Upper, $value, 'Process')
}
}
$BaseUrl = Read-Cfg 'base_url'
$ApiKey = Read-Cfg 'api_key'
if (-not $BaseUrl -or -not $ApiKey) {
Write-Error "Missing base_url or api_key in $EnvFile. Add base_url=https://api.wowfish.me/v1 and api_key=sk-your-key."
exit 2
}
if (-not $Prompt) {
Write-Error 'Missing -Prompt.'
exit 2
}
if ($N -lt 1) {
Write-Error '-N must be at least 1.'
exit 2
}
$BaseUrl = $BaseUrl.TrimEnd('/')
Set-ProxyFromCfg 'http_proxy' 'http_proxy' 'HTTP_PROXY'
Set-ProxyFromCfg 'https_proxy' 'https_proxy' 'HTTPS_PROXY'
if (-not $Out) {
$Out = ".\image-$(Get-Date -Format yyyyMMdd-HHmmss).png"
}
$OutDir = Split-Path -Parent $Out
if ($OutDir -and -not (Test-Path -LiteralPath $OutDir)) {
New-Item -ItemType Directory -Path $OutDir | Out-Null
}
$Headers = @{ Authorization = "Bearer $ApiKey" }
function Get-OutputPath([int]$Index) {
$extension = [System.IO.Path]::GetExtension($Out)
$baseName = if ($extension) { $Out.Substring(0, $Out.Length - $extension.Length) } else { $Out }
if ($Index -eq 0) { return $Out }
if ($extension) { return "${baseName}_$Index$extension" }
return "${baseName}_$Index"
}
function Commit-ImageFile([string]$TempFile, [string]$FinalFile) {
if (-not (Test-Path -LiteralPath $TempFile) -or (Get-Item -LiteralPath $TempFile).Length -le 0) {
Remove-Item -LiteralPath $TempFile -Force -ErrorAction SilentlyContinue
throw "Generated file is empty: $FinalFile"
}
Move-Item -LiteralPath $TempFile -Destination $FinalFile -Force
Write-Host "Saved: $FinalFile"
}
function Save-B64Image([string]$B64, [string]$FinalFile) {
$tempFile = [System.IO.Path]::GetTempFileName()
try {
[System.IO.File]::WriteAllBytes($tempFile, [System.Convert]::FromBase64String($B64))
} catch {
Remove-Item -LiteralPath $tempFile -Force -ErrorAction SilentlyContinue
throw "Base64 decode failed for $FinalFile. $($_.Exception.Message)"
}
Commit-ImageFile $tempFile $FinalFile
}
function Save-UrlImage([string]$Url, [string]$FinalFile) {
$tempFile = [System.IO.Path]::GetTempFileName()
$client = New-Object System.Net.WebClient
try {
$client.DownloadFile($Url, $tempFile)
} catch {
Remove-Item -LiteralPath $tempFile -Force -ErrorAction SilentlyContinue
throw "URL download failed for $Url. $($_.Exception.Message)"
} finally {
$client.Dispose()
}
Commit-ImageFile $tempFile $FinalFile
}
function Save-Outputs($Data) {
$saved = 0
foreach ($item in @($Data)) {
if ($null -eq $item) { continue }
$outputFile = Get-OutputPath $saved
$b64 = if ($null -ne $item.b64_json) { [string]$item.b64_json } else { '' }
$url = if ($null -ne $item.url) { [string]$item.url } else { '' }
if ($b64.Trim().Length -gt 0) {
Save-B64Image $b64 $outputFile
$saved++
continue
}
if ($url.Trim().Length -gt 0) {
Save-UrlImage $url.Trim() $outputFile
$saved++
continue
}
}
if ($saved -eq 0) {
throw 'API response did not contain non-empty b64_json or url image data.'
}
}
if ($Mode -eq 'generate') {
$bodyObject = @{
model = $Model
prompt = $Prompt
n = $N
size = $Size
}
if ($Quality) { $bodyObject.quality = $Quality }
$body = $bodyObject | ConvertTo-Json -Compress
$response = Invoke-RestMethod -Method Post -Uri "$BaseUrl/images/generations" -Headers $Headers -ContentType 'application/json' -Body $body
Save-Outputs $response.data
} elseif ($Mode -eq 'edit') {
if (-not $Image) {
Write-Error 'Edit mode requires -Image.'
exit 2
}
if (-not (Test-Path -LiteralPath $Image)) {
Write-Error "Image file not found: $Image"
exit 2
}
if ($Image2 -and -not (Test-Path -LiteralPath $Image2)) {
Write-Error "Image2 file not found: $Image2"
exit 2
}
if ($Mask -and -not (Test-Path -LiteralPath $Mask)) {
Write-Error "Mask file not found: $Mask"
exit 2
}
if ($PSVersionTable.PSVersion.Major -lt 7) {
Write-Error 'Edit mode requires PowerShell 7+ because Windows PowerShell 5 does not support Invoke-RestMethod -Form.'
exit 2
}
$form = @{
model = $Model
prompt = $Prompt
n = "$N"
size = $Size
}
$images = @(Get-Item -LiteralPath $Image)
if ($Image2) { $images += Get-Item -LiteralPath $Image2 }
$form['image[]'] = $images
if ($Mask) { $form['mask'] = Get-Item -LiteralPath $Mask }
if ($Quality) { $form['quality'] = $Quality }
$response = Invoke-RestMethod -Method Post -Uri "$BaseUrl/images/edits" -Headers $Headers -Form $form
Save-Outputs $response.data
}四个文件就位后,重启 Codex,输入 /image 选择 wowfish-image 技能,再描述你想要的图片即可。
切换配置前,先退出 Codex App 和 IDE 插件,避免文件被占用或旧配置仍在进程缓存里。
把 Wowfish 的 config.toml 和 auth.json 改名保留。Codex 下次启动时会按官方登录流程重新建立配置。
# macOS / Linux
mv ~/.codex/config.toml ~/.codex/config.toml.wowfish
mv ~/.codex/auth.json ~/.codex/auth.json.wowfish# Windows PowerShell
Rename-Item "$env:USERPROFILE\.codex\config.toml" "config.toml.wowfish"
Rename-Item "$env:USERPROFILE\.codex\auth.json" "auth.json.wowfish"重启 Codex 后按提示登录 OpenAI 官方账号。要切回 Wowfish 时,再把备份文件改回原名,或通过 CC-Switch 启用 Wowfish 供应商配置。
聊天记录通常还在本地,只是 Codex 会按 provider 名称或配置上下文分组。切换中转、官方账号或供应商配置后,你可能看到的是另一组记录。需要恢复官方登录时,先看 切换回官方账号。
打开 ~/.codex/config.toml,让下面三个 provider 名称完全一致。需要恢复 Wowfish 记录时,建议都使用 wowfish。
model_provider = "wowfish"
[model_providers.wowfish]
name = "wowfish"
base_url = "https://api.wowfish.me/v1"config.toml。教程默认提供 gpt-5.5、gpt-5.4、gpt-5.4-mini;high、medium、low、minimal 推理档位都可以配置。
不需要。可以先用占位符让 Codex 写配置,最后自己替换真实 key。网页脚本生成器也只在浏览器本地处理输入。
确认 CC-Switch 已安装并启动,系统能识别 ccswitch:// 协议,浏览器弹窗时允许打开外部应用。
官方插件、连接器或网页登录态异常时,先按 切换回官方账号 恢复官方登录,再判断是不是 Wowfish API 配置问题。
会写入新的 config.toml 和 auth.json,但写入前会创建带时间戳的备份,例如 config.toml.bak-YYYYMMDD-HHMMSS。
先确认 openclaw.json 中 provider 名称是 wowfish,API 请求地址是 https://api.wowfish.me/v1,然后重启 gateway。
平台余额、订阅套餐、用量和账单状态以 API 控制台展示为准。
平台余额和订阅套餐可以同时使用;平台余额用于按量扣费,但不能用于购买或续费订阅套餐。按量充值适合灵活使用;订阅套餐适合长期使用、团队使用或希望稳定控制成本的用户。
人民币计价的国产模型,会按 7:1 折算为平台钱包额度。
具体可选订阅套餐、有效期和平台余额按量扣费记录以 API 控制台展示为准。
Codex 是 Agent,不是普通聊天框。它可能会读取目录、分析文件、运行命令或多轮思考,因此一次任务会产生多次请求和更多上下文消耗。
high。https://api.wowfish.me/v1。auth.json。~/.codex 或 ~/.openclaw 是否在当前用户目录。如果报错和 OpenAI 官方账号、官方登录态、插件授权或网页登录有关,先打开 切换回官方账号 验证官方配置是否正常,再回到 Wowfish 配置排查。
Windows 用户优先使用 PowerShell,路径通常是 $env:USERPROFILE\.codex。如果文件资源管理器看不到隐藏目录,先开启“显示隐藏的项目”。