Introducing the AI Children’s Book Generator, a prototype that harnesses the power of artificial intelligence (GPT and DALLE2) to craft stories specifically designed for children by children and their parents. While still in its early stages, this innovative tool shows potential in changing children’s literature by offering unique and engaging narratives that inspire imagination and foster a love for reading.
This code snippet demonstrates the initial setup for using the OpenAI API and the Spacy library in a Python script:
# import libraries
import openai
import spacy
# Set up OpenAI API key
openai.api_key = "add_openAI_API_key_here_123"
What follows is the standard function I commonly use for working with the openAI API. The parameters passed to openai.Completion.create
are as follows:
engine
: Specifies the model to be used for text generation. In this case, the model “text-davinci-003” is used. Different models have different capabilities and pricing, so you can choose the most suitable model for your needs.prompt
: The text provided as input or context to generate the response. It is the value passed to thegenerate_response
function.max_tokens
: Specifies the maximum number of tokens in the generated response. Tokens are chunks of text (e.g., words, punctuation marks) used by the language model. The value of 4035 sets a limit on the length of the generated response.n
: Specifies the number of responses to generate. In this case, it is set to 1, so only one response will be generated.stop
: Specifies an optional string or list of strings where text generation should stop. IfNone
, the model generates a complete response based on the givenmax_tokens
limit.temperature
: Controls the randomness of the generated text. A higher temperature (e.g., 1) makes the output more diverse and creative, while a lower temperature (e.g., 0.2) makes it more focused and deterministic.
def generate_response(prompt):
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
max_tokens=4035 ,
n=1,
stop=None,
temperature=1,
)
return response.choices[0].text.strip()
What follows is the basic logic for asking questions to the user for defining the prompt and thus the story. This is an example which could easily be improved to increase the quality of the stories.
age = input("What is the age of the child?: ")
theme = input("What is the theme of the story?: ")
lesson_learned = input("What lesson needs to be learned?: ")
setting = input("What is the setting of the story?: ")
story_line = input("What is the story line?: ")
stories = {
1: "a steady rise from bad to good fortune",
2: "a fall from good to bad, a tragedy",
3: "a rise then a fall in fortune",
4: "a fall, a rise then a fall again",
5: "rise in fortune, fall, then rise again",
6: "fall in fortune, then rise"
}
story_line_full = stories.get(int(story_line), "rise, fall, rise")
def word_lim(age):
words = 0
if int(age) < 4:
return 200
elif int(age) < 6:
return 400
elif int(age) < 11:
return int(age) * 200
elif int(age) < 13:
words = int(age) * 500
else:
return 20000
prompt = f"Write a children's story that is funny for {age} year olds. The story has around {word_lim(age)}. The Theme is'{theme}' and set in {setting}. The story line follows '{story_line}' make sure the story has a clear beginning, middle and end."
What is the age of the child?: 5 What is the theme of the story?: pirate What lesson needs to be learned?: keep studying What is the setting of the story?: desert What is the story line?: 6
After running the above code, the 5 questions are asked and I have answered them as shown above. This only generates the prompt, now we need to generate the story with this prompt and print the output.
txt = generate_response(prompt)
print(f"{txt}")
(1) Once upon a time, in the heat of the desert, there was a band of six pirates, Captain Boombox and his five crewmates. They were on a mission to explore the desert in search of buried treasure. Every day they travelled in their rusty old ship, Adventurer, scouring the sands in hopes of uncovering a pirate's fortune. One day, Captain Boombox spotted something curious- a large cactus-shaped rock. He and his crew began digging in the sand and sure enough, they uncovered a mysterious chest with the label "Pirates Welcome!" Captain Boombox opened the chest, and to his excitement, he found a treasure map inside! As his crew cheered, Boombox took charge and set sail for the unknown destination marked on the map.
(2) They sailed for days, battling wild winds and battling sandstorms. The crew felt scared and exhausted, but Captain Boombox kept their spirits high with songs and tall tales. Eventually, they reached their destination –an oasis in the middle of the desert. Captain Boombox marched his crew ashore and told them that the treasure was hidden nearby. They dug for hours in the scorching sun and eventually hit something solid. It was a chest made of solid gold! When Boombox opened it, the crew found gems, jewels, and other glittering items inside. As the crew loaded up their vessel with the treasure, Boombox declared them the boldest and bravest band of pirates in the desert. The six adventurers sailed off into the sunset, proud and richer than ever before! And they all lived happily ever after. THE END
Generate images from the text
After generating the text, we can now use DALLE2 to generate the images. Note that text preprocessing is required to get good quality images that relate to the actual text.
# split the text based on paragraph (thus the newline split)
story_split = txt.split("\n\n")
# The en_core_web_md is the medium language model. It is best in most cases
nlp = spacy.load("en_core_web_md")
#used to sumarize the paragraphs for more accurate image generation
def summarize(text):
doc = nlp(text)
sentences = list(doc.sents)
sentence_scores = [sentence.similarity(doc) for sentence in sentences]
top_sentences = sorted(range(len(sentence_scores)), key=lambda i: sentence_scores[i], reverse=True)[:3]
summary_sentences = [sentences[i] for i in sorted(top_sentences)]
summary_text = " ".join(str(sentence) for sentence in summary_sentences)
return summary_text
# Summarize each section and store in a new array
summary_sections = [summarize(section) for section in story_split]
In sumarize_sections we now have all paragraphs summarized. They can now all be used as a prompt to generate the relevant images. Lets give an example for one paragraph:
# output is the 5th (summarized) paragraph from the text
summary_sections[4]
'They sailed for days, battling wild winds and battling sandstorms. The crew felt scared and exhausted, but Captain Boombox kept their spirits high with songs and tall tales.'
Lastly we define the function for the openAI api call of DALLE2. Here we also run the function and get an output for the 5th paragraph.
import os
openai.api_key = "add_openAI_API_key_here_123"
response = openai.Image.create(
prompt=f'digital art children story: {summary_sections[4]}',
n=1,
size="256x256",
)
print(response["data"][0]["url"])
# https://realpython.com/generate-images-with-dalle-openai-api/
Output Image
Relevant Paragraph
‘They sailed for days, battling wild winds and battling sandstorms. The crew felt scared and exhausted, but Captain Boombox kept their spirits high with songs and tall tales.’
Next steps to improve the POC:
- build a User interface
- Improve the questions
- Improve the text generation prompt
- Improve the image generation prompt