Welcome to the third lesson of our course on building an image generation service with Go! In our previous lessons, we created the PromptManager to format user inputs into detailed prompts and the ImageManager to handle storing and processing generated images. Now, we're ready to build the core component that brings everything together: the ImageGeneratorService.
The ImageGeneratorService is the central piece of our application that will:
- Connect to Google's Gemini API to generate images
- Use our
PromptManagerto format user inputs into effective prompts - Store generated images using our
ImageManager - Provide access to all previously generated images
This service acts as the bridge between our application's components and the external AI service that actually creates the images. By encapsulating all the image generation logic in a dedicated service struct, we maintain a clean separation of concerns in our application architecture.
In this lesson, we'll implement this service step by step, from setting up the API client to handling responses and errors. By the end, you'll have a fully functional image generation service that you can later integrate into a Go web application using Fiber.
For most Generative AI cases with Gemini, you can use the generative-ai-go/genai Go module for interacting with Gemini. As of this writing, however, this module does not support generative images.
Because of this, we are going to use the REST API directly with Go to request the images, which we will later encapsulate.
We've included a helper function to access the Gemini Image Generation API via REST in util.GenerateGeminiImages(prompt string, options *ImageGenerationParameters) ([][]byte, error). This was covered in a previous course so we won't go over it here. You can find this helper in the util folder of your practices.
In this constructor, we're doing two important things:
- Creating an instance of our
ImageManagerstruct to handle storing and retrieving images. - Creating an instance of our
PromptManagerstruct to handle retrieval of our prompts.
Now that we have our client set up, let's implement the core method of our service: GenerateImage(). This method will take a user input string, format it into a detailed prompt using our PromptManager, send the request to the Gemini API, and store the resulting image using our ImageManager.
Here's the implementation:
Let's break down what's happening in this method:
-
We start by calling
s.promptManager.FormatPrompt()to convert the user's input into a detailed prompt using our predefined template. This ensures consistency in our image generation requests. -
We call
util.GenerateGeminiImages()with the formatted prompt and image generation parameters, which include the aspect ratio. -
We check for errors in the image generation process and ensure that at least one image is generated.
-
We create a
bytes.Readerfrom the generated image data and pass it to ourImageManager'sAddImage()method, which stores the image and returns the base64 string.
Generating images through an external API can fail for various reasons: network issues, API limits, invalid prompts, or server errors. To make our service robust, we've added error handling at each step of the process, returning informative error messages.
This error handling is crucial for a production application, as it prevents crashes and provides meaningful error messages that can help with debugging and user feedback.
Now, let's add one more method to our service to retrieve all previously generated images:
This simple method delegates to our ImageManager's GetImages() method, returning the complete list of stored images along with their associated prompts and IDs.
With these two methods, our ImageGeneratorService provides a complete interface for generating and retrieving images. The service integrates our previously built components (PromptManager and ImageManager) and connects them to the external Gemini API.
Now that we've implemented our ImageGeneratorService, let's create a test script to verify that it works correctly. We'll create a new file called solution.go to use the new service:
In this test script, we:
- Import our
ImageGeneratorServicestruct. - Define a sample user input for testing.
- Create an instance of our
ImageGeneratorService. - Call the
GenerateImage()method with our sample input. - Print the result (the base64-encoded image).
- Retrieve and print all stored images.
When running this script with a valid API key, you would see output similar to:
In this lesson, we've built the ImageGeneratorService, the core component of our image generation application. This service connects our previously built components (PromptManager and ImageManager) to Google's Gemini API, allowing us to generate high-quality images from text prompts.
Let's review what we've learned:
- We set up an HTTP client to communicate with Google's Gemini API.
- We implemented the
GenerateImage()method to create images from user inputs. - We added robust error handling to deal with potential API issues.
- We created a method to retrieve all previously generated images.
- We tested our service with a sample prompt.
The ImageGeneratorService is a crucial piece of our application architecture. It encapsulates all the logic related to image generation, providing a clean interface for other components to use. In the next lesson, we'll build a controller that will use this service to handle HTTP requests in our Go web application.
In the upcoming practice exercises, you'll have the opportunity to work with the ImageGeneratorService, testing its functionality with different prompts and exploring how it integrates with the rest of our application. You'll also get to experiment with error handling and see how the service behaves in various scenarios.
Remember that to use this service in a real application, you'll need to:
- Set up the necessary environment variables for the API key and base URL.
- Ensure your Go environment is properly configured to make HTTP requests.
With the ImageGeneratorService in place, we're one step closer to having a complete image generation web application!
