Build a Photo-to-Ghibli CLI Tool
Transform any photo into Studio Ghibli art using OpenAI's Image Edit API.
Introduction
30 Second Summary
Everyone has seen those viral Ghibli-style photos floating around social media. What if you could create your own from any photo on your Mac, with a single terminal command?
In this project, you will build a Python CLI tool that transforms any photo into animated art using OpenAI's Image Edit API. Point it at a selfie, landscape, or pet photo and get back a hand-painted anime-style version in seconds.
What You'll Build
Run a single command in your terminal, and within seconds your photo pops open in Preview as a beautiful Studio Ghibli-style illustration that still looks like the original subject.
By the end of this project, you'll have:
- A working CLI tool that transforms any photo into Ghibli-style animated art with one terminal command, auto-opening the result in macOS Preview.
- Multiple animation style presets (Ghibli, Pixar, Comic Book, Watercolor) selectable with a simple flag so you can experiment with different looks.
- Full control over output quality and size through CLI options, letting you balance visual detail against API cost.
- Secret Mission: A comparison mode that stitches the original and animated images side-by-side into a single shareable image.
Are there any prerequisites?
You need Python 3 installed on your Mac, an OpenAI API key with image generation access, and basic familiarity with running commands in Terminal. Step 1 walks you through installing the OpenAI SDK and configuring your key.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters to you.
Taking a moment to articulate your goal turns a follow-along tutorial into a project you own.
Set Up Your Environment
You know what you're building. Now let's get your Mac ready to actually build it.
Your CLI tool needs three things before it can talk to OpenAI's image API: the Python SDK that handles communication, an API key that proves your identity, and a project folder to hold your script.
In this step, get ready to:
- Install the OpenAI Python SDK.
- Configure your OpenAI API key as an environment variable.
- Create the project directory and verify everything works together.
Install the OpenAI Python SDK
The OpenAI Python SDK is a library that lets your Python scripts communicate with OpenAI's APIs. You need version 2.51.0 or later, which includes support for the Image Edit API and the gpt-image-1 model.
- Install the SDK by running this command in Terminal:
pip install --upgrade openai
You should see pip downloading and installing packages. Once it finishes, you'll see a success message.
- Confirm the installed version by running:
pip show openai
Look for the Version field in the output. It should show 2.51.0 or higher.
Seeing 'command not found' for pip?
Your system might use pip3 instead of pip. Try running pip3 install --upgrade openai instead.
If neither works, confirm Python 3 is installed by running python3 --version. You should see a version number like 3.11 or higher.
Help me fix my pip installation
Configure your API key as an environment variable
The OpenAI SDK looks for an environment variable called OPENAI_API_KEY to authenticate every API call. Setting it in your ~/.zshrc file means it loads automatically every time you open Terminal.
- Add your API key to ~/.zshrc by running this command (replace your-api-key-here with your actual OpenAI API key before pressing Enter):
echo 'export OPENAI_API_KEY="your-api-key-here"' >> ~/.zshrc
Where do I find my OpenAI API key?
Go to platform.openai.com/api-keys and sign in. Click Create new secret key, give it a name, and copy the key immediately. You only see it once.
- Load the updated ~/.zshrc into your current Terminal session by running:
source ~/.zshrc
- Verify the key is set by running:
echo $OPENAI_API_KEY
You should see your API key printed in the terminal output.
Seeing a blank line instead of your key?
Check that the echo command you ran earlier used >> (double arrow) not > (single arrow). A single arrow overwrites the file instead of appending.
Open ~/.zshrc in a text editor with open -e ~/.zshrc and confirm the export OPENAI_API_KEY= line is there with your key. Save, then run source ~/.zshrc again.
Help me debug my OPENAI_API_KEY setup
Create the project directory and verify the SDK imports
Everything is installed and authenticated. Now you need a folder to hold your script, and a quick check that Python can actually find the OpenAI SDK.
- Create the project folder and move into it by running:
mkdir ~/ghiblify && cd ~/ghiblify
- Confirm you're inside the new folder by running:
pwd
You should see /Users/yourname/ghiblify printed (with your Mac username in place of yourname).
Before you run the final check, what do you expect this command to print if everything is set up correctly?
- Verify the SDK imports correctly by running:
python3 -c "from openai import OpenAI; print('ready')"
You should see ready printed with no errors. This confirms Python can find the OpenAI SDK and import it successfully.
Seeing 'ModuleNotFoundError: No module named openai'?
This means pip installed the package for a different Python version than python3 is using. Fix it by running python3 -m pip install --upgrade openai to install specifically for the Python that python3 points to.
Help me fix my OpenAI module import error
Your environment is locked and loaded. Next up, you'll send your first photo to the Image Edit API and see it come back in Ghibli style.
Build Your First Transformation
Your environment is locked and loaded. The SDK is installed, your API key is configured, and Python can import OpenAI without errors.
Now for the fun part. You are going to send an actual photo to OpenAI's Image Edit API and get back a Studio Ghibli-style animated version of it. This step proves the core concept works before adding any polish.
In this step, get ready to:
- Save a test photo into your project folder.
- Write a Python script that sends the photo to the Image Edit API and saves the animated result.
- Run the script and see the Ghibli-style image pop open in Preview.
Save a test photo to your project folder
The script needs an input image to transform. Any photo works. A selfie, a pet photo, or a landscape all produce interesting results.
- Find a photo on your Mac (or take one with Photo Booth) and copy it into your ~/ghiblify/ folder.
- Rename it to something simple like photo.jpg so it is easy to type in Terminal.
- Confirm the photo is in place by running:
ls ~/ghiblify/
You should see your photo file (e.g. photo.jpg) listed in the output.
Don't see your photo?
Make sure you copied the file into ~/ghiblify/ and not a subfolder. Check the filename has no spaces. If it does, rename it to something without spaces.
help me find where my photo ended up
Create the transformation script
This script does four things: reads the photo, sends it to the API with a Ghibli-style prompt, decodes the response, and opens the result. You will build it in two chunks.
- Create a new file called ghiblify.py in your ~/ghiblify/ folder and add the following code:
import argparse
import base64
import subprocess
import sys
from pathlib import Path
from openai import OpenAI
# Create the OpenAI client (uses OPENAI_API_KEY from environment)
client = OpenAI()
# Read the image path from the command line argument
image_path = Path(sys.argv[1])
# Generate the output filename by appending _ghibli
output_path = image_path.parent / f"{image_path.stem}_ghibli.png"
# The prompt tells the model what style to apply
prompt = (
"Transform this photo into Studio Ghibli anime style art. "
"Apply soft hand-painted textures, warm lighting, and the gentle "
"color palette characteristic of Studio Ghibli films."
)
What does this code do?
- OpenAI() creates a client that automatically reads your OPENAI_API_KEY environment variable for authentication.
- Path(sys.argv[1]) grabs the filename you pass when running the script (e.g. photo.jpg).
- The output path takes your input filename and appends _ghibli.png so photo.jpg becomes photo_ghibli.png.
- The prompt is the creative instruction that tells the model how to restyle your photo.
- Add the following code directly below the prompt in the same file:
print(f"Transforming: {image_path.name}")
print("Sending to OpenAI API...")
# Send the image to OpenAI's Image Edit API
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
)
# Decode the base64 response into image bytes
image_base64 = result.data[0].b64_json
image_bytes = base64.b64decode(image_base64)
# Save the result and open in macOS Preview
output_path.write_bytes(image_bytes)
print(f"Saved to: {output_path}")
subprocess.run(["open", str(output_path)])
What does this code do?
- client.images.edit() sends your photo to the gpt-image-1 model along with the style prompt. The model returns a transformed version.
- The response comes back as a base64-encoded string. You decode it into raw image bytes and write those bytes to a .png file.
- subprocess.run(["open", ...]) is the macOS way to open a file in its default app. For images, that is Preview.
- Save ghiblify.py.
✔️ Awesome, I've got everything!
Great. Double check you have saved the file before moving on.
ⓧ I'd like to double check the full code
Scroll up and confirm your ghiblify.py contains both chunks in this order:
- Chunk 1: Imports, client setup, path handling, and the prompt string.
- Chunk 2: Print statements, the client.images.edit() call, base64 decoding, file write, and the open command.
Make sure there are no extra blank lines between the chunks. The prompt block should flow directly into the print statements.
Run the transformation
Everything is in place. Your photo is in the folder and the script is saved. Time to see if it works.
- Before you run this, take a guess: what do you think will appear in Preview? Will it look exactly like your original photo, or something different?
- Run the transformation by executing this command:
cd ~/ghiblify && python3 ghiblify.py photo.jpg
The script prints progress messages while it waits for the API response. After a few seconds, a Ghibli-style version of your photo opens in Preview.
What should I see?
Preview opens with an animated, hand-painted version of your photo. The colors are warm and soft, and the textures look like watercolor brushstrokes.
Look closely at the subject though. If your photo was a selfie, the face may not look much like you. Features get reimagined rather than preserved. That is a limitation you will fix in the next step.
Seeing an API error?
- If you see a message about an invalid API key, run echo $OPENAI_API_KEY to confirm your key is loaded. If it prints nothing, run source ~/.zshrc and try again.
- If you see a file not found error, make sure your photo filename matches exactly what you typed in the command (including the extension).
- If Preview does not open, check that the output file was created by running ls ~/ghiblify/ and looking for a file ending in _ghibli.png.
help me debug my ghiblify.py script
You just turned a regular photo into Ghibli-style art with a single command. But you probably noticed the subject does not look much like the original. Next up, you will fix that likeness problem so the tool actually preserves who or what is in the photo.
Fix the Likeness Problem
Your script produces Ghibli-style art, but look at the output from the last step closely. The result probably doesn't look much like your actual subject. Faces get reimagined, details get changed, and you end up with "generic anime person" rather than an animated version of your real photo.
This happens because the input_fidelity parameter defaults to "low". The model treats your photo as loose inspiration instead of a faithful reference. In this step, you'll fix that so the tool becomes genuinely useful.
In this step, get ready to:
- Add input_fidelity="high" to preserve your subject's features.
- Update the prompt to explicitly instruct the model to maintain likeness.
- Increase output quality and size for more detail.
Add input_fidelity to preserve the subject
The input_fidelity parameter controls how much effort the model puts into matching the style and features of your input image. When it's set to "high", the model works harder to preserve facial features, clothing, and composition.
- In ghiblify.py, find the import argparse line at the very top of the file and delete it. This import isn't used yet.
- Now scroll down to the client.images.edit() call. Find this code:
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
)
- Add input_fidelity="high" as a new parameter so the call looks like this:
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
input_fidelity="high",
)
What does input_fidelity do?
When input_fidelity is "low" (the default), the model uses your photo as a loose creative reference. It might change face shapes, rearrange features, or reimagine the background.
Setting it to "high" tells the model to exert more effort matching the style and features of the input image, especially facial features. This is the single biggest lever for making the output actually look like your subject.
Update the prompt for explicit preservation
The input_fidelity parameter handles the technical side, but the prompt also matters. A vague prompt gives the model permission to reimagine. An explicit one locks down what must stay the same.
- In ghiblify.py, find the prompt variable. It currently looks like this:
prompt = (
"Transform this photo into Studio Ghibli anime style art. "
"Apply soft hand-painted textures, warm lighting, and the gentle "
"color palette characteristic of Studio Ghibli films."
)
- Replace the entire prompt variable with this updated version that explicitly instructs the model to preserve the subject:
prompt = (
"Transform this photo into Studio Ghibli anime style art. "
"Maintain the exact composition, pose, and all subject features "
"(face shape, hair style, clothing, background elements). "
"Apply soft hand-painted textures, warm lighting, and the gentle "
"color palette characteristic of Studio Ghibli films. "
"Keep it faithful to the original subject while making it look like "
"a frame from a Miyazaki film."
)
What does this prompt do differently?
The new prompt adds two critical instructions. First, it explicitly lists what must stay the same: composition, pose, face shape, hair style, clothing, and background. Second, it frames the task as "make it look like a frame from a Miyazaki film" rather than just "apply Ghibli style."
Naming specific features gives the model clear constraints. Without these, the model interprets "Ghibli style" as permission to redesign everything.
Before you run this, think about what you expect to see. Will the combination of input_fidelity="high" and the improved prompt produce a result that looks like you (or your subject)?
- Save ghiblify.py and run it with the same photo from the last step:
python3 ghiblify.py photo.jpg
Compare the new output with your previous result. The subject's face shape, hair, and clothing should now be recognizably preserved while still looking like Ghibli-style animation.
Still not looking like the subject?
Make sure you added input_fidelity="high" inside the client.images.edit() call, not outside it. Check for a comma after prompt=prompt, before the new parameter.
Also confirm your updated prompt is assigned to the same prompt variable that gets passed to the API call.
help me debug my ghiblify script - the output still doesn't look like the original subject
Increase output quality and resolution
The likeness should already be much better. Now you'll increase the output detail by adding quality and size parameters.
- In ghiblify.py, find the client.images.edit() call you just updated. It currently looks like this:
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
input_fidelity="high",
)
- Add quality="high" and size="1024x1024" so the call looks like this:
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
quality="high",
size="1024x1024",
input_fidelity="high",
)
What do quality and size control?
The quality="high" parameter increases the detail and fidelity of the generated image. The size="1024x1024" parameter sets a square output at 1024 pixels. Both give the model more room to render fine details like hair strands, fabric textures, and background elements.
What do you think the difference will be between this run and the previous one? The subject should already be recognizable. This change should improve the artistic detail and sharpness.
- Save ghiblify.py and run once more:
python3 ghiblify.py photo.jpg
The new output opens in Preview. You should see improved artistic quality with finer textures, crisper lines, and richer colors compared to your previous run. The subject's features remain preserved.
Seeing an API error?
Double check that quality="high" and size="1024x1024" are spelled exactly as shown, including the quotes. Make sure each parameter has a trailing comma.
If you see a billing or quota error, confirm your OpenAI account has available credits at platform.openai.com/usage.
help me fix an API error when running my ghiblify script with quality and size parameters
✔️ Awesome, I've got everything!
Great. Double check you've saved ghiblify.py with all three changes in place.
ⓧ I'd like to double check the full code
Scroll through your ghiblify.py and confirm these pieces are present in order:
- Imports: base64, subprocess, sys, Path, and OpenAI. No argparse import.
- The prompt variable with seven lines of text including "Maintain the exact composition, pose, and all subject features" and "Keep it faithful to the original subject."
- The client.images.edit() call with quality="high", size="1024x1024", and input_fidelity="high".
- The base64 decoding, file save, and subprocess.run(["open", ...]) at the bottom.
Your tool now transforms photos into genuine Ghibli-style art that actually looks like the original subject. Next up, you'll turn this script into a proper CLI with multiple animation styles and configurable options.
Build the Full CLI
Your tool works. Point it at a photo, and a Ghibli-style image pops open in Preview with genuine likeness preservation.
A hardcoded script is not a reusable tool, though. Right now you can only produce Ghibli-style output, you cannot control quality or size, and the output filename is fixed. In this step, you will turn the script into a proper CLI with multiple animation styles, configurable options, and error handling.
In this step, get ready to:
- Add a style presets dictionary with four animation styles (Ghibli, Pixar, Comic Book, Watercolor).
- Add argument parsing with style, quality, size, and output options.
- Add error handling and a run summary that prints after each transformation.
Create the style presets dictionary
Each animation style needs its own detailed prompt that instructs the model on the specific artistic characteristics to apply. You will store these in a dictionary at the top of the file so the CLI can look up the right prompt by name.
Since you are restructuring the file from a flat script into a proper CLI with functions, you will replace the entire contents of ghiblify.py with the new version.
- Open ghiblify.py in your editor, select all the existing code, and delete it.
- Paste the following imports and the first two style entries:
import argparse
import base64
import subprocess
import sys
from pathlib import Path
from openai import OpenAI
# Maps each style name to a detailed prompt for the API
STYLE_PROMPTS = {
"ghibli": (
"Transform this photo into Studio Ghibli anime style art. "
"Maintain the exact composition, pose, and all subject features "
"(face shape, hair style, clothing, background elements). "
"Apply soft hand-painted textures, warm lighting, and the gentle "
"color palette characteristic of Studio Ghibli films. "
"Keep it faithful to the original subject while making it look like "
"a frame from a Miyazaki film."
),
"pixar": (
"Transform this photo into Pixar 3D animation style. "
"Maintain the exact composition, pose, and all subject features "
"(face shape, hair style, clothing, background elements). "
"Apply smooth 3D rendering, slightly exaggerated proportions, "
"vibrant colors, and cinematic lighting characteristic of Pixar films. "
"Keep it faithful to the original subject."
),
What does this code do?
The imports add argparse (for CLI argument parsing) to the modules you already had.
STYLE_PROMPTS is a dictionary that maps a short style name like "ghibli" to the full prompt text the API needs. Each prompt tells the model to preserve the subject while applying the target art style.
- Directly below the pixar entry (on the next line after its closing parenthesis and comma), paste the remaining two styles:
"comic": (
"Transform this photo into bold comic book illustration style. "
"Maintain the exact composition, pose, and all subject features "
"(face shape, hair style, clothing, background elements). "
"Apply strong ink outlines, flat color fills, halftone shading, "
"and dramatic contrast characteristic of graphic novels. "
"Keep it faithful to the original subject."
),
"watercolor": (
"Transform this photo into delicate watercolor painting style. "
"Maintain the exact composition, pose, and all subject features "
"(face shape, hair style, clothing, background elements). "
"Apply soft wet-on-wet blending, visible brush strokes, gentle color "
"bleeding at edges, and the luminous transparency of watercolor paint. "
"Keep it faithful to the original subject."
),
}
What does this code do?
The comic style uses ink outlines and halftone shading for a graphic novel look. The watercolor style uses wet-on-wet blending and visible brush strokes for a painted look.
Every prompt shares the same structure: style instruction, then a preservation clause that locks in the subject's features. This is what keeps output faithful to the original photo regardless of style.
- Save ghiblify.py and confirm the dictionary is valid Python by running:
python3 -c "import importlib.util; spec = importlib.util.spec_from_file_location('g', 'ghiblify.py'); mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod); print(list(mod.STYLE_PROMPTS.keys()))"
You should see ['ghibli', 'pixar', 'comic', 'watercolor'] printed. This confirms all four styles are defined correctly.
Seeing a SyntaxError?
Check that each style entry ends with a closing parenthesis followed by a comma: ),. The dictionary's final closing brace } should appear on its own line after the watercolor entry.
Also confirm you have the opening STYLE_PROMPTS = { line before the ghibli entry.
help me fix a SyntaxError in my STYLE_PROMPTS dictionary
Add argument parsing and the main function
With the style data in place, you need two functions: one to define and parse CLI arguments, and one to orchestrate the transformation. Together they turn the script from a flat sequence into a tool that responds to flags like --style pixar or --help.
- Below the closing } of STYLE_PROMPTS, add the parse_args() function:
def parse_args():
parser = argparse.ArgumentParser(
description="Transform photos into animated art styles using OpenAI's Image Edit API."
)
# Positional argument: the input image file
parser.add_argument("image", type=str, help="Path to the input image file")
parser.add_argument(
"--style",
choices=["ghibli", "pixar", "comic", "watercolor"],
default="ghibli",
help="Animation style to apply (default: ghibli)",
)
parser.add_argument(
"--quality",
choices=["low", "medium", "high"],
default="high",
help="Output quality (default: high)",
)
parser.add_argument(
"--size",
choices=["1024x1024", "1536x1024", "1024x1536"],
default="1024x1024",
help="Output image size (default: 1024x1024)",
)
parser.add_argument("--output", type=str, help="Custom output file path")
parser.add_argument(
"--no-open",
action="store_true",
help="Do not auto-open the result in Preview",
)
return parser.parse_args()
What does this code do?
- image is a positional argument. The learner just types the filename after the script name.
- --style restricts input to the four defined styles. argparse rejects anything else automatically.
- --no-open uses action="store_true" so it defaults to False unless the flag is present.
- Below parse_args(), add the main() function with input validation, output path logic, and summary prints:
def main():
args = parse_args()
# Validate the input file exists and has a supported format
image_path = Path(args.image)
if not image_path.exists():
print(f"Error: File not found: {image_path}")
sys.exit(1)
if not image_path.suffix.lower() in (".png", ".jpg", ".jpeg", ".webp"):
print(f"Error: Unsupported image format: {image_path.suffix}")
print("Supported formats: .png, .jpg, .jpeg, .webp")
sys.exit(1)
# Determine output path from --output flag or auto-generate
if args.output:
output_path = Path(args.output)
else:
output_path = image_path.parent / f"{image_path.stem}_{args.style}.png"
prompt = STYLE_PROMPTS[args.style]
# Print a summary so the user knows what's happening
print(f"Transforming: {image_path.name}")
print(f"Style: {args.style}")
print(f"Quality: {args.quality} | Size: {args.size}")
print("Sending to OpenAI API...")
if __name__ == "__main__":
main()
What does this code do?
- The file-existence check exits early with a clear error message if the photo path is wrong.
- The format check ensures the API only receives supported image types (.png, .jpg, .jpeg, .webp).
- The output path auto-generates from the input filename plus the style name, so photo.jpg with --style pixar becomes photo_pixar.png.
- The if __name__ == "__main__" guard means the script only runs when executed directly, not when imported.
- Save ghiblify.py and test that argument parsing works by running:
python3 ghiblify.py --help
You should see a usage message listing all your options: image, --style, --quality, --size, --output, and --no-open.
- Now test the validation and summary output by running:
python3 ghiblify.py photo.jpg
You should see the summary lines print (Transforming, Style, Quality, Size, Sending to OpenAI API) and then the script exits. No image is generated yet because the API call is not wired up.
- Test the error handling by running with a non-existent file:
python3 ghiblify.py fake.jpg
You should see Error: File not found: fake.jpg and the script exits with no traceback.
Seeing a NameError or ImportError?
Make sure import argparse is at the top of the file. Check that parse_args() is defined before main() since main() calls it.
help me debug a NameError in my ghiblify.py CLI tool
Wire up the API call
The skeleton runs, parses arguments, and validates input. Now you need the part that actually calls the OpenAI API and saves the result.
- In ghiblify.py, find this line inside main():
print("Sending to OpenAI API...")
- Add the following code directly below that line (before the if __name__ block):
client = OpenAI()
try:
result = client.images.edit(
model="gpt-image-1",
image=open(image_path, "rb"),
prompt=prompt,
quality=args.quality,
size=args.size,
input_fidelity="high",
)
except Exception as e:
print(f"Error: API call failed: {e}")
sys.exit(1)
# Decode the base64 response and save as PNG
image_base64 = result.data[0].b64_json
image_bytes = base64.b64decode(image_base64)
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_bytes(image_bytes)
print(f"Saved to: {output_path}")
if not args.no_open:
subprocess.run(["open", str(output_path)])
What does this code do?
- The try/except block catches API failures (network issues, invalid keys, rate limits) and prints a readable error instead of a raw traceback.
- args.quality and args.size pass the CLI flags directly to the API call, so the learner controls cost and output dimensions from the command line.
- output_path.parent.mkdir(parents=True, exist_ok=True) creates any missing directories if the user passes a custom --output path.
- The --no-open check skips the open command when the flag is set, useful for batch processing.
- Save ghiblify.py.
Before you run this, what style do you expect to see in the output image?
- Test the full CLI with a different style by running:
python3 ghiblify.py photo.jpg --style pixar --quality medium
A Pixar-style image opens in Preview. The output has smooth 3D rendering and slightly exaggerated proportions while still preserving your subject's features.
Seeing "Error: API call failed"?
Check that your OPENAI_API_KEY is still loaded in this terminal session. Run echo $OPENAI_API_KEY to confirm it prints your key. If it is empty, run source ~/.zshrc to reload it.
If the error mentions rate limits, wait a minute and try again. The gpt-image-1 model has per-minute request limits.
help me fix an API call error in my ghiblify.py tool
- Confirm the help output shows all options by running:
python3 ghiblify.py --help
You should see usage information listing the positional image argument and all five optional flags.
✔️ Awesome, I've got everything!
Great. Double check that you have saved ghiblify.py and your Pixar-style image opened in Preview.
ⓧ I'd like to double check the full code
Your ghiblify.py is built from the following sections, in order. Scroll up and confirm each one is present:
- Imports (argparse, base64, subprocess, sys, Path, OpenAI).
- STYLE_PROMPTS dictionary with four entries: ghibli, pixar, comic, watercolor.
- parse_args() function defining the argument parser with 6 arguments.
- main() function with file validation, output path logic, summary prints, API call inside try/except, base64 decode, file save, and conditional open command.
- if __name__ == "__main__": main() at the very bottom.
Your single-purpose script is now a proper CLI tool with four styles, configurable quality, and friendly error messages. Next up, you will push it even further in the Secret Mission.
Secret mission
Add a Side-by-Side Comparison Mode
Your animated images look great, but sharing them requires people to compare two separate files. Add a --compare flag that stitches the original and animated images into a single side-by-side image, perfect for sharing on social media or sending to friends.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally and only costs money when you actively run the tool (approximately $0.05-0.15 per transformation).
Resources you used:
- ~/ghiblify project directory (contains ghiblify.py and generated images).
- OPENAI_API_KEY environment variable in ~/.zshrc.
- openai and Pillow Python packages installed via pip.
- OpenAI API usage (pay-per-use, no persistent cloud resources).
Keep everything running
No action needed. Choose this if you plan to keep transforming photos with your tool.
- Your ghiblify.py tool stays ready to use whenever you want to transform a photo.
- Monitor your OpenAI API spend at https://platform.openai.com/usage.
- Each run costs approximately $0.05-0.15 depending on your quality settings. You are only charged when you actively run the script.
Pause - I'll come back to this later
No action needed. The tool only costs money when you run it, so there is nothing to pause.
- Your ~/ghiblify folder stays on disk and takes up negligible space.
- Your OPENAI_API_KEY remains in ~/.zshrc ready for next time.
- No charges accrue while the tool is not running.
Delete - I don't want to use this again
Remove all project files and configuration to start fresh.
- Delete the project directory by running:
rm -rf ~/ghiblify
- Remove the API key from your shell configuration. Open ~/.zshrc in a text editor and delete the line that says export OPENAI_API_KEY="...". Then reload your shell by running:
source ~/.zshrc
- Uninstall the Python packages by running:
pip uninstall openai Pillow -y
- Your OpenAI account remains active. If you want to revoke your API key, visit the API keys page and delete the key you used for this project.
That's a Wrap!
That's a Wrap!
Nice work! You just built a fully functional CLI tool that transforms any photo into animated art using OpenAI's Image Edit API.
You've learned how to:
- Built a working Python CLI tool that sends photos to the Image Edit API and decodes base64 responses into saved image files.
- Used input_fidelity="high" to preserve subject likeness during style transfer, solving the problem of the model reimagining rather than faithfully transforming your photos.
- Created a multi-style tool with Ghibli, Pixar, Comic Book, and Watercolor presets controlled by argparse flags, with results auto-opening in macOS Preview.
- Secret Mission: Added a --compare mode that stitches the original and animated images side-by-side into a single shareable image using Pillow.
Ready to quiz yourself?