Image input for image variation with api.openai.com/v1/images/variations

Hello people. I’m trying to use the image variations API but I don’t know how the image should be. Currently I have a base64 string as image and it’s not working and giving me the error 415 “Unsupported Media Type”.

I triple checked that the image is square, PNG and less than 4MB.
I tried by making first a RGB image and sending those bytes but it gave me the error 500. I did that by replacing the payload to { image : image} in the code below.

Hopefully somebody has an idea.

import os
import json
import boto3
import urllib.request
import urllib.parse
from PIL import Image
import base64

import io

def base64_to_rgb_image(base64_string):
    # Decode the base64 string
    image_data = base64.b64decode(base64_string)
    # Create a BytesIO object to work with PIL
    image_buffer = io.BytesIO(image_data)
    # Open the image using PIL
    image = Image.open(image_buffer)
    # Convert the image to RGB mode
    image = image.convert("RGB")
    return image

def lambda_handler(event, context):
    api_key = os.environ['YOUR_API_KEY']
    try:
        # Parse the incoming HTTP request
        request_body = json.loads(event["body"])
        image_base64 = request_body["image"]
        print(f"Got image ")
        # Convert base64 images to RGB mode
        print("Will covert to RGB...")
        image = base64_to_rgb_image(image_base64)
        print("Coverted to RGB...")

        # Create a request payload for OpenAI's image editing API
        payload = {
            "image": image_base64,
        }

        # Encode the payload as JSON
        payload_data = json.dumps(payload).encode('utf-8')

        # Create a request object with the appropriate headers
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        }

        request = urllib.request.Request(
            url="https://api.openai.com/v1/images/variations",
            data=payload_data,
            headers=headers,
            method="POST"
        )
        
        print("Making request to OpenAI...")

        # Make the POST request using urllib and handle exceptions
        try:
            with urllib.request.urlopen(request) as response:
                response_data = response.read()
                response_code = response.getcode()
                parsed_response = json.loads(response_data)
                print(f"Received response: {parsed_response}")
        except Exception as request_error:
            print(f"Error making the request: {str(request_error)}")
            raise request_error

        if response_code == 200:
            result = json.loads(response_data.decode('utf-8'))
            # Extract the generated image URL from the result
            generated_image_url = result.get("url", "")
            return {
                "statusCode": 200,
                "body": json.dumps({"generated_image_url": generated_image_url}),
            }
        else:
            return {
                "statusCode": response_code,
                "body": response_data.decode('utf-8'),
            }
    except Exception as e:
        return {
            "statusCode": 500,
            "body": str(e),
        }

Might try using the OpenAI library?

import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
openai.Image.create_variation(
  image=open("otter.png", "rb"),
  n=2,
  size="1024x1024"
)

The images endpoint can be tricky / picky …

Here’s what GPT-4 recommends…

Given the documentation you provided, it seems you’re trying to use OpenAI’s Python client to interact with the Image Variations API. You seem to have used urllib to make a POST request manually in your original code. However, if you decide to use OpenAI’s Python client, it should simplify the process.

Let’s create a more concise version using the OpenAI Python client:

import os
import openai
from PIL import Image
import base64
import io

def base64_to_rgb_image(base64_string):
    # Decode the base64 string
    image_data = base64.b64decode(base64_string)
    # Create a BytesIO object to work with PIL
    image_buffer = io.BytesIO(image_data)
    # Open the image using PIL
    image = Image.open(image_buffer)
    # Convert the image to RGB mode
    image = image.convert("RGB")
    return image

def create_image_variation(image_base64):
    # Convert the base64 string to an RGB image
    image = base64_to_rgb_image(image_base64)
    
    # Save the image to a temporary file
    image.save('temp_image.png', 'PNG')
    
    # Set the API key
    openai.api_key = os.getenv("YOUR_API_KEY")

    # Use the OpenAI Python client to create image variations
    response = openai.Image.create_variation(
        image=open("temp_image.png", "rb"),
        n=2,  # number of images to generate
        size="1024x1024"  # size of the generated images
    )
    
    # Optional: Remove the temporary file
    os.remove('temp_image.png')
    
    return response.data  # This will be a list of image objects with URLs

def lambda_handler(event, context):
    try:
        request_body = json.loads(event["body"])
        image_base64 = request_body["image"]
        
        generated_images = create_image_variation(image_base64)
        
        return {
            "statusCode": 200,
            "body": json.dumps({"generated_images": generated_images}),
        }

    except Exception as e:
        return {
            "statusCode": 500,
            "body": str(e),
        }

This code does the following:

  1. It decodes the base64 image string you provide into an RGB image using the base64_to_rgb_image function.
  2. It saves this RGB image to a temporary file named temp_image.png.
  3. Using the OpenAI Python client, it then sends this image file to OpenAI’s Image Variations API to generate variations of the image.
  4. It finally returns the generated image URLs as a response.

Note: Make sure to install the required libraries (openai and PIL) in your lambda environment.

2 Likes

Thank you, I will try that. First I’ll need to install the openai library in my lambda function, that’s where this code is running.

1 Like

No problem. You could also peek at the OpenAI library code to see how they’re doing it then just replicate in your function. Good luck. Let us know how it goes.

Now it’s working perfectly. The code had a couple of issues, but here it is corrected.

import os
import openai
from PIL import Image
import base64
import io
import json 

def base64_to_rgb_image(base64_string):
    # Decode the base64 string
    image_data = base64.b64decode(base64_string)
    # Create a BytesIO object to work with PIL
    image_buffer = io.BytesIO(image_data)
    # Open the image using PIL
    image = Image.open(image_buffer)
    # Convert the image to RGB mode
    image = image.convert("RGB")
    return image

def create_image_variation(image_base64):
    # Convert the base64 string to an RGB image
    image = base64_to_rgb_image(image_base64)
    
    # Save the image to a temporary file in the /tmp directory
    temp_file_path = '/tmp/temp_image.png'
    image.save(temp_file_path, 'PNG')
    
    # Set the API key
    openai.api_key = os.getenv("YOUR_API_KEY")

    # Use the OpenAI Python client to create image variations
    try:
        with open(temp_file_path, "rb") as image_file:
            response = openai.Image.create_variation(
                image=image_file,
                n=1,  # number of images to generate
                size="1024x1024"  # size of the generated images
            )
    finally:
        # Optional: Remove the temporary file
        os.remove(temp_file_path)
    
    return response.data  # This will be a list of image objects with URLs


def lambda_handler(event, context):
    try:
        request_body = json.loads(event["body"])
        image_base64 = request_body["image"]
        
        generated_images = create_image_variation(image_base64)
        
        return {
            "statusCode": 200,
            "body": json.dumps({"generated_images": generated_images}),
        }

    except Exception as e:
        return {
            "statusCode": 500,
            "body": str(e),
        }

Thank you very much