본문 바로가기
취미 또는 부업/openai 블로그 글 생성기

ChatGPT와 OpenAI를 활용한 블로그 글쓰기2

by cy.kim 2024. 9. 30.
반응형

이전 포스팅에 이어서 이번 포스팅은 electron관련 전체 소스를 첨부하려 한다.

 

먼저 package.json을 통해 현재 사용할 라이브러리 등을 설치한다(npm install)

 

{
  "name": "autoblog",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "npx electron .",
    "dev": "nodemon --watch . --exec \"electron .\""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "axios": "^1.7.7",
    "electron": "^32.1.2",
    "marked": "^14.1.2",
    "openai": "^4.64.0"
  }
}

 

그 뒤 index.js를 작성한다.

import { app, BrowserWindow, ipcMain } from 'electron';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import getOpenAIInstance from "./openaiInstance.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 창 생성 함수
function createWindow() {
    const win = new BrowserWindow({
        width: 1024,
        height: 880,
        webPreferences: {
            preload: join(__dirname, 'preload.js'),
            nodeIntegration: false,  // Ensures no direct access to Node.js
            contextIsolation: true,  // Isolates the context for better security
        },
    });

    win.loadFile('./view/index.html');
}

app.whenReady().then(() => {
    createWindow();

    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
            createWindow();
        }
    });
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

 

기존 require에서 import로 구문을 변경했고 창 사이즈를 변경했다.

이 소스도 chatgpt의 도움을 받아 작성했다.

 

그 뒤에 view와 통신을 위한 다음 코드도 넣는다.

ipcMain.handle('generate-blog-post', async (event, data) => {
    try {
        return {
            blogContent: blogContent,
        };

    } catch (error) {
        console.error("오류 발생:", error);
        return { error: error };
    }
});

 

preload.js에 설정한 내용을 통해 view쪽 js 파일에서 호출할 수 있는 함수를 하나 만들었다.

여기에 추가될 내용은 openai와 api통신 후 해당 내용을 view로 다시 리턴해주는 역할을 추가할 것이다.

 

npm으로 openai를 설치 후

싱글턴 패턴으로 호출할 예정이다.

import { OpenAI } from 'openai';

let openaiInstance = null;

const getOpenAIInstance = (apiKey) => {
    if (!openaiInstance) {
        openaiInstance = new OpenAI({
            apiKey: apiKey
        });
    }
    return openaiInstance;
};

export default getOpenAIInstance;

 

그 후 함수를 최종적으로 구현 하면

 

ipcMain.handle('generate-blog-post', async (event, data) => {
    try {
        const openai = getOpenAIInstance(data.key);

        // 1단계: 블로그 글 개요 생성
        const outlineResponse = await openai.chat.completions.create({
            model: data.chatModel,
            messages: [
                {
                    role: "system",
                    content: "당신은 전문적인 블로그 콘텐츠 작성 도우미입니다. 작성하는 블로그 글은 독자들에게 유익하고 흥미로운 정보를 제공하며, 쉽게 이해할 수 있도록 명확하게 서술되어야 합니다. 블로그는 SEO에 최적화되어야 하며, 핵심 주제를 중심으로 구체적이고 실용적인 정보를 제공합니다."
                },
                {
                    role: "user",
                    content: `${data.userInput}에 대한 블로그 글을 작성해 주세요. 이 블로그 글은 다음의 중요한 요소를 포함해야 합니다:

                    1. **주제에 대한 명확한 소개**: 간결하면서도 핵심을 담아 독자가 주제를 빠르게 이해할 수 있도록 소개합니다.
                    2. **핵심 개념 설명**: 주제와 관련된 주요 요소나 개념을 설명하며, 독자가 쉽게 따라올 수 있도록 구체적이면서도 명확하게 서술합니다.
                    3. **실제 사례와 데이터**: 주제를 뒷받침할 수 있는 실제 사례나 통계를 사용해 신뢰성을 높입니다.
                    4. **주제 선택 이유**: 왜 이 주제를 선택했는지, 독자에게 왜 중요한지에 대해 간단히 설명합니다.
                    5. **참고 자료와 추가 학습 링크**: 독자가 더 깊이 탐구할 수 있는 자료나 링크를 제시하여 글의 신뢰도를 높입니다.
                    6. **소제목 사용**: 내용을 체계적으로 나누기 위해 적절한 소제목을 사용하고, 각 소제목 아래 최소 3~5문단 이상의 구체적 설명을 작성합니다.
                    7. **SEO 최적화**: 자연스럽게 주요 키워드를 포함하여 검색엔진에서 쉽게 발견될 수 있도록 작성합니다.
                    8. **결론과 핵심 메시지**: 독자가 얻을 수 있는 주요 메시지를 명확하게 전달하고, 글을 적절히 마무리합니다.
                    
                    각 항목은 상세한 설명과 사례로 뒷받침되어야 하며, 독자가 흥미를 가질 수 있도록 쉽게 소화 가능한 내용으로 작성해주세요. 최소 500자 이상을 요구합니다.`
                }
            ],
            max_tokens:3000,
            temperature: 0.7,
        });

        const blogOutline = outlineResponse.choices[0]?.message?.content;
        // 2단계: 마크다운 형식의 블로그 글 생성
        const blogResponse = await openai.chat.completions.create({
            model: data.chatModel,
            messages: [
                {
                    role: "system",
                    content: `당신은 매우 전문적인 HTML 콘텐츠 생성 도우미입니다. 사용자가 제공한 내용을 바탕으로 SEO에 최적화된 블로그 글을 작성해야 합니다. 블로그 글은 HTML 태그로 형식화되어야 하며, 글에 제목, 소제목, 목록, 강조된 문구 등을 포함해야 합니다. 문법적으로 완벽하며, 읽기 쉬운 구조로 작성해 주세요. 각 소제목 아래에는 최소한 3~5개의 문단이 포함되어야 하고, HTML 태그는 p, h1, h2, h3, h4, h5, h6, strong, i, ul, li, ol만 사용해야 합니다. head, body, meta, doctype 태그는 사용하지 마세요. 이모지는 적절한 부분에서만 가볍게 사용하세요.`
                },
                {
                    role: "user",
                    content: `
                    다음은 블로그 글의 개요입니다:
            
                    ${blogOutline}
            
                    위 개요를 바탕으로 다음의 요구사항을 반영하여 HTML 형식으로 블로그 글을 작성해 주세요:
            
                    1. 제목(h1 태그)을 사용하여 블로그 글의 메인 주제를 명확하게 드러내세요. (예: 📢, 선택 사항)
                    2. 각 소제목(h2, h3 태그 등)을 사용하여 개요의 각 항목을 구분하세요. (필요할 경우 💡 이모지를 포함)
                    3. 각 소제목 아래에는 최소 3개의 문단(p 태그)을 사용하여 상세히 설명하세요. 문단 시작에 가벼운 이모지를 사용할 수 있습니다. (예: ✨, 선택 사항)
                    4. 리스트가 필요한 경우 ul, ol, li 태그를 사용해 목록을 만드세요. 목록에 적합한 이모지를 가볍게 추가하세요. (예: ✅, 선택 사항)
                    5. 중요한 내용은 strong 또는 i 태그를 사용해 강조하세요. 강조된 내용에 이모지를 제한적으로 넣으세요. (예: 🔥, 선택 사항)
                    6. 문법과 철자를 확인하고, 글이 논리적으로 연결되도록 하세요.
                    7. HTML 구조는 간결하고, 중복된 태그 사용을 피하세요.
                    8. SEO 최적화를 위해 주요 키워드를 자연스럽게 포함하세요.
                    9. 글의 끝에는 독자가 추가적인 정보를 얻을 수 있는 링크나 참고 자료를 포함하세요.
            
                    이모지는 가볍게 포인트로만 사용하여, 과도하지 않게 글의 흐름을 유지해 주세요.`
                }
            ],
            max_tokens:3000,
            temperature: 0.7,
        });

        const blogContentHTML = blogResponse.choices[0]?.message?.content.replace('```html', '').replace('```', '');

        let blogContent = blogContentHTML;

        if(data.imgFlag) {
            const imageResponse = await openai.images.generate({
                prompt: `Create a high-quality, visually appealing image that represents the following blog content: "${blogOutline}". Ensure the image is relevant to the topic and aesthetically pleasing. Use a clean and professional design style.`,
                model:data.imageModel,
                n: 1,
                size: "1024x1024",
                response_format: "b64_json"
            });
            blogContent = `<p style="margin-bottom:30px;"><img src="data:image/png;base64, ${imageResponse.data[0].b64_json}" alt="${data.userInput}"></p>${blogContentHTML}`;
        }

        return {
            blogContent: blogContent,
        };

    } catch (error) {
        console.error("오류 발생:", error);
        return { error: error };
    }
});

 

이런식으로 할 수 있다

여기서 파라미터로 api키와 어떤 내용에 관해 쓸건지에대한 내용 이미지 생성여부에 따라 이미지 생성 등 등 이있다.

추가로 prompt 수정으로 원하는데로 chatgpt에게 글을 쓰게 요청할 수 있다.

 

import { app, BrowserWindow, ipcMain } from 'electron';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import getOpenAIInstance from "./openaiInstance.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 창 생성 함수
function createWindow() {
    const win = new BrowserWindow({
        width: 1024,
        height: 880,
        webPreferences: {
            preload: join(__dirname, 'preload.js'),
            nodeIntegration: false,  // Ensures no direct access to Node.js
            contextIsolation: true,  // Isolates the context for better security
        },
    });

    win.loadFile('./view/index.html');
}

app.whenReady().then(() => {
    createWindow();

    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
            createWindow();
        }
    });
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

// ChatGPT API 호출
ipcMain.handle('generate-blog-post', async (event, data) => {
    try {
        const openai = getOpenAIInstance(data.key);

        // 1단계: 블로그 글 개요 생성
        const outlineResponse = await openai.chat.completions.create({
            model: data.chatModel,
            messages: [
                {
                    role: "system",
                    content: "당신은 전문적인 블로그 콘텐츠 작성 도우미입니다. 작성하는 블로그 글은 독자들에게 유익하고 흥미로운 정보를 제공하며, 쉽게 이해할 수 있도록 명확하게 서술되어야 합니다. 블로그는 SEO에 최적화되어야 하며, 핵심 주제를 중심으로 구체적이고 실용적인 정보를 제공합니다."
                },
                {
                    role: "user",
                    content: `${data.userInput}에 대한 블로그 글을 작성해 주세요. 이 블로그 글은 다음의 중요한 요소를 포함해야 합니다:

                    1. **주제에 대한 명확한 소개**: 간결하면서도 핵심을 담아 독자가 주제를 빠르게 이해할 수 있도록 소개합니다.
                    2. **핵심 개념 설명**: 주제와 관련된 주요 요소나 개념을 설명하며, 독자가 쉽게 따라올 수 있도록 구체적이면서도 명확하게 서술합니다.
                    3. **실제 사례와 데이터**: 주제를 뒷받침할 수 있는 실제 사례나 통계를 사용해 신뢰성을 높입니다.
                    4. **주제 선택 이유**: 왜 이 주제를 선택했는지, 독자에게 왜 중요한지에 대해 간단히 설명합니다.
                    5. **참고 자료와 추가 학습 링크**: 독자가 더 깊이 탐구할 수 있는 자료나 링크를 제시하여 글의 신뢰도를 높입니다.
                    6. **소제목 사용**: 내용을 체계적으로 나누기 위해 적절한 소제목을 사용하고, 각 소제목 아래 최소 3~5문단 이상의 구체적 설명을 작성합니다.
                    7. **SEO 최적화**: 자연스럽게 주요 키워드를 포함하여 검색엔진에서 쉽게 발견될 수 있도록 작성합니다.
                    8. **결론과 핵심 메시지**: 독자가 얻을 수 있는 주요 메시지를 명확하게 전달하고, 글을 적절히 마무리합니다.
                    
                    각 항목은 상세한 설명과 사례로 뒷받침되어야 하며, 독자가 흥미를 가질 수 있도록 쉽게 소화 가능한 내용으로 작성해주세요. 최소 500자 이상을 요구합니다.`
                }
            ],
            max_tokens:3000,
            temperature: 0.7,
        });

        const blogOutline = outlineResponse.choices[0]?.message?.content;
        // 2단계: 마크다운 형식의 블로그 글 생성
        const blogResponse = await openai.chat.completions.create({
            model: data.chatModel,
            messages: [
                {
                    role: "system",
                    content: `당신은 매우 전문적인 HTML 콘텐츠 생성 도우미입니다. 사용자가 제공한 내용을 바탕으로 SEO에 최적화된 블로그 글을 작성해야 합니다. 블로그 글은 HTML 태그로 형식화되어야 하며, 글에 제목, 소제목, 목록, 강조된 문구 등을 포함해야 합니다. 문법적으로 완벽하며, 읽기 쉬운 구조로 작성해 주세요. 각 소제목 아래에는 최소한 3~5개의 문단이 포함되어야 하고, HTML 태그는 p, h1, h2, h3, h4, h5, h6, strong, i, ul, li, ol만 사용해야 합니다. head, body, meta, doctype 태그는 사용하지 마세요. 이모지는 적절한 부분에서만 가볍게 사용하세요.`
                },
                {
                    role: "user",
                    content: `
                    다음은 블로그 글의 개요입니다:
            
                    ${blogOutline}
            
                    위 개요를 바탕으로 다음의 요구사항을 반영하여 HTML 형식으로 블로그 글을 작성해 주세요:
            
                    1. 제목(h1 태그)을 사용하여 블로그 글의 메인 주제를 명확하게 드러내세요. (예: 📢, 선택 사항)
                    2. 각 소제목(h2, h3 태그 등)을 사용하여 개요의 각 항목을 구분하세요. (필요할 경우 💡 이모지를 포함)
                    3. 각 소제목 아래에는 최소 3개의 문단(p 태그)을 사용하여 상세히 설명하세요. 문단 시작에 가벼운 이모지를 사용할 수 있습니다. (예: ✨, 선택 사항)
                    4. 리스트가 필요한 경우 ul, ol, li 태그를 사용해 목록을 만드세요. 목록에 적합한 이모지를 가볍게 추가하세요. (예: ✅, 선택 사항)
                    5. 중요한 내용은 strong 또는 i 태그를 사용해 강조하세요. 강조된 내용에 이모지를 제한적으로 넣으세요. (예: 🔥, 선택 사항)
                    6. 문법과 철자를 확인하고, 글이 논리적으로 연결되도록 하세요.
                    7. HTML 구조는 간결하고, 중복된 태그 사용을 피하세요.
                    8. SEO 최적화를 위해 주요 키워드를 자연스럽게 포함하세요.
                    9. 글의 끝에는 독자가 추가적인 정보를 얻을 수 있는 링크나 참고 자료를 포함하세요.
            
                    이모지는 가볍게 포인트로만 사용하여, 과도하지 않게 글의 흐름을 유지해 주세요.`
                }
            ],
            max_tokens:3000,
            temperature: 0.7,
        });

        const blogContentHTML = blogResponse.choices[0]?.message?.content.replace('```html', '').replace('```', '');

        let blogContent = blogContentHTML;

        if(data.imgFlag) {
            const imageResponse = await openai.images.generate({
                prompt: `Create a high-quality, visually appealing image that represents the following blog content: "${blogOutline}". Ensure the image is relevant to the topic and aesthetically pleasing. Use a clean and professional design style.`,
                model:data.imageModel,
                n: 1,
                size: "1024x1024",
                response_format: "b64_json"
            });
            blogContent = `<p style="margin-bottom:30px;"><img src="data:image/png;base64, ${imageResponse.data[0].b64_json}" alt="${data.userInput}"></p>${blogContentHTML}`;
        }

        return {
            blogContent: blogContent,
        };

    } catch (error) {
        console.error("오류 발생:", error);
        return { error: error };
    }
});

 

전체 코드를 첨부하고 electron으로 구현한 index.js를 마무리하고 다음 포스팅엔 view쪽 코드를 첨부할 예정이다.

반응형