How to create a story generator app with an image in Django using OpenAI?

Creating a story generator application and using OpenAI to draw images related to the story.

Sevdimali
Geek Culture
6 min readJan 11, 2023

--

Introduction

Today, together with you, we will create a storyteller application in Django and we will also create an image related to the story.

This project will help you to use OpenAI Api, Django models, and Python random module.

I want to skip the boring parts, such as creating a Django project, environment, etc.

Our stories will consist of several parts.

  1. Introduction
  2. Character
  3. Time
  4. Plot
  5. Location
  6. A Second Character
  7. The age of the second character
  8. The action was taken by the second character

We will use the DALL-E service from OpenAI to draw pictures.

The DALL-E service can create visuals based on written definitions thanks to the support of artificial intelligence. To use the DALL-E service, which has a straightforward way of working, you must prepare a written description of how you want to get an image.

We need an API_KEY to use OpenAI. For this purpose, you can register on the OpenAI website and get your personal API_KEY from this link.

You will only have access to the generated image through the URL for one hour, so it is recommended to save the image to your computer if you wish to keep it.

Create models and populate the database.

We create our appropriate models for the story sections we listed above.

Our models include only one char field named content.

Since the structure of all our models will be the same, in order not to repeat, we can create a Base Class and inherit our models from it. I have written in detail about Abstraction in Django in the following article.

Let’s create our models as follows:

from django.db import models


class Base(models.Model):
content = models.CharField(max_length=255)

class Meta:
abstract = True

def __str__(self):
return self.content


class SentenceStarter(Base):
pass


class Character(Base):
pass


class StoryTime(Base):
pass


class Plot(Base):
pass


class Place(Base):
pass


class SecondCharacter(Base):
pass


class CharacterAge(Base):
pass


class Activity(Base):
pass

As you can see from the code above, we have created our Base class which is abstract. There is one content field. We inherited our other models from this Abstract class.

For populating the database we will use custom Django commands.

To create a management command, we need to make a management/commands directory under our app folder. In this directory, we will create our management command file.

load_db.py

from django.core.management.base import BaseCommand
from core.models import SentenceStarter, Character, Place, SecondCharacter, CharacterAge, Activity, Plot, StoryTime

sentence_starter = ['In the past', 'About 100 years ago', 'In the 20 BC', 'Once upon a time', 'In 1990s',
'In the ancient Egypt']
character = [' there lived a king.', ' there was a man named Jack.', ' there was a young boy.', ' there was a old man.',
' there lived a farmer.', ' there was a man who lived with her son.']
time = [' One day', ' One full-moon night', ' One night', ' In the morning', ' At midnight']
story_plot = [' he was passing by', ' he was going for a picnic to', ' he is standing', ' he is walking',
' talking with old guy']
place = [' the mountains', ' the garden', ' the yard', ' the fence', ' the hills', ' the forest']
second_character = [' he saw a man', ' he saw a lady', ' he saw a boy', ' he saw a woman', ' he saw a girl']
age = [' who seemed to be in late 20s', ' who seemed very old and feeble', ' who seemed very young',
' who is very old looking']
activity = [' searching something.', ' digging a well on roadside.', ' trying to catch a snake.',
' looking from the window of the house.', ' fighting with someone.', ' counting the gold coins.',
' trying to hide.', ' entering the hive.', ' riding the horse.', ' want to escape.']


class Command(BaseCommand):
def handle(self, *args, **options):

for ss in sentence_starter:
ss_o = SentenceStarter(content=ss)
ss_o.save()

for c in character:
c_o = Character(content=c)
c_o.save()

for t in time:
t_o = StoryTime(content=t)
t_o.save()

for sp in story_plot:
sp_o = Plot(content=sp)
sp_o.save()

for p in place:
p_o = Place(content=p)
p_o.save()

for a in age:
a_o = CharacterAge(content=a)
a_o.save()

for ac in activity:
ac_o = Activity(content=ac)
ac_o.save()

for sc in second_character:
sc_o = SecondCharacter(content=sc)
sc_o.save()

I recommend reading the following article for more detailed information about how to create commands and test them.

We register our models in the Admin.py file.

admin.py

from django.contrib import admin
from core.models import SentenceStarter, Character, Place, SecondCharacter, CharacterAge, Activity, Plot, StoryTime

admin.site.register(SentenceStarter)
admin.site.register(Character)
admin.site.register(Place)
admin.site.register(SecondCharacter)
admin.site.register(CharacterAge)
admin.site.register(Activity)
admin.site.register(Plot)
admin.site.register(StoryTime)
Admin Page.

Create view and URL.

In this step we will create our view:

views.py

import random
import openai
from django.conf import settings
from django.shortcuts import render
from openai.error import APIConnectionError

from core.models import SentenceStarter, Character, Place, SecondCharacter, CharacterAge, Activity, Plot, StoryTime


def index(request):
random_starter_ids = SentenceStarter.objects.all().values_list('id', flat=True)
random_starter = SentenceStarter.objects.get(pk=random.choice(list(random_starter_ids)))

random_character_ids = Character.objects.all().values_list('id', flat=True)
random_character = Character.objects.get(pk=random.choice(list(random_character_ids)))

random_place_ids = Place.objects.all().values_list('id', flat=True)
random_place = Place.objects.get(pk=random.choice(list(random_place_ids)))

random_sc_ids = SecondCharacter.objects.all().values_list('id', flat=True)
random_sc = SecondCharacter.objects.get(pk=random.choice(list(random_sc_ids)))

random_ca_ids = CharacterAge.objects.all().values_list('id', flat=True)
random_ca = CharacterAge.objects.get(pk=random.choice(list(random_ca_ids)))

random_activity_ids = Activity.objects.all().values_list('id', flat=True)
random_activity = Activity.objects.get(pk=random.choice(list(random_activity_ids)))

random_plot_ids = Plot.objects.all().values_list('id', flat=True)
random_plot = Plot.objects.get(pk=random.choice(list(random_plot_ids)))

random_story_time_ids = StoryTime.objects.all().values_list('id', flat=True)
random_story_time = StoryTime.objects.get(pk=random.choice(list(random_story_time_ids)))

story = random_starter.content + random_character.content + random_story_time.content + random_plot.content +
random_place.content + random_sc.content + random_ca.content + random_activity.content

try:

openai.api_key = "OPENAI_API_KEY"
response = openai.Image.create(
prompt=story,
n=1,
size="512x512"
)
image_url = response['data'][0]['url']
except (ConnectionError, APIConnectionError):
image_url = None

context = {
'story': story,
'image_url': image_url
}
return render(request, context=context, template_name='index.html')

We first randomly select data from our models. Here, we initially get our ids in the database as a list, and in the next line, we select a random id from this list using the choice method from the Python “random” library and take the entry from the database according to that id. Later, we combine them and create our final sentence. Then we send the created sentence to the OpenAI image creation API. When submitting a request, we also specify the size and number of images we will create.

We adding a path in urls.py

urls.py

from django.contrib import admin
from django.urls import path
from core.views import index
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='index')
]

As a final step, we will create the index.html file and put the story and image here.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Story Generator with Image</title>
</head>
<body>
<h3>{{ story }}</h3>
<img src="{{ image_url }}" alt="">
</body>
</html>

And the final results:

Please keep in mind that, OpenAI gives 18$ free credit for testing purposes.

And it has three resolutions and pricing changes based on the resolution as below:

Thanks for reading. I hope you enjoyed it ❤. If you found the article useful don’t forget to clap and follow me.

This is my #2/52 story in 2023, I’m on a challenge to write 52 stories in 2023.

Keep Learning..!

--

--

Sevdimali
Geek Culture

Python Developer, who loves to share ideas, contribute open source, and play chess. Sharing at least one article in every week. Sometimes more😉