Codex 调用 gpt-image-2 生图实战:Windows 固定配置、脚本封装与代理兼容

Codex 调用 gpt-image-2 生图实战:Windows 固定配置、脚本封装与代理兼容

本文记录如何在 Windows 的 Codex 工作区中固定保存图像 API 配置,并通过一个 PowerShell 命令调用 gpt-image-2 生成图片。方案支持内联提示词和提示词文件,也兼容接口返回 Base64 或临时图片 URL 两种情况。

一、最终效果

配置完成后,在项目根目录执行:

powershell 复制代码
.\scripts\generate-image.ps1 `
  -Prompt "一朵粉色水彩花,白色背景,画面简洁,不要文字" `
  -OutFile ".\outputs\pink-flower.png"

脚本会自动完成以下操作:

  1. 读取固定 API 地址、模型和默认参数;
  2. 从本地文件加载 API Key;
  3. 查找 Codex 自带的 Python 运行时;
  4. 首次运行时自动安装依赖;
  5. 调用 gpt-image-2
  6. 处理 Base64 或图片 URL 响应;
  7. 将最终 PNG 保存到 outputs 目录。

发布文章时,可以在这里插入一张自己的测试生成图。

二、项目结构

text 复制代码
项目目录/
├─ config/
│  ├─ imagegen.json          # API 地址、模型及默认参数
│  └─ api-key.txt            # API Key,本地明文文件,不提交 Git
├─ scripts/
│  ├─ generate-image.ps1     # 统一调用入口
│  └─ imagegen_client.py     # Python 图像 API 客户端
├─ outputs/                  # 图片输出目录
├─ work/                     # 提示词文件等临时内容
├─ .imagegen-runtime/        # 自动安装的 Python 依赖
└─ .gitignore

三、准备配置文件

1. 图像 API 配置

新建 config/imagegen.json

json 复制代码
{
  "base_url": "https://your-api-host.example/v1",
  "model": "gpt-image-2",
  "size": "1024x1024",
  "quality": "low",
  "output_format": "png"
}

参数说明:

参数 说明
base_url OpenAI 兼容接口地址,通常以 /v1 结尾
model 生图模型,本文使用 gpt-image-2
size 默认分辨率,例如 1024x1024
quality lowmediumhighauto
output_format 输出格式,本文使用 png

low 适合快速预览,正式海报可以改为 high。常用横向尺寸有 1536x10242048x1152,方形图片可以使用 1024x10242048x2048

2. 固定 API Key

新建 config/api-key.txt,文件中只保存一行 Key:

text 复制代码
sk-your-api-key-here

本文为了调用方便使用明文文件。该文件属于敏感信息,必须加入 .gitignore,不要上传到 GitHub、网盘或文章附件。

3. 配置 .gitignore

gitignore 复制代码
# 本地 API 凭据和运行依赖
config/api-key.txt
.imagegen-runtime/

四、编写 Python 图像客户端

新建 scripts/imagegen_client.py

python 复制代码
import argparse
import base64
from pathlib import Path


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Generate an image with a GPT Image compatible API"
    )
    prompt_group = parser.add_mutually_exclusive_group(required=True)
    prompt_group.add_argument("--prompt")
    prompt_group.add_argument("--prompt-file")
    parser.add_argument("--out", required=True)
    parser.add_argument("--model", required=True)
    parser.add_argument("--size", required=True)
    parser.add_argument("--quality", required=True)
    parser.add_argument("--output-format", default="png")
    return parser.parse_args()


def main() -> int:
    args = parse_args()

    from openai import OpenAI
    import httpx2

    prompt = args.prompt
    if args.prompt_file:
        prompt = Path(args.prompt_file).read_text(encoding="utf-8")

    result = OpenAI().images.generate(
        model=args.model,
        prompt=prompt,
        n=1,
        size=args.size,
        quality=args.quality,
        output_format=args.output_format,
    )

    item = result.data[0]

    # 官方接口可能返回 Base64,部分兼容网关则返回临时 URL。
    if item.b64_json:
        image_bytes = base64.b64decode(item.b64_json)
    elif item.url:
        response = httpx2.get(
            item.url,
            timeout=600,
            follow_redirects=True,
        )
        response.raise_for_status()
        image_bytes = response.content
    else:
        raise RuntimeError(
            "The API response contains neither b64_json nor url"
        )

    output = Path(args.out).resolve()
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_bytes(image_bytes)
    print(f"Saved image: {output} ({len(image_bytes)} bytes)")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

这段代码中最重要的是同时判断 b64_jsonurl。部分 OpenAI 兼容网关虽然完成了生图,但返回的是 URL。如果代码只读取 b64_json,保存阶段可能出现下面的错误:

text 复制代码
TypeError: argument should be a bytes-like object or ASCII string,
not 'NoneType'

这并不一定表示生成失败,而可能只是响应格式与客户端预期不同。

五、编写 PowerShell 统一入口

新建 scripts/generate-image.ps1

powershell 复制代码
[CmdletBinding(DefaultParameterSetName = 'InlinePrompt')]
param(
    [Parameter(Mandatory = $true, ParameterSetName = 'InlinePrompt')]
    [string]$Prompt,

    [Parameter(Mandatory = $true, ParameterSetName = 'PromptFile')]
    [string]$PromptFile,

    [Parameter(Mandatory = $true)]
    [string]$OutFile,

    [string]$Model,
    [string]$Size,

    [ValidateSet('low', 'medium', 'high', 'auto')]
    [string]$Quality
)

$ErrorActionPreference = 'Stop'
$projectRoot = Split-Path -Parent $PSScriptRoot
$configPath = Join-Path $projectRoot 'config\imagegen.json'
$keyPath = Join-Path $projectRoot 'config\api-key.txt'
$clientPath = Join-Path $PSScriptRoot 'imagegen_client.py'
$packagePath = Join-Path $projectRoot '.imagegen-runtime\python-packages'

if (-not (Test-Path -LiteralPath $configPath)) {
    throw "Missing configuration file: $configPath"
}

if (-not (Test-Path -LiteralPath $keyPath)) {
    throw "Missing API key file: $keyPath"
}

$config = Get-Content -Raw -LiteralPath $configPath | ConvertFrom-Json

if (-not $Model) { $Model = $config.model }
if (-not $Size) { $Size = $config.size }
if (-not $Quality) { $Quality = $config.quality }

[array]$pythonCandidates = @(
    (Get-Command python -ErrorAction SilentlyContinue).Source,
    "$env:USERPROFILE\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
) | Where-Object {
    $_ -and (Test-Path -LiteralPath $_)
}

if (-not $pythonCandidates) {
    throw 'Python was not found. Open this project in Codex once.'
}

$pythonExe = $pythonCandidates[0]

# 依赖只安装到当前项目,不污染系统 Python。
New-Item -ItemType Directory -Force -Path $packagePath | Out-Null
$env:PYTHONPATH = $packagePath

& $pythonExe -c 'import openai, httpx2' 2>$null
if ($LASTEXITCODE -ne 0) {
    Write-Host 'Installing local image-generation dependencies...'
    & $pythonExe -m pip install `
        --disable-pip-version-check `
        --target $packagePath `
        openai pillow

    if ($LASTEXITCODE -ne 0) {
        throw 'Failed to install image-generation dependencies.'
    }
}

$apiKey = (Get-Content -Raw -LiteralPath $keyPath).Trim()
if ([string]::IsNullOrWhiteSpace($apiKey)) {
    throw "API key file is empty: $keyPath"
}

try {
    # 只把凭据注入当前调用进程。
    $env:OPENAI_API_KEY = $apiKey
    $env:OPENAI_BASE_URL = $config.base_url

    $arguments = @(
        $clientPath,
        '--out', $OutFile,
        '--model', $Model,
        '--size', $Size,
        '--quality', $Quality,
        '--output-format', $config.output_format
    )

    if ($PSCmdlet.ParameterSetName -eq 'PromptFile') {
        $arguments += @(
            '--prompt-file',
            (Resolve-Path -LiteralPath $PromptFile).Path
        )
    }
    else {
        $arguments += @('--prompt', $Prompt)
    }

    & $pythonExe @arguments

    if ($LASTEXITCODE -ne 0) {
        throw "Image generation failed with exit code $LASTEXITCODE"
    }
}
finally {
    # 调用结束后清理当前进程中的环境变量。
    $apiKey = $null
    Remove-Item Env:OPENAI_API_KEY -ErrorAction SilentlyContinue
    Remove-Item Env:OPENAI_BASE_URL -ErrorAction SilentlyContinue
    Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
}

注意这里的 [array]$pythonCandidates。如果候选路径只有一个,而变量被当作普通字符串处理,$pythonCandidates[0] 可能只得到盘符首字母 C,随后出现:

text 复制代码
The term 'C' is not recognized as a name of a cmdlet

显式声明为数组即可避免这个问题。

六、运行方式

1. 直接传入提示词

powershell 复制代码
.\scripts\generate-image.ps1 `
  -Prompt "一朵蓝色水彩花,白色背景,居中构图,无文字,无水印" `
  -OutFile ".\outputs\blue-flower.png"

2. 使用提示词文件

复杂海报适合把提示词保存在 work/poster-prompt.txt

text 复制代码
Use case: stylized-concept
Asset type: landscape character poster
Primary request: 一张左右分屏的足球人物插画海报
Style/medium: 手绘数字水粉与墨线
Composition/framing: 2048x1152 横向画布,严格左右平衡
Lighting/mood: 体育场灯光,强烈但保留人物面部细节
Constraints: 无水印,无乱码文字,无多余人物

执行:

powershell 复制代码
.\scripts\generate-image.ps1 `
  -PromptFile ".\work\poster-prompt.txt" `
  -OutFile ".\outputs\poster.png" `
  -Size "2048x1152" `
  -Quality "high"

命令行中的 -Size-Quality-Model 会覆盖 JSON 中的默认值。

七、推荐的提示词结构

复杂图片不要只写一句主题,建议使用结构化提示词:

text 复制代码
Use case: stylized-concept
Asset type: 图片用途
Primary request: 核心画面要求
Scene/backdrop: 场景与背景
Subject: 主体、数量和位置
Style/medium: 插画、摄影、水彩、3D 等
Composition/framing: 横竖比例、景别和留白
Lighting/mood: 光线与情绪
Color palette: 主色与辅助色
Constraints: 必须满足的限制
Avoid: 不要出现的内容

对于人物群像,建议明确写出:

  • 人物总数及左右各有多少人;
  • 中心人物与辅助人物的位置;
  • 胸像、半身还是全身;
  • 是否需要文字、队徽、商标;
  • 禁止重复人物、额外手臂、乱码和水印。

八、常见问题排查

1. OPENAI_API_KEY is not set

检查 config/api-key.txt 是否存在、是否为空。文件中不要增加引号或说明文字。

2. Authentication failed

可能原因包括:

  • Key 无效或已经过期;
  • base_url 缺少 /v1
  • API 服务的 TLS 或证书与 PowerShell 客户端不兼容;
  • 接口服务限制了来源 IP。

如果 PowerShell 的 Invoke-RestMethod 失败,而 Python SDK 可以访问,可以继续使用本文的 Python 客户端通道。

3. 生图完成后出现 NoneType Base64 错误

兼容网关可能返回 url,而不是 b64_json。本文客户端已经同时兼容两种响应字段。

4. content_policy_violation

简化提示词中对真人身份、暴力、敏感内容或强身份复刻的表述。可以把"完全一致的真人肖像"调整为"编辑插画风格的致敬形象",同时保留构图与服装要求。

5. 高质量图片等待时间较长

这是正常现象。建议先用:

text 复制代码
size: 1024x1024
quality: low

确认构图后,再改为 2K 与 high 生成最终版本。

九、安全建议

本文采用明文 Key 文件,优点是调用方便,缺点是任何能读取项目目录的程序都可能读取凭据。至少应做到:

  1. 始终将 config/api-key.txt 加入 .gitignore
  2. 不要在截图、录屏和文章代码中展示真实 Key;
  3. 不要把整个项目目录打包上传;
  4. 定期轮换 Key,并设置额度或调用限制;
  5. Key 一旦在公开页面出现,应立即作废并重新生成。

生产环境更推荐系统凭据库、环境变量或专用密钥管理服务。

十、总结

通过 JSON 配置、PowerShell 入口和 Python 客户端三层拆分,可以把 Codex 生图流程固定下来:日常只需要提供提示词和输出路径,不必每次重新输入 API 地址、模型与 Key。

本文方案还解决了两个 Windows 和兼容网关中常见的问题:Python 路径被误取成首字符,以及接口返回 URL 导致 Base64 保存失败。配置完成后,简单插画、人物海报和高分辨率横幅都可以使用同一个命令生成。


推荐标题: Codex 调用 gpt-image-2 生图实战:Windows 固定配置、脚本封装与代理兼容

文章摘要: 本文介绍如何在 Windows Codex 工作区中固定保存 gpt-image-2 的 API 配置,通过 PowerShell 与 Python 封装统一生图入口,并解决兼容网关返回 URL、Python 路径解析、依赖隔离等常见问题。

推荐标签: CodexOpenAIgpt-image-2AIGCPythonPowerShell

相关推荐
仙逆GPT1 小时前
ChatGPT、Codex趋势:为什么AI时代最重要的能力,不是写代码,而是定义问题?
chatgpt·codex·ai agent·chatgpt plus·chatgpt pro·ai coding
JavaPub-rodert2 小时前
DeepSeek 终于能看图了:V4 Flash Vision 上线,我觉得真正重要的是这件事
人工智能·codex
前进的程序员4 小时前
告别Copilot?Codex本地化部署指南
开源·php·copilot·codex
枫叶丹420 小时前
MCP、A2A、AG-UI:一篇讲清 Agent 协议栈
人工智能·ui·chatgpt·agent·codex
key_3_feng1 天前
Codex + Skills让原始记录自动变成 KPI 与图表
codex·ai coding
潘正翔2 天前
DeepSeek Harness从0到1部署
人工智能·开发·codex·deepseek·harness·deepseekharness·cludecode
番茄不是西红柿kk3 天前
什么是Token?
人工智能·ai·chatgpt·agent·token·codex·deepseek