Back to Portfolio

Generating Content with Puppeteer and OpenAI

AI & Automation2024
OpenAI content generation dashboard

To automate blog content creation for Foo, a SaaS platform I created, I built a CLI utilizing Puppeteer and OpenAI that runs daily as a Kubernetes CronJob. It generates full-length articles with metadata, references, and a main image — and publishes directly to my self-hosted Ghost instance using the Ghost REST API.

The CLI performs the following steps: 1) Iterates over a curated list of RSS feeds relevant to a target topic (e.g., "AI"). 2) Launches a headless Puppeteer instance to scrape a set number of recent blog posts from each feed. 3) Uses the OpenAI Chat Completion API to read and analyze post content, score each article (0–100) based on its relevance to the topic, and select the top-scoring posts to generate a comprehensive review post.

The system also generates blog captions and meta descriptions, a featured image, and a structured list of references. All content is published programmatically to the Ghost CMS.

Sample OpenAI Return Schema

I defined an OpenAI Chat Completion return schema as follows (derived from a corresponding prompt):

const PostOutputResponseSchema = z.object({
  /** Content of the blog post */
  content: z.string(),

  /**
   * Description of the blog post as meta element on the page
   */
  description: z.string(),

  /**
   * Excerpt of the blog post that describes it but more
   * importantly entices users to click into the post
   */
  excerpt: z.string(),

  /** Prompt text to use when generating an image */
  imageGenerationPrompt: z.string(),

  /** Chain of thought steps and output in determining image generation prompt */
  imageGenerationPromptSteps: z.array(StepSchema),

  /** A small blurb to use as a post on social media */
  socialMediaExcerpt: z.string(),

  /** Tags of the post for classification */
  tags: z.array(z.string()),

  /** Title of the blog post */
  title: z.string(),

  /** Title posibilities of the blog post */
  possibleTitles: z.array(z.string()),
});

You may have noticed the imageGenerationPrompt field above. This field represents generated prompt text that is then used as the prompt to generate a main blog image via DALL·E 3 model.

OpenAI DALL-E generated image example

Notable Technologies

OpenAI Chat Completion APIPuppeteerimageminGhost Content APIKubernetes CronJobTypeScript