create-image-gpt-image-fal
Purpose
Generate one image via fal.ai's OpenAI gpt-image endpoints. Two model families are supported through a single --model flag:
gpt-image-1 (default) — fal-ai/gpt-image-1. The FAL fallback for Higgsfield's gpt_image_2. Fixed output sizes only. Used by:
video-orchestrator/lock-character Phase 0 (anchor portrait) and Phase 1 (angle keyframes via /edit)
video-orchestrator/create-clips Phase 1 for photoreal scenes
- the orchestrator's
generate_with_fallback.py router on Higgsfield failure
gpt-image-2 — openai/gpt-image-2. The newer model; accepts custom output sizes (any multiple of 16, up to 3840px) and renders dense text/layouts well. Used for designed sheets such as ad storyboards (create-storyboard-sheets-fal).
The default stays gpt-image-1 so existing callers and the lock-character anchor-parity contract are unaffected. Opt into the newer model with --model gpt-image-2.
Pricing (approximate, as of 2026-05)
The script defaults to medium; pass --quality high for finals.
Inputs
Required:
--prompt — text prompt. A verbatim character descriptor block goes here for character work.
--output — local PNG destination.
Optional:
--model — gpt-image-1 (default) or gpt-image-2.
--aspect-ratio — 9:16 (default), 16:9, 1:1, 2:3, 3:2. gpt-image-2 also accepts 3:4, 4:3, 4:5. Used when --image-size is not given.
--image-size — explicit WIDTHxHEIGHT (e.g. 1728x2304). gpt-image-2 only — values are rounded to multiples of 16 and capped at 3840px. On gpt-image-1 a custom size is ignored with a warning and the aspect-ratio mapping is used instead.
--quality — low | medium | high (default medium).
--ref-image — local image path. Repeatable — pass --ref-image PATH --ref-image PATH to send multiple refs (e.g. identity + style). When present, routes to the model's /edit variant so the model can match the references (used for character angle gens off an anchor, and for style-anchor + identity-anchor composition). Order matters: pass identity (character) first, then style refs.
--with-logs — stream fal queue logs.
Credentials:
FAL_API_KEY (or FAL_KEY) in .env.
Preflight
test -n "$FAL_API_KEY" || test -n "$FAL_KEY" || { echo "Missing FAL_API_KEY / FAL_KEY in .env"; exit 1; }
python3 -c "import fal_client" || pip3 install fal_client
Workflow
# Text-to-image, default model (gpt-image-1)
python3 skills/ads/capabilities/create-image-gpt-image-fal/scripts/generate.py \
--prompt "..." \
--output /path/to/anchor.png \
--aspect-ratio 9:16 \
--quality medium
# Edit-from-reference (anchor -> angle), default model
python3 .../generate.py \
--prompt "..." \
--output /path/to/angle-3q-left.png \
--ref-image /path/to/anchor.png \
--aspect-ratio 9:16
# gpt-image-2 with a custom output size (e.g. a designed storyboard sheet)
python3 .../generate.py \
--prompt "..." \
--output /path/to/storyboard.png \
--model gpt-image-2 \
--image-size 1728x2304 \
--quality high
The script:
- Loads the FAL key via
fal_helpers.load_fal_key().
- Resolves the model family (
--model) and output size (--image-size if given and supported, else the aspect-ratio mapping).
- If one or more
--ref-image flags are set, uploads each to fal storage and routes to the model's /edit variant with image_urls=[url1, url2, ...]. Otherwise routes to the /text-to-image variant.
- Calls
fal_client.subscribe(model, payload) via fal_helpers.subscribe.
- Downloads the first result image to
--output.
- Writes
<output>.meta.json with gateway, model id, model_family, request, and cost.
Output
<output_path> — PNG (≥ 1 KB).
<output_path>.meta.json — request + result metadata + cost, including model_family (gpt-image-1 or gpt-image-2).
Quality Checks
- Output file exists and is > 1 KB.
- For character anchors: visually inspect against the descriptor block (hair, shirt color, age).
meta.json includes gateway: "fal", the resolved model id, model_family, image_size, and quality.
- For gpt-image-2 custom sizes: confirm the output dimensions match the requested
WIDTHxHEIGHT.
- No readable text in the prompt that should appear in the image. AI image models mangle short brand text, URLs, code tokens, captions, and wordmarks even with explicit prompting. Examples observed:
"ffmpeg" → "ffmmg"; "klarify" → "clarify"; "therapists" → "therapits". Use PIL or ffmpeg drawtext for any overlay containing readable text. Reserve image gen for purely visual content (characters, scenes, backgrounds). Repeats LEARNINGS L4.
Failure Modes
| Symptom |
Likely cause |
Fix |
401 Unauthorized |
Bad FAL key |
Verify FAL_API_KEY / FAL_KEY in .env. |
429 Too Many Requests |
RPS limit |
Drop concurrency to 2-3. |
| Custom size ignored |
--image-size passed with --model gpt-image-1 |
gpt-image-1 only supports fixed sizes; use --model gpt-image-2 for custom sizes. |
| Aspect-ratio drift (gpt-image-1) |
gpt-image-1 only supports 1024x1024, 1024x1536, 1536x1024 |
The script maps aspect ratios to these internally. |
| Size rejected (gpt-image-2) |
Dimension not a multiple of 16, or > 3840px |
The script rounds to /16 and caps at 3840; pass a smaller size. |
| Anchor reference ignored |
/text-to-image variant doesn't accept refs |
Pass --ref-image to force the /edit variant. |
| Skin / face looks "AI-stock" |
gpt-image's failure mode |
Add anti-AI cues to the prompt: "natural skin texture with pores, slight asymmetry, no perfect teeth". |
Cross-provider parity note
When this atom generates a character anchor (lock-character Phase 0), the anchor approved here MUST be pinned for all downstream angle gens, and the same --model must be used for those angle gens. Mixing model families (or mixing FAL-gpt-image with Higgsfield-gpt_image_2) introduces aesthetic drift. The orchestrator's generate_with_fallback.py inherits gateway/model_family from the anchor's .meta.json for subsequent calls.
References
- fal.ai/models/fal-ai/gpt-image-1
- fal.ai/models/openai/gpt-image-2
- Sibling Higgsfield path:
mcp__higgsfield__generate_image with model="gpt_image_2"
- Shared helpers:
scripts/fal_helpers.py (vendored alongside generate.py — self-contained)
- Storyboard-sheet consumer:
create-storyboard-sheets-fal (video flow, in the separate ads-video repo)
1---2name: create-image-gpt-image-fal3description: Generate a single photoreal or designed image with OpenAI gpt-image via fal.ai. Supports gpt-image-1 (default, fixed sizes — the FAL fallback for Higgsfield's `gpt_image_2`) and gpt-image-2 (`openai/gpt-image-2`, custom output sizes up to 3840px). Routes to text-to-image or the edit variant depending on whether a reference image is provided. Use for photoreal character anchors, scene keyframes, and designed sheets (e.g. storyboards) where precise layout and legible text matter.4---5
6# create-image-gpt-image-fal
7
8## Purpose
9
10Generate one image via fal.ai's OpenAI gpt-image endpoints. Two model families are supported through a single `--model` flag:
11
12- **`gpt-image-1`** (default) — `fal-ai/gpt-image-1`. The FAL fallback for Higgsfield's `gpt_image_2`. Fixed output sizes only. Used by:
13 - `video-orchestrator/lock-character` Phase 0 (anchor portrait) and Phase 1 (angle keyframes via `/edit`)
14 - `video-orchestrator/create-clips` Phase 1 for photoreal scenes
15 - the orchestrator's `generate_with_fallback.py` router on Higgsfield failure
16- **`gpt-image-2`** — `openai/gpt-image-2`. The newer model; accepts **custom output sizes** (any multiple of 16, up to 3840px) and renders dense text/layouts well. Used for designed sheets such as ad storyboards (`create-storyboard-sheets-fal`).
17
18The default stays `gpt-image-1` so existing callers and the lock-character anchor-parity contract are unaffected. Opt into the newer model with `--model gpt-image-2`.
19
20## Pricing (approximate, as of 2026-05)
21
22- **gpt-image-1** — $0.04 (low), $0.08 (medium), $0.20 (high) per image. Source: [fal.ai/models/fal-ai/gpt-image-1](https://fal.ai/models/fal-ai/gpt-image-1).
23- **gpt-image-2** — token-priced; rough per-image estimate $0.02 (low), $0.07 (medium), $0.19 (high). Source: [fal.ai/models/openai/gpt-image-2](https://fal.ai/models/openai/gpt-image-2).
24
25The script defaults to `medium`; pass `--quality high` for finals.
26
27## Inputs
28
29Required:
30- `--prompt` — text prompt. A verbatim character descriptor block goes here for character work.
31- `--output` — local PNG destination.
32
33Optional:
34- `--model` — `gpt-image-1` (default) or `gpt-image-2`.
35- `--aspect-ratio` — `9:16` (default), `16:9`, `1:1`, `2:3`, `3:2`. gpt-image-2 also accepts `3:4`, `4:3`, `4:5`. Used when `--image-size` is not given.
36- `--image-size` — explicit `WIDTHxHEIGHT` (e.g. `1728x2304`). **gpt-image-2 only** — values are rounded to multiples of 16 and capped at 3840px. On `gpt-image-1` a custom size is ignored with a warning and the aspect-ratio mapping is used instead.
37- `--quality` — `low | medium | high` (default `medium`).
38- `--ref-image` — local image path. **Repeatable** — pass `--ref-image PATH --ref-image PATH` to send multiple refs (e.g. identity + style). When present, routes to the model's `/edit` variant so the model can match the references (used for character angle gens off an anchor, and for style-anchor + identity-anchor composition). Order matters: pass identity (character) first, then style refs.
39- `--with-logs` — stream fal queue logs.
40
41Credentials:
42- `FAL_API_KEY` (or `FAL_KEY`) in `.env`.
43
44## Preflight
45
46```bash
47test -n "$FAL_API_KEY" || test -n "$FAL_KEY" || { echo "Missing FAL_API_KEY / FAL_KEY in .env"; exit 1; }
48python3 -c "import fal_client" || pip3 install fal_client
49```
50
51## Workflow
52
53```bash
54# Text-to-image, default model (gpt-image-1)
55python3 skills/ads/capabilities/create-image-gpt-image-fal/scripts/generate.py \
56 --prompt "..." \
57 --output /path/to/anchor.png \
58 --aspect-ratio 9:16 \
59 --quality medium
60
61# Edit-from-reference (anchor -> angle), default model
62python3 .../generate.py \
63 --prompt "..." \
64 --output /path/to/angle-3q-left.png \
65 --ref-image /path/to/anchor.png \
66 --aspect-ratio 9:16
67
68# gpt-image-2 with a custom output size (e.g. a designed storyboard sheet)
69python3 .../generate.py \
70 --prompt "..." \
71 --output /path/to/storyboard.png \
72 --model gpt-image-2 \
73 --image-size 1728x2304 \
74 --quality high
75```
76
77The script:
781. Loads the FAL key via `fal_helpers.load_fal_key()`.
792. Resolves the model family (`--model`) and output size (`--image-size` if given and supported, else the aspect-ratio mapping).
803. If one or more `--ref-image` flags are set, uploads each to fal storage and routes to the model's `/edit` variant with `image_urls=[url1, url2, ...]`. Otherwise routes to the `/text-to-image` variant.
814. Calls `fal_client.subscribe(model, payload)` via `fal_helpers.subscribe`.
825. Downloads the first result image to `--output`.
836. Writes `<output>.meta.json` with gateway, model id, `model_family`, request, and cost.
84
85## Output
86
87- `<output_path>` — PNG (≥ 1 KB).
88- `<output_path>.meta.json` — request + result metadata + cost, including `model_family` (`gpt-image-1` or `gpt-image-2`).
89
90## Quality Checks
91
92- Output file exists and is > 1 KB.
93- For character anchors: visually inspect against the descriptor block (hair, shirt color, age).
94- `meta.json` includes `gateway: "fal"`, the resolved `model` id, `model_family`, `image_size`, and `quality`.
95- For gpt-image-2 custom sizes: confirm the output dimensions match the requested `WIDTHxHEIGHT`.
96- **No readable text in the prompt that should appear in the image.** AI image models mangle short brand text, URLs, code tokens, captions, and wordmarks even with explicit prompting. Examples observed: `"ffmpeg"` → `"ffmmg"`; `"klarify"` → `"clarify"`; `"therapists"` → `"therapits"`. Use PIL or `ffmpeg drawtext` for any overlay containing readable text. Reserve image gen for purely visual content (characters, scenes, backgrounds). Repeats LEARNINGS L4.
97
98## Failure Modes
99
100| Symptom | Likely cause | Fix |
101|---|---|---|
102| `401 Unauthorized` | Bad FAL key | Verify `FAL_API_KEY` / `FAL_KEY` in `.env`. |
103| `429 Too Many Requests` | RPS limit | Drop concurrency to 2-3. |
104| Custom size ignored | `--image-size` passed with `--model gpt-image-1` | gpt-image-1 only supports fixed sizes; use `--model gpt-image-2` for custom sizes. |
105| Aspect-ratio drift (gpt-image-1) | gpt-image-1 only supports 1024x1024, 1024x1536, 1536x1024 | The script maps aspect ratios to these internally. |
106| Size rejected (gpt-image-2) | Dimension not a multiple of 16, or > 3840px | The script rounds to /16 and caps at 3840; pass a smaller size. |
107| Anchor reference ignored | `/text-to-image` variant doesn't accept refs | Pass `--ref-image` to force the `/edit` variant. |
108| Skin / face looks "AI-stock" | gpt-image's failure mode | Add anti-AI cues to the prompt: "natural skin texture with pores, slight asymmetry, no perfect teeth". |
109
110## Cross-provider parity note
111
112When this atom generates a character anchor (lock-character Phase 0), the anchor approved here MUST be pinned for all downstream angle gens, and the **same `--model`** must be used for those angle gens. Mixing model families (or mixing FAL-gpt-image with Higgsfield-gpt_image_2) introduces aesthetic drift. The orchestrator's `generate_with_fallback.py` inherits `gateway`/`model_family` from the anchor's `.meta.json` for subsequent calls.
113
114## References
115
116- [fal.ai/models/fal-ai/gpt-image-1](https://fal.ai/models/fal-ai/gpt-image-1)
117- [fal.ai/models/openai/gpt-image-2](https://fal.ai/models/openai/gpt-image-2)
118- Sibling Higgsfield path: `mcp__higgsfield__generate_image` with `model="gpt_image_2"`
119- Shared helpers: `scripts/fal_helpers.py` (vendored alongside generate.py — self-contained)
120- Storyboard-sheet consumer: `create-storyboard-sheets-fal` (video flow, in the separate ads-video repo)