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:
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.