diff --git a/bakerydemo/base/management/commands/create_gpt_generated_data.py b/bakerydemo/base/management/commands/create_gpt_generated_data.py new file mode 100644 index 000000000..1c37d58fa --- /dev/null +++ b/bakerydemo/base/management/commands/create_gpt_generated_data.py @@ -0,0 +1,157 @@ +from pathlib import Path + +from django.conf import settings +from django.core.management.base import BaseCommand +from django.utils import timezone +from django.utils.text import slugify +from wagtail.rich_text import RichText +from django.core.files.base import ContentFile +from wagtail.images.models import Image +from django.db import IntegrityError + +from bakerydemo.blog.models import BlogIndexPage, BlogPage, BlogPersonRelationship +from bakerydemo.base.models import Person +import requests +import json +import random +import datetime +from wagtail.models import Collection + +from openai import OpenAI + +FIXTURE_MEDIA_DIR = Path(settings.PROJECT_DIR) / "base/fixtures/media/original_images" +client = OpenAI() + +class Command(BaseCommand): + help = "Creates generated Page data using chatGPT. Useful for demonstrating different use cases." + + def add_arguments(self, parser): + parser.add_argument( + "--page_count", + type=int, + help="How many blog pages to create", + ) + + def make_stream_field_content(self, title, subtitle, collection_name): + # get random images for the blog from the generated set + image_1 = self.get_random_image(Image, collection_name) + image_2 = self.get_random_image(Image, collection_name) + # generate rich text for the content + prompt = f"""Please give me three paragraphs of content for a blog post called '{title}' with the subtitle '{subtitle}'. They should in JSON of the form {{"paragraph_1": "

example

", "paragraph_2": "

example

", "paragraph_3: "

example

"}} where example is replaced with html content. You may use

,

,

and

tags as well as lists. It is the entire blog post so make sure to conclude at the end.""" + chat_completion = client.chat.completions.create( + messages=[ + { + "role": "user", + "content": prompt, + } + ], + model="gpt-4", + ) + streamfield_chat_completion = chat_completion.choices[0].message.content.replace('\n', "") + json_streamfield_chat_completion = json.loads(streamfield_chat_completion) + + return [('paragraph_block', RichText(json_streamfield_chat_completion["paragraph_1"])), + ('image_block', {'image': image_1}), + ('paragraph_block', RichText(json_streamfield_chat_completion["paragraph_2"])), + ('image_block', {'image': image_2}), + ('paragraph_block', RichText(json_streamfield_chat_completion["paragraph_3"])), + ] + + + def generate_images(self, theme, number_of_images, collection_name): + for _ in range(number_of_images): + print("Generating image...") + prompt = f"an image for blog post about {theme}" + response = client.images.generate( + model="dall-e-3", + prompt=prompt, + size="1024x1024", + quality="standard", + n=1, + ) + # Download the image + image_url = response.data[0].url + response = requests.get(image_url) + # Get or create a collection for the generated images + try: + collection, created = Collection.objects.get_or_create(name=collection_name) + except IntegrityError: + root_coll = Collection.get_first_root_node() + collection = root_coll.add_child(name=collection_name) + + if response.status_code == 200: + # Create a Django ContentFile with the image content + image_content = ContentFile(response.content) + wagtail_image = Image(title=prompt, collection=collection) + wagtail_image.file.save(f"{prompt}.jpg", image_content, save=True) + + def make_title(self, theme): + chat_completion = client.chat.completions.create( + messages=[ + { + "role": "user", + "content": f"Create a unique and creative title for a blog post about {theme}. Aim for originality and surprise me with your choice. It should be of the format title: subtitle. Don't include the words title or subtitle in your response", + } + ], + model="gpt-4", + ) + content = chat_completion.choices[0].message.content.strip("'").strip('"') + title, subtitle = content.split(":", 1) + print(f'title: {title}, subtitle: {subtitle}') + return title, subtitle + + def make_intro(self, title, subtitle): + chat_completion = client.chat.completions.create( + messages=[ + { + "role": "user", + "content": f"Based on the title '{title}' and the subtitle '{subtitle}', create an introduction paragraph for this blog post. Don't repeat the title or the subtitle.", + } + ], + model="gpt-4", + ) + content = chat_completion.choices[0].message.content.strip("'") + return content + + def get_random_image(self, model, collection_name): + return model.objects.filter(collection__name=collection_name).order_by("?").first() + + def get_random_model(self, model): + return model.objects.order_by("?").first() + + def get_random_recent_date(self): + now = timezone.now() + random_day_diff = random.randint(0, 365) + random_date = now - datetime.timedelta(days=random_day_diff) + return random_date + + def create_pages(self, page_count, theme, collection_name): + self.stdout.write("Creating blog pages...") + blog_index = BlogIndexPage.objects.live().first() + for _ in range(page_count): + title, subtitle = self.make_title(theme) + new_blog_page = BlogPage( + title=title, + image=self.get_random_image(Image, collection_name), + slug=slugify(title), + introduction=self.make_intro(title, subtitle), + body=self.make_stream_field_content(title, subtitle, collection_name), + subtitle=subtitle, + date_published=self.get_random_recent_date(), + ) + blog_index.add_child(instance=new_blog_page) + # add an author + BlogPersonRelationship.objects.create(page=new_blog_page, person=self.get_random_model(Person)) + + def handle(self, **options): + theme = input('What should the blog posts be about? ') + page_count = int(input('How many blog posts should be created? ')) + generate_images = input('Do you want to create new images? (y/n): ').lower().strip() + if generate_images == 'y': + number_of_images = int(input('How many images should be created? ')) + collection_name = input('What should the collection to keep these images in be called? (Or what is the name of an existing one?) ') + else: + number_of_images = 0 + collection_name = input('Which collection do you want to take images from? ') + self.generate_images(theme, number_of_images, collection_name) + self.create_pages(page_count, theme, collection_name)