Friends of OpenJDK Today

Generate AI-based Images with Quarkus and OpenAI DALL.E

August 21, 2023

Author(s)

  • Avatar photo
    Antonio Perrone

    I'm a passionate and experienced Software Architect, from Milan, Italy. I've worked as a Software Engineer and Architect for almost ten years in consulting. Currently I'm working as a Manager ... Learn more

In this article, we explore how to integrate OpenAI API with Quarkus. We will create a Quarkus application using the new REST Client Reactive to invoke the OpenAI DALL.E API for images generation.

OpenAI API Overview

Before jumping into the code, let’s explore the OpenAI Create Image API and how it works.

Create Image Request

The body request is made of the following parameters:

  • prompt: the only required parameter is the description of the desired image (max 1000 characters)
  • n: number of desired images (from 1 to 10)
  • size: the size of a generated image (default 1024x1024, also admitted 256x256, 512x512)
    other parameters are:
  • response_format: to specify the response image format (default url, also admitted b64_json)
  • user: identifier to track user activities.

To authenticate with the API, we'll generate an API key. We'll set this key in the Authorization header while calling the API.
Here is a sample API request:

curl https://api.openai.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI\_API\_KEY" \
-d '{
   "prompt": "A cute baby sea otter",
   "n": 2,
   "size": "1024x1024"
}'

Create Image Response

The response will be a JSON object with created and data fields. The data field will be an array of objects. Each object will have a url field containing the response to the prompt.

The number of objects in the data array will equal the optional n parameter in the request. If the n parameter is not specified, the data array will contain a single object.
Here is a sample API response:

{
"created": 1589478378,
"data": [
   {
      "url": "https://..."
   },
   {
      "url": "https://..."
   }
]
}

Setting up the Quarkus Application

To startup our application, go to and configure it by selecting the following extensions:

  • RESTEasy Reactive Jackson
  • RESTEasy Reactive
  • REST Client Reactive
  • REST Client Reactive Jackson
    Or using maven with the following command:
mvn io.quarkus.platform:quarkus-maven-plugin:3.2.3.Final:create \
-DprojectGroupId=com.foojay.openai \
-DprojectArtifactId=quarkus-openai-app \
-Dextensions='resteasy-reactive-jackson,rest-client-reactive-jackson,resteasy-reactive' \
-DnoCode

After creating the project, add your OpenAI API Key with the following line inside the application.properties file.

# OpenAI properties 
openai.api.key=$OPENAI_API_KEY

The Model

Now starting from what we have seen before, we create a class to model the API request body of OpenAI Image Generation API:

public class CreateImageRequest {

    @JsonProperty("prompt")
    private String prompt;

    @JsonProperty("n")
    private int n;

    @JsonProperty("size")
    private String size;

    public CreateImageRequest() {
    }

    public String getPrompt() {
        return prompt;
    }

    public void setPrompt(String prompt) {
        this.prompt = prompt;
    }

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public String getSize() {
        return size;
    }

    public void setSize(String size) {
        this.size = size;
    }
}

Let's define the API response class:

public class CreateImageResponse {

    @JsonProperty("created")
    private Integer created;

    @JsonProperty("data")
    private List<Item> urls;

    public List<Item> getUrls() {
        return urls;
    }

    public void setUrls(List<Item> urls) {
        this.urls = urls;
    }

    public Integer getCreated() {
        return created;
    }

    public void setCreated(Integer created) {
        this.created = created;
    }
}

And finally, the Item class

public class Item {
    @JsonProperty("url")
    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

REST Client

To invoke the OpenAI API we define our REST client using the new REST Client Reactive, which allows a declarative way to define the API to be invoked using the new Jakarta EE and Microprofile annotations.

@RegisterRestClient(baseUri = "https://api.openai.com")
@Path("/v1")
public interface OpenAIRestClient {

        @GET
        @Path("/models")
        @ClientHeaderParam(name = "Authorization", value = "Bearer ${openai.api.key}")
        ModelResponse getModels();

        @POST
        @Path("/images/generations")
        @ClientHeaderParam(name = "Authorization", value = "Bearer ${openai.api.key}")
        CreateImageResponse generateImage(CreateImageRequest createImageRequest);

}

The @RegisterRestClient allows Quarkus to know that this interface should be available for CDI injection as a REST Client, the baseUri properties define the url the client point to. @Path, @POST are standard Jakarta REST annotations defining how to access the API.

To manage API auth, as we have seen before, we need to pass the API KEY inside the header of the request. To do this in our client, we use the @ClientHeaderParam passing the name and the value of the entries. In this case, we read the key from the application.properties using the notation ${opena.ai.key} that allows injecting the properties' value directly.

Testing the client

To test our client, let's define a REST resource that we will call from out browser.

@Path("/quarkus-openai")
public class OpenAIEndpoint {

    @RestClient
    private OpenAIRestClient openAIRestClient;

    @GET
    @Path("/generate-image")
    @Produces(MediaType.APPLICATION_JSON)
    public Response generateImage(@QueryParam("description") String description,
            @DefaultValue("1") @QueryParam("n") int n,
            @DefaultValue("1024x1024") @QueryParam("size") String size) {

        final CreateImageRequest createImageRequest = new CreateImageRequest();
        createImageRequest.setPrompt(description);
        createImageRequest.setN(n);
        createImageRequest.setSize(size);

        URI uri;
        try {
            uri = new URI(
                    openAIRestClient.generateImage(createImageRequest).getUrls().get(0).getUrl());
        } catch (URISyntaxException e) {
            return Response.noContent().build();
        }
        return Response.seeOther(uri).build();
    }
}

We define OpenAIEndpoint and inject the REST client using @RestClient annotation. Then we create the API generateImage that accepts the prompt and optionally the number of images and their size.

Inside the method, we build the request and pass it to our client; calling the method generateImage, we get the result and perform a redirect to the first URL of the response payload.

To see the result let's start our project with the command:

quarkus dev

and point the browser to this example url passing our prompt as the value of description parameters:

http://localhost:8080/quarkus-openai/generate-image?description=a%20photo%20of%20a%20happy%20corgi%20puppy%20sitting%20in%20front%20of%20sea

and the output will be:

Try with other prompts and enjoy the results.

Conclusion

This article we explored how to use the OpenAI DALL.E API to generate images from prompts. We created a Quarkus application that calls the API using the new REST Client Reactive and manage the result.

The code examples for this tutorial are available on GitHub.

References

Topics:

Related Articles

View All

Author(s)

  • Avatar photo
    Antonio Perrone

    I'm a passionate and experienced Software Architect, from Milan, Italy. I've worked as a Software Engineer and Architect for almost ten years in consulting. Currently I'm working as a Manager ... Learn more

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard