Skip to content

Commit

Permalink
✨ multiple content generation (#5)
Browse files Browse the repository at this point in the history
Changed site metadata values including post titles and language defaults. Added yargs for better command-line argument handling. Improved existing helper functions in generate-content.ts and added fail-safe mechanisms for content generation. Updated instructional content creator prompts in content-creator.ts for better clarity. Added new blog posts and respective thumbnails.

---
  • Loading branch information
mingi3314 authored Jul 15, 2024
2 parents c2d92ac + 717c389 commit 2ef52d0
Show file tree
Hide file tree
Showing 13 changed files with 376 additions and 87 deletions.
2 changes: 1 addition & 1 deletion gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const siteMetadata = {
utterances: {
repo: meta.utterances,
},
postTitle: "전체",
postTitle: "All",
menuLinks: [
{
link: "/",
Expand Down
12 changes: 6 additions & 6 deletions gatsby-meta-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
/** @type {MetaConfig} */
const metaConfig = {
//TODO: Change the values below according to your project
title: "tmp-title",
description: "tmp-description",
author: "tmp-author",
siteUrl: "https://tmp-siteUrl.netlify.app",
lang: "ko-KR",
utterances: "tmp-utterances",
title: "blog-stream",
description: "Blog that uploads useful contents.",
author: "mingi3314",
siteUrl: "https://blog-stream.netlify.app",
lang: "en-US",
utterances: "mingi3314/blog-stream",
links: { github: "https://github.com/mingi3314/blog-stream" },
favicon: "src/images/icon.png",
}
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"styled-components": "^6.1.1",
"styled-reset": "^4.5.1",
"typography": "^0.16.24",
"vscode-theme-github-light": "https://github.com/yunlingz/vscode-theme-github-light.git#commit=38174065a9e6c8d93a20fab5fe7c7641c07aeca7"
"vscode-theme-github-light": "https://github.com/yunlingz/vscode-theme-github-light.git#commit=38174065a9e6c8d93a20fab5fe7c7641c07aeca7",
"yargs": "^17.7.2"
},
"resolutions": {
"@langchain/core": "0.2.15"
Expand All @@ -68,6 +69,7 @@
"@types/react-helmet": "^6.1.11",
"@types/styled-components": "^5.1.34",
"@types/typography": "^0.16.7",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"babel-plugin-styled-components": "^2.1.4",
Expand Down
109 changes: 76 additions & 33 deletions scripts/generate-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,87 @@ import { RunnableSequence } from "@langchain/core/runnables"
import { ChatMistralAI } from "@langchain/mistralai"
import axios from "axios"
import dotenv from "dotenv"
import yargs from "yargs"

import { prompt as contentCreatorPrompt } from "./prompts/content-creator"
import { prompt as metaGeneratorPrompt } from "./prompts/meta-generator"
import { prompt as outlineBuilderPrompt } from "./prompts/outline-builder"

dotenv.config()

const backgroundColors = [
"3498db", // 밝은 파랑
"2ecc71", // 에메랄드 녹색
"e74c3c", // 밝은 빨강
"f39c12", // 주황
"9b59b6", // 보라
"1abc9c", // 청록색
"d35400", // 진한 주황
"c0392b", // 어두운 빨강
"16a085", // 진한 청록색
"2980b9", // 진한 파랑
"8e44ad", // 진한 보라
"2c3e50", // 짙은 남색
const argv = yargs(process.argv.slice(2))
.option("n-content", {
alias: "n",
describe: "Number of content pieces to generate",
type: "number",
default: 1,
})
.option("topic", {
alias: "t",
describe: "Topic for content generation",
type: "string",
default: "stock-trading", // TODO: Change the default topic
})
.parseSync()

const BACKGROUND_COLORS = [
"3498db",
"2ecc71",
"e74c3c",
"f39c12",
"9b59b6",
"1abc9c",
"d35400",
"c0392b",
"16a085",
"2980b9",
"8e44ad",
"2c3e50",
]

const THUMBNAIL_WIDTH = 1200
const THUMBNAIL_HEIGHT = 630
const TEXT_COLOR = "ffffff"

type Meta = {
meta: {
title: string
description: string
}
}

async function main() {
const topic = "stock trading"
const count = argv["n-content"]
const topic = argv["topic"]

const model = new ChatMistralAI({
model: "open-mixtral-8x7b",
temperature: 0.8,
temperature: 0.7,
})

const outline = await generateOutline(model, topic)
const content = await generateContent(model, outline)
const meta = await generateMeta(model, outline)
for (let i = 0; i < count; i++) {
try {
console.log(`Generating content ${i + 1} of ${count}...`)

const outline = await generateOutline(model, topic)
const content = await generateContent(model, outline)
const meta = await generateMeta(model, outline)

await createMarkdownFile(content, meta)
} catch (error) {
console.error("An error occurred:", error)
console.error("Skipping to the next content generation...")
}

await createMarkdownFile(content, meta)
console.log("Content generation complete. Moving to the next content...")
}
}

async function generateOutline(model: BaseChatModel, topic: string) {
// Helper functions with improved error handling and typing
async function generateOutline(
model: BaseChatModel,
topic: string,
): Promise<string> {
console.log("Generating outline...")
const outlineBuildChain = RunnableSequence.from([
PromptTemplate.fromTemplate(outlineBuilderPrompt),
Expand All @@ -61,7 +104,10 @@ async function generateOutline(model: BaseChatModel, topic: string) {
return outline
}

async function generateContent(model: BaseChatModel, outline: string) {
async function generateContent(
model: BaseChatModel,
outline: string,
): Promise<string> {
console.log("Generating content based on the outline...")
const contentCreateChain = RunnableSequence.from([
PromptTemplate.fromTemplate(contentCreatorPrompt),
Expand All @@ -73,7 +119,10 @@ async function generateContent(model: BaseChatModel, outline: string) {
return content
}

async function generateMeta(model: BaseChatModel, outline: string) {
async function generateMeta(
model: BaseChatModel,
outline: string,
): Promise<Meta> {
console.log("Generating meta data based on the outline...")
const metaGenerateChain = RunnableSequence.from([
PromptTemplate.fromTemplate(metaGeneratorPrompt),
Expand All @@ -83,18 +132,15 @@ async function generateMeta(model: BaseChatModel, outline: string) {

const meta = await metaGenerateChain.invoke({ Outline: outline })
console.log("Meta data generated.")
return meta as { meta: { title: string; description: string } }
return meta as Meta
}

async function generatePlaceholderThumbnail(fileName: string): Promise<string> {
const width = 1200
const height = 630
const text = fileName.replaceAll("-", " ")
const backgroundColor =
backgroundColors[Math.floor(Math.random() * backgroundColors.length)]
const textColor = "ffffff"
BACKGROUND_COLORS[Math.floor(Math.random() * BACKGROUND_COLORS.length)]

const url = `https://dummyimage.com/${width}x${height}/${backgroundColor}/${textColor}.png&text=${encodeURIComponent(text)}`
const url = `https://dummyimage.com/${THUMBNAIL_WIDTH}x${THUMBNAIL_HEIGHT}/${backgroundColor}/${TEXT_COLOR}.png&text=${encodeURIComponent(text)}`

const response = await axios({
url,
Expand All @@ -119,10 +165,7 @@ async function generatePlaceholderThumbnail(fileName: string): Promise<string> {
})
}

async function createMarkdownFile(
content: string,
meta: { meta: { title: string; description: string } },
) {
async function createMarkdownFile(content: string, meta: Meta): Promise<void> {
const currentDate = new Date()
.toLocaleString("en-US", {
timeZone: "Asia/Seoul",
Expand Down Expand Up @@ -164,4 +207,4 @@ ${content}`
console.log(`Markdown file created: ${filePath}`)
}

main()
main().catch(error => console.error("An error occurred:", error))
12 changes: 6 additions & 6 deletions scripts/prompts/content-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export const prompt = `### Instruction ###
- Use SEO best practices, such as incorporating keywords naturally and using internal and external links.
- Keep the content within the 1000 to 1800-word range.
- Construct the content in markdown format with the following header structure:
- MUST Use a single # for the main title (H1)
- MUST Use ## for main section headers (H2)
- MUST Use ### for subsection headers (H3)
- MUST Use a single # sign for the main title
- MUST Use ## sign for main section headers
- MUST Use ### sign for subsection headers
- Do not use more than three # symbols for any header.
### Input ###
Expand All @@ -25,9 +25,9 @@ export const prompt = `### Instruction ###
### Output Instruction ###
Provide the full blog post content based on the given outline. The content should be in markdown format with appropriate headers and subheaders as specified in the instructions. Ensure that the final post is comprehensive, engaging, and aligns closely with the provided outline.
you MUST use the following header structure:
- Use a single # for the main title (H1)
- Use ## for main section headers (H2)
- Use ### for subsection headers (H3)
- Use a single # for the main title
- Use ## for main section headers
- Use ### for subsection headers
- Do not use more than three # symbols for any header.
### Reward ###
Expand Down
4 changes: 2 additions & 2 deletions src/components/postNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const PostNavigator: React.FC<PostNavigatorProps> = ({
{nextPost && (
<Link key={nextPost.id} to={nextPost.slug as string}>
<Card>
<Direction>이전 글</Direction>
<Direction>Prev</Direction>
<Title>{nextPost.title}</Title>
</Card>
</Link>
Expand All @@ -30,7 +30,7 @@ const PostNavigator: React.FC<PostNavigatorProps> = ({
{prevPost && (
<Link key={prevPost.id} to={prevPost.slug as string}>
<Card>
<Direction>다음 글</Direction>
<Direction>Next</Direction>
<Title>{prevPost.title}</Title>
</Card>
</Link>
Expand Down
6 changes: 3 additions & 3 deletions src/components/seo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import useSiteMetadata from "~/src/hooks/useSiteMetadata"

import defaultOpenGraphImage from "../images/og-thumbnail.png"

const DEFAULT_LANG = "en"
const DEFAULT_LANG = "en-US"

type Meta = React.DetailedHTMLProps<
React.MetaHTMLAttributes<HTMLMetaElement>,
Expand All @@ -34,7 +34,7 @@ const SEO: React.FC<SEOProperties> = ({
jsonLds = [],
}) => {
const site = useSiteMetadata()
const description = desc || site.description
const description = (desc || site.description || "").slice(0, 160)
const ogImageUrl = image || (defaultOpenGraphImage as string)
const jsonLd = {
"@context": "https://schema.org",
Expand Down Expand Up @@ -67,7 +67,7 @@ const SEO: React.FC<SEOProperties> = ({
<Helmet
htmlAttributes={{ lang: site.lang ?? DEFAULT_LANG }}
title={title || site.title!}
titleTemplate={title || site.title!.replace(" 🍎", "")}
titleTemplate={title || site.title!}
meta={
[
{
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2ef52d0

Please sign in to comment.