|
| 1 | +--- |
| 2 | +title: Generate images with SDXL Turbo |
| 3 | +description: Learn to generate images with SDXL with a frontend web app. |
| 4 | +sidebar_position: 2 |
| 5 | +--- |
| 6 | + |
| 7 | +import Tabs from '@theme/Tabs'; |
| 8 | +import TabItem from '@theme/TabItem'; |
| 9 | + |
| 10 | +When it comes to working with an AI image generator, the speed in which images are generated is often a compromise. |
| 11 | +RunPod's Serverless Workers allows you to host [SDXL Turbo](https://huggingface.co/stabilityai/sdxl-turbo) from Stability AI, which is a fast text-to-image model. |
| 12 | + |
| 13 | +In this tutorial, you'll build a web application, where you'll leverage RunPod's Serverless Worker and Endpoint to return an image from a text-based input. |
| 14 | + |
| 15 | +By the end of this tutorial, you'll have an understanding of running a Serverless Worker on RunPod and sending requests to an Endpoint to receive a response. |
| 16 | + |
| 17 | +You can proceed with the tutorial by following the build steps outlined here or skip directly to [Deploy the Model](#deploy-the-model) section. |
| 18 | + |
| 19 | +## Prerequisites |
| 20 | + |
| 21 | +This section presumes you have an understanding of the terminal and can execute commands from your terminal. |
| 22 | + |
| 23 | +Before starting this tutorial, you'll need access to: |
| 24 | + |
| 25 | +### RunPod |
| 26 | + |
| 27 | +To continue with this quick start, you'll need access to the following from RunPod: |
| 28 | + |
| 29 | +- RunPod account |
| 30 | +- RunPod API Key |
| 31 | + |
| 32 | +### Docker |
| 33 | + |
| 34 | +To build your Docker image, you'll need access to the following: |
| 35 | + |
| 36 | +- Docker installed |
| 37 | +- Docker account |
| 38 | + |
| 39 | +You can also use the prebuilt image from [runpod/sdxl-turbo](https://hub.docker.com/r/runpod/sdxl-turbo). |
| 40 | + |
| 41 | +### GitHub |
| 42 | + |
| 43 | +To clone the `worker-sdxl-turbo` repo, you'll need access to the following: |
| 44 | + |
| 45 | +- Git installed |
| 46 | +- Permissions to clone GitHub repos |
| 47 | + |
| 48 | +With the prerequisites covered, get started by building and pushing a Docker image to a container registry. |
| 49 | + |
| 50 | +## Build and push your Docker image |
| 51 | + |
| 52 | +This step will walk you through building and pushing your Docker image to your container registry. |
| 53 | +This is useful to building custom images for your use case. |
| 54 | +If you prefer, you can use the prebuilt image from [runpod/sdxl-turbo](https://hub.docker.com/r/runpod/sdxl-turbo) instead of building your own. |
| 55 | + |
| 56 | +Building a Docker image allows you to specify the container when creating a Worker. |
| 57 | +The Docker image includes the [RunPod Handler](https://github.com/runpod-workers/worker-sdxl-turbo/blob/main/src/handler.py) which is how you provide instructions to Worker to perform some task. |
| 58 | +In this example, the Handler is responsible for taking a Job and returning a base 64 instance of the image. |
| 59 | + |
| 60 | +1. Clone the [RunPod Worker SDXL Turbo](https://github.com/runpod-workers/worker-sdxl-turbo) repository: |
| 61 | + |
| 62 | +```command |
| 63 | +gh repo clone runpod-workers/worker-sdxl-turbo |
| 64 | +``` |
| 65 | + |
| 66 | +2. Navigate to the root of the cloned repo: |
| 67 | + |
| 68 | +```command |
| 69 | +cd worker-sdxl-turbo |
| 70 | +``` |
| 71 | + |
| 72 | +3. Build the Docker image: |
| 73 | + |
| 74 | +```command |
| 75 | +docker build --tag <username>/<repo>:<tag> . |
| 76 | +``` |
| 77 | + |
| 78 | +4. Push your container registry: |
| 79 | + |
| 80 | +```command |
| 81 | +docker push <username>/<repo>:<tag> |
| 82 | +``` |
| 83 | + |
| 84 | +Now that you've pushed your container registry, you're ready to deploy your Serverless Endpoint to RunPod. |
| 85 | + |
| 86 | +## Deploy a Serverless Endpoint |
| 87 | + |
| 88 | +The container you just built will run on the Worker you're creating. |
| 89 | +Here, you will configure and deploy the Endpoint. |
| 90 | +This will include the GPU and the storage needed for your Worker. |
| 91 | + |
| 92 | +This step will walk you through deploying a Serverless Endpoint to RunPod. |
| 93 | + |
| 94 | +1. Login to the [RunPod Serverless console](https://www.runpod.io/console/serverless). |
| 95 | +2. Select **+ New Endpoint**. |
| 96 | +3. Provide the following: |
| 97 | + 1. Endpoint name. |
| 98 | + 2. Select a GPU. |
| 99 | + 3. Configure the number of workers. |
| 100 | + 4. (optional) Select **FlashBoot**. |
| 101 | + 5. (optional) Select a template. |
| 102 | + 6. Enter the name of your Docker image. |
| 103 | + - For example, `runpod/sdxl-turbo:latest`. |
| 104 | + 7. Specify enough memory for your Docker image. |
| 105 | +4. Select **Deploy**. |
| 106 | + |
| 107 | +Now, let's send a request to your Endpoint. |
| 108 | + |
| 109 | +## Send a request |
| 110 | + |
| 111 | +Now that our Endpoint is deployed, you can begin interacting with and integrating it into an application. |
| 112 | +Before writing the logic into the applicaiton, ensure that you can interact with the Endpoint by sending a request. |
| 113 | + |
| 114 | +Run the following command: |
| 115 | + |
| 116 | +<Tabs> |
| 117 | + <TabItem value="curl" label="cURL" default> |
| 118 | + |
| 119 | +```bash |
| 120 | +curl -X POST "https://api.runpod.ai/v2/${YOUR_ENDPOINT}/runsync" \ |
| 121 | + -H "accept: application/json" \ |
| 122 | + -H "content-type: application/json" \ |
| 123 | + -H "authorization: ${YOUR_API_KEY}" \ |
| 124 | + -d '{ |
| 125 | + "input": { |
| 126 | + "prompt": "${YOUR_PROMPT}", |
| 127 | + "num_inference_steps": 25, |
| 128 | + "refiner_inference_steps": 50, |
| 129 | + "width": 1024, |
| 130 | + "height": 1024, |
| 131 | + "guidance_scale": 7.5, |
| 132 | + "strength": 0.3, |
| 133 | + "seed": null, |
| 134 | + "num_images": 1 |
| 135 | + } |
| 136 | + }' |
| 137 | +``` |
| 138 | + |
| 139 | +</TabItem> |
| 140 | + <TabItem value="output" label="Output"> |
| 141 | + |
| 142 | +```json |
| 143 | +{ |
| 144 | + "delayTime": 168, |
| 145 | + "executionTime": 251, |
| 146 | + "id": "sync-fa542d19-92b2-47d0-8e58-c01878f0365d-u1", |
| 147 | + "output": "BASE_64", |
| 148 | + "status": "COMPLETED" |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +</TabItem> |
| 153 | +</Tabs> |
| 154 | + |
| 155 | +Export your variable names in your terminal session or replace them in line: |
| 156 | + |
| 157 | +- `YOUR_ENDPOINT`: The name of your Endpoint. |
| 158 | +- `YOUD_API_KEY`: The API Key required with read and write access. |
| 159 | +- `YOUR_PROMPT`: The custom prompt passed to the model. |
| 160 | + |
| 161 | +You should se the output. The status will return `PENDING`; but quickly change to `COMPLETED` if you query the Job Id. |
| 162 | + |
| 163 | +## Integrate into your application |
| 164 | + |
| 165 | +Now, let's create a web application that can take advantage of writing a prompt and generate an image based on that prompt. |
| 166 | +While these steps are specific to JavaScript, you can make requests against your Endpoint in any language of your choice. |
| 167 | + |
| 168 | +To do that, you'll create two files: |
| 169 | + |
| 170 | +- `index.html`: The frontend to your web application. |
| 171 | +- `script.js`: The backend which handles the logic behind getting the prompt and the call to the Serverless Endpoint. |
| 172 | + |
| 173 | +<Tabs> |
| 174 | + <TabItem value="html" label="HTML" default> |
| 175 | + |
| 176 | +The HTML file (`index.html`) sets up a user interface with an input box for the prompt and a button to trigger the image generation. |
| 177 | + |
| 178 | +```html |
| 179 | +<!-- index.html --> |
| 180 | +<!DOCTYPE html> |
| 181 | +<html lang="en"> |
| 182 | +<head> |
| 183 | + <meta charset="UTF-8"> |
| 184 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 185 | + <title>RunPod AI Image Generator</title> |
| 186 | + <style> |
| 187 | + body { |
| 188 | + font-family: Arial, sans-serif; |
| 189 | + text-align: center; |
| 190 | + padding: 20px; |
| 191 | + } |
| 192 | +
|
| 193 | + #imageResult { |
| 194 | + margin-top: 20px; |
| 195 | + } |
| 196 | + </style> |
| 197 | +</head> |
| 198 | +<body> |
| 199 | + <h1>RunPod AI Image Generator</h1> |
| 200 | + <input type="text" id="promptInput" placeholder="Enter your image prompt" /> |
| 201 | + <button onclick="generateImage()">Generate Image</button> |
| 202 | + |
| 203 | + <div id="imageResult"></div> |
| 204 | + |
| 205 | + <script src="script.js"></script> |
| 206 | +</body> |
| 207 | +</html> |
| 208 | +``` |
| 209 | + |
| 210 | +</TabItem> |
| 211 | + <TabItem value="javascript" label="JavaScript"> |
| 212 | + |
| 213 | +The JavaScript file (`script.js`) contains the `generateImage` function. This function reads the user's input, makes a POST request to the RunPod serverless endpoint, and handles the response. |
| 214 | +The server's response is expected to contain the base64-encoded image, which is then displayed on the webpage. |
| 215 | + |
| 216 | +```javascript |
| 217 | +// script.js |
| 218 | +async function generateImage() { |
| 219 | + const prompt = document.getElementById("promptInput").value; |
| 220 | + if (!prompt) { |
| 221 | + alert("Please enter a prompt!"); |
| 222 | + return; |
| 223 | + } |
| 224 | + |
| 225 | + const options = { |
| 226 | + method: "POST", |
| 227 | + headers: { |
| 228 | + accept: "application/json", |
| 229 | + "content-type": "application/json", |
| 230 | + // Replace with your actual API key |
| 231 | + authorization: "Bearer ${process.env.REACT_APP_AUTH_TOKEN}", |
| 232 | + }, |
| 233 | + body: JSON.stringify({ |
| 234 | + input: { |
| 235 | + prompt: prompt, |
| 236 | + num_inference_steps: 25, |
| 237 | + width: 1024, |
| 238 | + height: 1024, |
| 239 | + guidance_scale: 7.5, |
| 240 | + seed: null, |
| 241 | + num_images: 1, |
| 242 | + }, |
| 243 | + }), |
| 244 | + }; |
| 245 | + |
| 246 | + try { |
| 247 | + const response = await fetch( |
| 248 | + // Replace with your actual Endpoint Id |
| 249 | + "https://api.runpod.ai/v2/${process.env.REACT_APP_ENDPOINT_ID}/runsync", |
| 250 | + options, |
| 251 | + ); |
| 252 | + const data = await response.json(); |
| 253 | + if (data && data.output) { |
| 254 | + const imageBase64 = data.output; |
| 255 | + const imageUrl = `data:image/jpeg;base64,${imageBase64}`; |
| 256 | + document.getElementById("imageResult").innerHTML = |
| 257 | + `<img src="${imageUrl}" alt="Generated Image" />`; |
| 258 | + } else { |
| 259 | + alert("Failed to generate image"); |
| 260 | + } |
| 261 | + } catch (error) { |
| 262 | + console.error("Error:", error); |
| 263 | + alert("Error generating image"); |
| 264 | + } |
| 265 | +} |
| 266 | +``` |
| 267 | + |
| 268 | +</TabItem> |
| 269 | +</Tabs> |
| 270 | + |
| 271 | +1. Replace `${process.env.REACT_APP_AUTH_TOKEN}` with your actual API key. |
| 272 | +2. Replace `${process.env.REACT_APP_ENDPOINT_ID}` with your specific Endpoint. |
| 273 | +3. Open `index.html` in a web browser, enter a prompt, and click the "Generate Image" button to see the result. |
| 274 | + |
| 275 | +This web application serves as a basic example of how to interact with your RunPod serverless endpoint from a client-side application. |
| 276 | +It can be expanded or modified to fit more complex use cases. |
| 277 | + |
| 278 | +## Run a server |
| 279 | + |
| 280 | +You can run a server through Python or by opening the `index.html` page in your browser. |
| 281 | + |
| 282 | +<Tabs> |
| 283 | + |
| 284 | +<TabItem value="python" label="Python" default> |
| 285 | + |
| 286 | + Run the following command to start a server locally using Python. |
| 287 | + |
| 288 | + ```python |
| 289 | + python -m http.server 8000 |
| 290 | + ``` |
| 291 | + |
| 292 | +</TabItem> |
| 293 | + |
| 294 | +<TabItem value="directly" label="File explorer"> |
| 295 | + |
| 296 | + **Open the File in a Browser** |
| 297 | + |
| 298 | + Open the `index.html` file directly in your web browser. |
| 299 | + |
| 300 | + 1. Navigate to the folder where your `index.html` file is located. |
| 301 | + 2. Right-click on the file and choose "Open with" and select your preferred web browser. |
| 302 | + - Alternatively, you can drag and drop the `index.html` file into an open browser window. |
| 303 | + - The URL will look something like `file:///path/to/your/index.html`. |
| 304 | + |
| 305 | +</TabItem> |
| 306 | +</Tabs> |
0 commit comments