I’m encountering a blocking issue while trying to generate an image using the OpenAI Python SDK.
Here is the relevant part of my code:
import os
# Initialize client with API key stored in environment variable
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
# Image generation request
generation_response = client.images.generate(
model="dall-e-3",
prompt="A cyberpunk monkey dreaming of a beautiful bunch of bananas, digital art",
n=1,
size="1024x1024",
response_format="url",
)
I do not know if that is the case, but for image/edits endpoint I had the same error for dall-e-2. For gpt-image-1 using SDK from openAI
client.images.(...)
worked fine, unlike dall-e-2. Switching to use requests library in python and use requests.post(…) resolved the problem with dall-e-2. But I used only image.edit
This error message indicates that the extreme, ridiculous (as in subject to my ridicule) moderations blocked the image.
'type': 'image_generation_user_error'
However, I tried a few times, and didn’t get an error. It may have to do with org-specific allowances, or what the prompt rewriter actually changed your prompt into, if it used blocked keywords or similar (you don’t see the rewriting upon failure - an API shortcoming).
(note - you don’t need to include os.environ.get(), as the API library does that for you automatically with the default environment variable)
Have a procedural incremental script that guards against bad parameters being sent, that was successful for my organization with these options. It will save locally to a subdirectory whether you use the boolean download_by_url to get URL or base64. (also a popup preview of the created image)
'''
DALL-E image generation example for openai>1.8.4, saves requested images as files
'''
## START - global user input data
prompt = (
"""
A cyberpunk monkey dreaming of a beautiful bunch of bananas, digital art
""".strip()
)
model_choice = "dall-e-3"
size_choice = 1 # !! see size table
dalle_3_hd = False # quality at 2x the price, defaults to "standard"
dalle_3_natural = False # defaults to "vivid", natural is poor
image1_quality = "medium" # high, medium, or low
download_by_url = True # retrieval method; False = get base64 in response
save_directory = "./images"
log_directory = "./logs" # json of call and response per image
## END - user input data
from io import BytesIO
from datetime import datetime, timezone # for formatting date returned with images
from importlib.metadata import version, PackageNotFoundError # check w/o import
# other imports lazy-loaded as needed
def is_old_package(version, minimum):
version_parts = list(map(int, version.split(".")))
minimum_parts = list(map(int, minimum.split(".")))
return version_parts < minimum_parts
try:
openai_version = version("openai")
except PackageNotFoundError:
raise RuntimeError("The ‘openai’ package is not installed or found. "
"You should run 'pip install --upgrade openai")
if is_old_package(openai_version, "1.8.4"): # the only package needing version check
raise ValueError(f"Error: OpenAI version {openai.__version__}"
" is less than the minimum version 1.8.4\n\n"
">>You should run 'pip install --upgrade openai')")
else:
from openai import OpenAI, RateLimitError, BadRequestError
from openai import APIConnectionError, APIStatusError
sizes = {
"dall-e-2": {1:"256x256", 2: "512x512", 3: "1024x1024"},
"dall-e-3": {1:"1024x1024", 2: "1792x1024", 3: "1024x1792"},
"gpt-image-1": {1:"1024x1024", 2: "1536x1024", 3: "1024x1536"},
}
api_params = {
"model": model_choice, # Defaults to dall-e-2
"size": sizes[model_choice][size_choice],
"prompt": prompt, # DALL-E 3: max 4000 characters, DALL-E 2: max 1000
"n": 1, # Between 2 and 10 is only for DALL-E 2
"user": "myname", # pass a customer ID for safety tracking
}
if model_choice == "gpt-image-1":
api_params.update({
"quality": image1_quality,
"moderation": "low", # or None = stupidly strict
"background": "opaque", # transparent, opaque or auto
"output_format": "png", # or jpg, webp
})
if api_params["output_format"] in ["jpg", "webp"]:
api_params["output_compression"] = "99" # only jpg, webp
if download_by_url:
print("warn: gpt-image-1 can't download via URLs; using base64")
# gpt-image-1 always returns base64; remove untolerated `response_format` key
api_params.pop("response_format", None)
else: # if dall-e
if download_by_url:
api_params["response_format"] = "url"
else:
api_params["response_format"] = "b64_json"
if model_choice == "dall-e-3" and dalle_3_hd:
api_params["quality"] = "hd"
if model_choice == "dall-e-3" and dalle_3_natural:
api_params["style"] = "natural"
def prepare_path(path_str):
"""
Ensure the provided path exists and is writable.
Creates the directory if it doesn't exist. Tests writability by
creating and deleting a temporary file. Returns a pathlib.Path.
"""
from pathlib import Path
path = Path(path_str)
# If path is relative, treat as subdirectory of cwd
if not path.is_absolute():
path = Path.cwd() / path
# Create the directory if it doesn't exist
if not path.exists():
path.mkdir(parents=True, exist_ok=True)
elif not path.is_dir():
raise ValueError(f"'{path}' exists and is not a directory")
# Test writability by writing and deleting a temp file
test_file = path / ".write_test"
try:
with open(test_file, "w") as f:
f.write("") # empty write
test_file.unlink()
except Exception as e:
raise PermissionError(f"Cannot write to directory '{path}': {e}")
return path
# ensure files can be written before calling
files_path = prepare_path(save_directory)
logs_path = prepare_path(log_directory)
# here's the actual request to API and lots of error-catching
client = OpenAI(timeout=150) # will use environment variable "OPENAI_API_KEY"
try:
from time import time
start = time()
images_response = client.images.generate(**api_params)
except APIConnectionError as e:
print("Server connection error: {e.__cause__}") # passed from httpx
raise
except RateLimitError as e:
print(f"OpenAI RATE LIMIT error {e.status_code}: (e.response)")
raise
except APIStatusError as e:
print(f"OpenAI STATUS error {e.status_code}: (e.response)")
raise
except BadRequestError as e:
print(f"OpenAI BAD REQUEST error {e.status_code}: (e.response)")
raise
except Exception as e:
print(f"An unexpected error occurred: {e}")
raise
# Print the elapsed time of the API call
print(f"Elapsed time: {time()-start:.1f}")
# get the prompt used if rewritten by dall-e-3, null if unchanged by AI
revised_prompt = images_response.data[0].revised_prompt
print(f"Revised Prompt:", revised_prompt)
# get out all the images in API return, whether url or base64
# note images_response being pydantic "model.data" and its model_dump() method
image_url_list = []
image_data_list = []
for image in images_response.data:
image_url_list.append(image.model_dump()["url"])
image_data_list.append(image.model_dump()["b64_json"])
# Prepare a list of image file bytes from either URLs or base64 data
image_file_bytes = []
# Download or decode images and append to image_objects (no saving yet)
if image_url_list and all(image_url_list):
import requests # for downloading images from URLs
for url in image_url_list:
while True:
try:
print(f"getting URL: {url}")
response = requests.get(url)
response.raise_for_status() # Raises stored HTTPError, if one occurred.
except requests.HTTPError as e:
print(f"Failed to download image from {url}. Error: {e.response.status_code}")
retry = input("Retry? (y/n): ") # ask script user if image url is bad
if retry.lower() in ["n", "no"]:
raise
else:
continue
break
image_file_bytes.append(response.content)
elif image_data_list and all(image_data_list): # if there is b64 data
import base64 # for decoding images if received in the reply
for data in image_data_list:
image_file_bytes.append(base64.b64decode(data))
else:
raise ValueError("No image data was obtained. Maybe bad code?")
# After obtaining all image objects, produce filenames and save files
def prompt_to_filename(s,max_length=30):
'''make prompt text safe for use within file names'''
import unicodedata,re
t=unicodedata.normalize('NFKD',s).encode('ascii','ignore').decode('ascii')
t=re.sub(r'[^A-Za-z0-9._\- ]+','_',t)
t=re.sub(r'_+','_',t).strip(' .')
if len(t)>max_length: t=t[:max_length].rstrip(' .')
if not t: return 'prompt'
r={'CON','PRN','AUX','NUL','COM1','COM2','COM3','COM4','COM5',
'COM6','COM7','COM8','COM9','LPT1','LPT2','LPT3','LPT4',
'LPT5','LPT6','LPT7','LPT8','LPT9'}
if t.upper().split('.')[0] in r: t='_'+t
return t
# make an auto file name; "created" in response is UNIX epoch time
filename_base = api_params["model"]
epoch_time_int = images_response.created
my_datetime = datetime.fromtimestamp(epoch_time_int, timezone.utc)
if globals().get('i_want_local_time') or True:
my_datetime = my_datetime.astimezone()
file_datetime = my_datetime.strftime('%Y%m%d-%H%M%S')
short_prompt = prompt_to_filename(prompt)
img_filebase = f"{filename_base}-{file_datetime}-{short_prompt}"
extension = "png" # or api_params["output_format"] only accepted with gpt-image-1 model
# Initialize an empty list to store the Image objects
image_objects = []
from PIL import Image
for i, img_bytes in enumerate(image_file_bytes):
img = Image.open(BytesIO(img_bytes))
image_objects.append({"file":img, "filename": f"{img_filebase}-{i}.{extension}"})
# build a Path to the output file
out_file = files_path / f"{img_filebase}-{i}.{extension}"
img.save(out_file)
print(f"{out_file} was saved")
# Log the request body parameters and the full response object to a file
log_obj = {"req": api_params, "resp": images_response.model_dump()}
log_filename = logs_path / f"{img_filebase}.json"
# Write the log_obj as JSON to the log file
import json
with open(log_filename, "w", encoding="utf-8") as log_f:
json.dump(log_obj, log_f, indent=0)
## -- extra fun: pop up some thumbnails in a GUI if you want to see what was saved
from PIL import Image # pillow, for processing image types
import tkinter as tk # for GUI thumbnails of what we got
from PIL import ImageTk # for GUI thumbnails of what we got
def resize_to_max(img, max_w, max_h):
"""
Return a resized copy of `img` so that neither width nor height
exceeds (max_w, max_h), preserving aspect ratio.
"""
w, h = img.size
scale = min(max_w / w, max_h / h)
new_w = int(w * scale)
new_h = int(h * scale)
return img.resize((new_w, new_h), Image.LANCZOS)
if image_objects:
for i, img_dict in enumerate(image_objects):
img = img_dict["file"]
filename = img_dict["filename"]
# Resize image for pop-up
if img.width > 768 or img.height > 768:
img = resize_to_max(img, 768, 768)
window = tk.Tk()
window.title(filename)
tk_image = ImageTk.PhotoImage(img)
label = tk.Label(window, image=tk_image)
label.image = tk_image # keep a reference so it isn’t garbage-collected
label.pack()
window.mainloop()