본문 바로가기

ChatGPT

(ChatGPT) Automating your blog with OpenAI 2

Following on from my last post on ChatGPT auto-writing, this time I'm going to create an auto-upload to a blog. I tried several platforms for blogging, but it's not easy to find a blog that provides a simple API, so I decided to just use Steemit.


Database Data Structure

I created the database (DB) in Firestore and used Jetadmin as the DB management tool.
The data that is automatically generated is simply the body, main image, and hashtags, excluding the title. And the actual document structure is as follows

Instead of making it fully automatic, I configured the system so that I have to enter the title. After entering the title in the DB, ChatGPT automatically generates and fills in the remaining fields. ChatGPT will then post the article to the blog.

Writing a blog post with ChatGPT

Get data from the DB that has only a title and no body yet. Since this is a post that hasn't been published to the blog yet, we'll have ChatGPT write the post.

We ask ChatGPT to write a function to get the data with no body.

I modified the code of the getDocumentsWithNullBody function that ChatGPT wrote a little bit, because when I tried to register the title in Jetadmin, the value of the field that was not filled in was empty ("") instead of Null.

async function getDocumentsWithNullBody(collectionName: string) {
const db = firebase.firestore();
const collectionRef = db.collection(collectionName);
const query = collectionRef.where("body", "in", [null, ""]);

const snapshot = await query.get();
return snapshot.docs.map((doc) => ({ id: doc.id, data: doc.data() }));
}

Now, press the New Record button in Jetadmin, and enter the title of the blog you want to create.

A new record has been created in the DB.

Then, if you test the getDocumentsWithNullBody function, you can see that it gets a record with only a title.

const response = await getDocumentsWithNullBody("documents");
console.log(response);

Using the writeBlogPost function we wrote last time, we ask ChatGPT to generate values for the remaining fields, and then update the Firestore with the generated data.

// #1. Get the title of the upcoming blog post
const response = await getDocumentsWithNullBody("documents");
const { id, data: { title } } = response[0];

// #2. Request ChatGPT to create body, tags, and mainImage
const body = await writeBlogPost(
"`I'm writing an essay about the life of a developer for my blog. The title is "${title}". Please write a post of about 500 words. And don't include the main title.`
);
const tags = await writeBlogPost(
`Generate about 5 good hashtags for the post title "${title}". Don't use # in front of the tags, and separate the hashtags with commas`
);
const mainImage = await writeBlogPost(
`[INFO: Use the Unsplash API (https://source.unsplash.com/1600×900/?). the query is just some tags that describes the image. Write the final Image URL.] ## DO NOT RESPOND TO INFO BLOCK ##\n\nGive me a blog cover image url fit to this subject: ${title}`
);

// #3. Update to the Firestore
await updateDocument(id, title, body, tags, mainImage);

Check that the data generated by ChatGPT is stored in the DB.

Uploading to the blog

Now write an uploadPost function to post to the blog.

The uploadPost function is also modified slightly because I couldn't use the code written by ChatGPT.

import { Client, PrivateKey } from "@upvu/dsteem";

async function uploadPost(post: {
title: string;
body: string;
tags: string[];
image: string[];
author: string;
postingKey: string;
}) {
const { title, body, tags, author, image, postingKey } = post;
const client = new Client(["https://api.steemit.com"]);

try {
const result = await client.broadcast.comment(
{ title
author,
body,
parent_author: "",
parent_permlink: tags[0],
permlink: new Date().toISOString().replace(/[^a-zA-Z0-9]+/g, "").toLowerCase(),
title,
json_metadata: JSON.stringify({
tags,
image,
app: "dsteem-js",
format: "markdown",
}),
},
PrivateKey.fromString(postingKey)
);
return result;
} catch (error) {
console.error(error);
throw error;
}
}

Now let's post it to the blog with the uploadPost function.

const author = process.env.STEEMIT_USERNAME!;
const postingKey = process.env.STEEMIT_POSTING_KEY!;

await uploadPost({
title,
body: `![](${mainImage})\n\n${body}`,
tags: ['kr', ..tags.split(',')],
image: [mainImage],
author,
postingKey,
});

Tested and successfully posted to the blog!

Last step: Create a scheduler

Finally, let's create a scheduler that will check the DB for new data every 10 minutes and automatically blog if there are any new records.

For reference, reading documents in Google Cloud Firestore is free up to 5,000 times per day. Therefore, you can retrieve data about 34 times per minute. If I had it check the DB every second, it would use up a day's worth of data quickly. So I set it to check the DB every 10 minutes, which is reasonable.

The following code checks the DB every 10 minutes and auto-blogs any newly registered records.

while (true) {
console.log(`${new Date().toISOString()} | CHECK!`);

// #1. Get the title of the upcoming blog
const response = await getDocumentsWithNullBody("documents");
if (!response.length) return;

const { id, data: { title } } = response[0];
console.log(`${new Date().toISOString()} | title: "${title}"`);

// #2. Request ChatGPT to create body, tags, and mainImage
// ⋯ (omitted) ⋯

// #3. Update the Firestore
// ⋯ (omitted) ⋯

// #4. Post to your blog
// ⋯ (omitted) ⋯

console.log(`${new Date().toISOString()} | DONE!`);

// 10 minutes waiting
await new Promise((resolve) => setTimeout(resolve, 10 * 60 * 1000));
}

If you want a cron-like scheduler behavior, you can use the node-schedule package.

Conclusion

  • Jetadmin has similar automation features to zapier. However, I found it difficult to use. I found it easier to just develop my own.
  • Using the Openai API, I made 12 API requests. And it cost me $0.23 to use it. I think it costs about $0.08 to write one post with the Openai API. I think that's pretty cheap. If you write prompts well, you can save more money.
  • I've been working with ChatGPT on coding and writing blog posts, and I feel like I have a reliable partner.