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.
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.
- Introduction
- Character
- Time
- Plot
- Location
- A Second Character
- The age of the second character
- 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)
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..!