How to Build Text to Image Generator Using Django and Hugging Face API


Welcome to this tutorial, where I will walk you through building an AI-powered Text-to-Image Generator using Django, Hugging Face API, and Python. This project allows users to input a prompt and choose a style, generating a unique image based on the prompt and style using Hugging Face’s powerful inference API.

By the end of this tutorial, you will have a fully functional web app that allows users to generate and download images by simply providing a textual description and selecting a preferred style.


Prerequisites

To follow along, make sure you have the following installed:

  • Python 3.x
  • Django
  • Requests library
  • Pillow (PIL) for image processing
  • Hugging Face API access (You’ll need an API key from Hugging Face)

Step 1: Setting Up the Django Project

First, create a new Django project and app. If you haven’t installed Django yet, you can do so by running:

pip install django requests pillow

Create a new Django project by running:

django-admin startproject text_to_image
cd text_to_image

Next, create a new app within your project:

python manage.py startapp generator

Add the new app to your settings.py file:

INSTALLED_APPS = [
    # other apps
    'generator',
]

Step 2: Setting Up the Hugging Face API

To generate images from text, we’ll use the Hugging Face API. You’ll need to sign up for an API key from Hugging Face.

Once you have your key, store it securely. For this tutorial, I’ll show you how to use it within the code.

Step 3: Writing the Views in Django

Create the view that handles image generation in the views.py file in the generator app. Here’s the code:

from django.shortcuts import render
import requests
import base64
from PIL import Image
import io

# Hugging Face API details
API_URL = "https://api-inference.huggingface.co/models/ZB-Tech/Text-to-Image"
headers = {"Authorization": "Bearer REPLACE_WITH_YOUR_HUGGING_FACE_TOKEN"}

def query(payload):
    response = requests.post(API_URL, headers=headers, json=payload)
    print("Status Code:", response.status_code)
    
    if response.status_code != 200:
        raise Exception(f"Error: {response.status_code}, {response.text}")

    return response.content  # Return the binary content directly

def generate_image(request):
    if request.method == 'POST':
        prompt = request.POST.get('prompt')
        style = request.POST.get('style')  # Get the selected style from the form
        if prompt and style:
            try:
                # Send the prompt and style to the API
                image_bytes = query({"inputs": prompt, "style": style})  # Adjust this line as per API requirements
                
                # Open the image
                image = Image.open(io.BytesIO(image_bytes))
                
                # Convert the image to a format that can be rendered in the template
                img_io = io.BytesIO()
                image.save(img_io, 'PNG')
                img_io.seek(0)
                image_data = base64.b64encode(img_io.read()).decode('utf-8')

                # Render the result template with the image
                return render(request, 'result.html', {
                    'prompt': prompt,
                    'style': style,
                    'image_data': image_data,
                })
            except Exception as e:
                return render(request, 'generate_image.html', {
                    'error': str(e),
                })

    return render(request, 'generate_image.html')

This view handles both GET and POST requests. It uses the Hugging Face API to send the prompt and style, retrieve the generated image, and display it on the page.

Note: Make sure to replace the Hugging Face API key with your own to avoid rate limits or access issues.

Step 4: Creating the HTML Templates

Create two HTML templates, generate_image.html and result.html, inside a new folder called templates/generator/.


generate_image.html

This template handles the form where users input a text prompt and choose a style.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Roboto', sans-serif;
            background-color: #121212; /* Dark background */
            color: #e0e0e0; /* Light text */
            margin: 0;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            flex-direction: column;
        }
        h1 {
            color: #00c853; /* Bright green color */
            margin-bottom: 20px;
            text-align: center;
        }
        .container {
            background: #1f1f1f; /* Darker card background */
            border-radius: 15px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
            padding: 30px;
            width: 90%;
            max-width: 450px;
            transition: transform 0.2s;
        }
        .container:hover {
            transform: scale(1.02);
        }
        label {
            font-weight: bold;
            margin-bottom: 5px;
            display: block;
            color: #00c853; /* Bright green color */
        }
        input[type="text"],
        select {
            width: 100%;
            padding: 12px;
            margin-bottom: 15px;
            border: 1px solid #444; /* Darker border */
            border-radius: 8px;
            font-size: 14px;
            background: #2a2a2a; /* Dark background for inputs */
            color: #e0e0e0; /* Light text */
            transition: border-color 0.3s;
        }
        input[type="text"]:focus,
        select:focus {
            border-color: #00c853; /* Bright green focus */
            outline: none;
        }
        button {
            width: 100%;
            padding: 12px;
            background-color: #00c853; /* Bright green button */
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            cursor: pointer;
            transition: background-color 0.3s;
            font-weight: bold;
        }
        button:hover {
            background-color: #009624; /* Darker green on hover */
        }
        .error {
            color: #ff5252; /* Red for errors */
            margin-top: 10px;
            text-align: center;
        }
        .result {
            margin-top: 20px;
            text-align: center;
        }
        img {
            max-width: 100%;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
        }
        /* Progress bar styles */
        .progress {
            width: 100%;
            background-color: #444; /* Background color for the progress bar */
            border-radius: 8px;
            margin-top: 10px;
            display: none; /* Initially hidden */
        }
        .progress-bar {
            height: 20px;
            width: 0%; /* Initial width */
            background-color: #00c853; /* Green color for the progress */
            border-radius: 8px;
            transition: width 0.4s; /* Smooth transition */
        }
        @media (max-width: 500px) {
            .container {
                width: 100%;
                padding: 20px; /* Adjust padding for smaller screens */
            }
        }
    </style>
    <script>
        function showProgressBar() {
            const progressBarContainer = document.getElementById('progress');
            const progressBar = document.querySelector('.progress-bar');
            progressBarContainer.style.display = 'block';
            let width = 0;
            const interval = setInterval(() => {
                if (width >= 100) {
                    clearInterval(interval);
                } else {
                    width++;
                    progressBar.style.width = width + '%'; // Update the width of the progress bar
                }
            }, 30); // Adjust the interval time as needed
        }
    </script>
</head>
<body>
    <h1> AI Text to Image Generator</h1>
    <div class="container">
        <form method="post" onsubmit="showProgressBar()">
            {% csrf_token %}
            <label for="prompt">Enter your prompt:</label>
            <input type="text" id="prompt" name="prompt" required placeholder="e.g., A futuristic city">

            <label for="style">Select a style:</label>
            <select id="style" name="style" required>
                <option value="realistic">Realistic</option>
                <option value="cartoon">Cartoon</option>
                <option value="sketch">Sketch</option>
                <option value="abstract">Abstract</option>
                <option value="digital">Digital Art</option>
                <option value="oil painting">Oil Painting</option>
                <!-- Add more styles as needed -->
            </select>

            <button type="submit">Generate Image</button>
        </form>
        
        <!-- Progress bar -->
        <div class="progress" id="progress">
            <div class="progress-bar"></div>
        </div>

        {% if error %}
            <p class="error">Error: {{ error }}</p>
        {% elif image_data %}
            <div class="result">
                <h2>Generated Image</h2>
                <img src="data:image/png;base64,{{ image_data }}" alt="Generated Image"/>
                <p><strong>Prompt:</strong> {{ prompt }}</p>
                <p><strong>Style:</strong> {{ style }}</p>
            </div>
        {% endif %}
    </div>
</body>
</html>

result.html

This template shows the generated image and provides an option to download it.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Generated Image</title>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Roboto', sans-serif;
            background-color: #121212; /* Dark background */
            color: #e0e0e0; /* Light text */
            margin: 0;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
            height: 100vh;
        }
        h1 {
            color: #00c853; /* Bright green color */
            margin-bottom: 20px;
            text-align: center;
        }
        .container {
            background: #1f1f1f; /* Darker card background */
            border-radius: 15px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
            padding: 30px;
            width: 90%;
            max-width: 450px;
            text-align: center;
        }
        .error {
            color: #ff5252; /* Red for errors */
            margin-top: 10px;
            text-align: center;
        }
        img {
            max-width: 100%;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
            margin-top: 20px;
        }
        a {
            display: inline-block;
            margin-top: 20px;
            padding: 10px 20px;
            background-color: #00c853; /* Bright green link */
            color: white;
            border-radius: 8px;
            text-decoration: none;
            transition: background-color 0.3s;
        }
        a:hover {
            background-color: #009624; /* Darker green on hover */
        }
        @media (max-width: 500px) {
            .container {
                width: 100%;
                padding: 20px; /* Adjust padding for smaller screens */
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Generated Image</h1>
        {% if error %}
            <p class="error">Error: {{ error }}</p>
        {% else %}
            <p><strong>Prompt:</strong> {{ prompt }}</p>
            <img src="data:image/png;base64,{{ image_data }}" alt="Generated Image" id="generatedImage"/>
            <a href="data:image/png;base64,{{ image_data }}" download="generated_image.png" id="downloadButton">Download Image</a> <!-- Download button -->
        {% endif %}
        <a href="{% url 'generate_image' %}">Generate Another Image</a>
    </div>
</body>
</html>

Step 5: Adding URLs

You need to map the views to URLs. Open your urls.py and add the following:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.generate_image, name='generate_image'),
]

This sets up the routing so the generate_image view can be accessed.

Step 6: Testing the Application

Finally, run the Django server:

python manage.py runserver

Visit http://localhost:8000/, enter a prompt, choose a style, and generate an image. If everything is set up correctly, you should see your generated image on the result page and have an option to download it!


Conclusion

In this tutorial, we created a text-to-image generator using Django and Hugging Face’s API. The project includes a form for users to enter a prompt and select an art style. The Hugging Face API processes the input, generating an image that can be downloaded.

Feel free to experiment with the styles, and try different prompts for creative outputs!


For more tutorials like this, check out my YouTube channel and blog:

Happy coding!

Leave a Comment

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


Shopping Basket
Scroll to Top