메뉴 닫기

워드프레스 자동 등록 : 파이썬, ChatGPT API, 워드프레스 Rest API 활용 #3

워드프레스 자동등록 - 파이썬, ChatGPT API, 워드프레스 Rest API #3

머리말

이번 편에서는 워드프레스 자동등록의 꽃이라 할 수 있는 ChatGPT API 를 활용하여 특정 주제로 글을 생성하여 워드프레스 자동등록이 되도록 구현을 해보려고 한다.

워드프레스 Rest API(이하 WP Rest API) 로 구현한 신규 포스팅 등록 기능은 지난 포스팅의 소스를 기반으로 작성이 될 예정이니 편을 참고 바란다.

https://github.com/mymizze/Class.wp.auto-post.git

참고용 강의 자료 소스

Summary

  •  ChatGPT API 사용법
  •  ChatGPT 를 활용한 글 생성
  •  ChatGPT 로 생성한 글 워드프레스에 자동 등록

ChatGPT API 사용법

API Reference – OpenAI API

ChatGPT API 공식 문서

자세한 사용법은 위의 공식 문서를 참고 하길 바라며 이번 포스팅에서 딱 우리가 사용 할 최소한의 기본적인 부분의 사용법을 알아보자

  • openai 모듈 설치
pip install openai

  • openai 모듈 호출
import openai
  • ChatGPT API 인증
openai.organization = "나의 ChatGPT 조직 ID: org-euZ0s47nUy...."
openai.api_key = "나의 ChatGPT API Key: sk-1tfTO3fW..."

조직 ID 와 API Key 얻는 방법은 현 강의 #1 편 참조

워드프레스 자동 등록 : 파이썬, ChatGPT API, 워드프레스 Rest API 활용 #1

ChatGPT Organization ID, API Keys 얻기 참고 포스팅
  • 답변 생성
res = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)

model: ChatGPT 에는 버전별로 여러 모델이 존재 하는데 “text-davinci-003” 이라는 모델을 사용할 예정이다.

Models – OpenAI API

ChatGPT 버전별 Model 의 자세한 설명이 있는 공식 페이지

prompt: 프롬프트 즉, 우리가 하는 질문 영역이며 실제로 우리가 주제를 던질 부분이다.

max_tokens: 1회 질문에 사용가능한 최대 토큰수를 의미하며 “프롬프트” + “응답 문장” = “최대토큰” 으로 계산이 된다. “text-davinci-003” 모델은 1회에 사용가능한 최대 토큰수는 4,097 tokens 이다.

이 토큰이라는게 처음에는 바이트 단위를 뜻하는 건가 싶었다. 보통 영문은 1바이트, 한글은 2바이트 인데, 토큰 계산기를 돌려보니 전혀 다른 개념인 듯 하다.

“가”, “나” 는 3토큰 인데 “다”, “사” 는 2토큰이다… 단순히 글자수로 계산되는 것이 아닌 것 같으며 토큰 계산은 아래 링크를 통해 확인 해볼 수 있다.

OpenAI Platform – Tokenizer

ChatGPT 토큰 계산기

ChatGPT API 글 생성

코딩에 앞서 꼭 짚고 넘어가야 할 내용이 있다.

인공지능이 발전하는 현시점에는 프롬프트 전문가 라는 직업 역시 생겨났는데 프롬프트 엔지니어, 프롬프트 디자이너 라고도 부른다.

그런데 이런 직업이 왜 생겨났고 왜 필요한 걸까?

아직은 인공지능이 내주는 답변들의 수준이 인간이 보기에는 어색하거나 맞지 않거나 부족한 면이 많기 때문이다.

하지만 같은 주제를 가지고도 어떤 프롬프트를 인공지능에게 질문을 던지냐에 따라서 얻을 수 있는 답의 질이 천차만별로 달라진다.

아캣이는 프롬프트 전문가가 아니다. 그래서 이번 예문에 들어갈 프롬프트는 타 유튜버 분이 작성한 프롬프트를 거의 참조 하였고 아캣이에게 맞게 조금 수정해서 사용 한다는 것을 알아주었으면 한다.

AI 프롬프트는 ChatGPT (openai.com) 에서 여러가지 연습 해보면서 자신의 스타일에 맞는 프롬프트를 만들어내는 것이 중요하다.

글 생성 함수 추가

# ChatGPT 컨텐츠 생성 함수
def generateChatGPT(topic, category, numTags, model='text-davinci-003', maxTokens=3900):

함수 인자 값은 주제, 카테고리, 생성할 태그 갯수, ChatGPT 모델, 최대 토큰 순서로 지정하였다.

제목 생성 코드

주제를 던지면 그 주제를 가지고 제목을 생성 해주는 코드를 작성 해보자.

# ChatGPT 컨텐츠 생성 함수
def generateChatGPT(topic, category, numTags, model='text-davinci-003', maxTokens=3900):
    # ChatGPT API 인증
    openai.organization = "나의 ChatGPT 조직 ID: org-euZ0s47nUy...."
    openai.api_key = "나의 ChatGPT API Key: sk-1tfTO3fW..."

    # 타이틀 생성
    prompt = f"""
        As a very proficient SEO writer, I am writing a blog about {category}.
        Here are 1 potential blog subjects that would fit well with the topic name "{topic}",
        recommend a sentimental title.
    """
    res = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
    title = res["choices"][0]["text"]
    title = title.replace('\n','').replace('\"','').replace('-','').strip()
    print('타이틀 생성 완료')
.
.
.

"""
    메인 프로세스
"""
if __name__ == "__main__":
    # ChatGPT 새 글 생성
    response = generateChatGPT(topic, category, numTags)

대충 이런 형태로 흘러 갈 것이다. 그렇다면 지난 포스팅 소스에서 메인 프로세스 부분을 좀 손봐야 할 것이 있다.

지난 메인 프로세스 코드:

기존 워드프레스 포스팅 기능때 사용했던 값 들은 테스트용 이므로 실제 적용 될 내용은 ChatGPT 에서 만들어진 제목, 내용 등의 값을 받아서 워드프레스 Rest API 에 값을 던져 줄 것이다.

즉, response = generateChatGPT() 함수를 통해 받은 리턴 값 response 를 이용해서 변수 처리를 해주면 된다.

순서상으로는 실제로 먼저 ChatGPT 를 돌려보고 리턴 값을 보고 변수 처리 해야하나 빠른 진행을 위해 먼저 변수 처리를 하도록 하겠다.

"""
    메인 프로세스
"""
if __name__ == "__main__":
    # ChatGPT 새 글 생성
    topic = "제주도의 숨겨진 여행 명소"
    category = "여행"
    numTags = 5
        
    response = generateChatGPT(topic, category, numTags)
        
    # 워드프레스 접속 정보
    userInfo = {
        'url': 'ecat.kr',
        'username': '워드프레스 아이디',
        'password': '워드프레스 비밀번호'
    }

    # 워드프레스 포스팅
    postInfo = {
        'title' : response['title'],
        'contents' : response['contents'],
        'category' : response['category'],
        'tag' : response['tag'],
        'status' : 'draft'
    }

    createPost(userInfo, postInfo)

이와 같이 postInfo = { } 값들은 모두 변수 처리가 되었으며 이제 ChatGPT 에서 만들어진 글 들을 각 요소에 맞게 값 전달만 해주면 워드프레스에 자동으로 포스팅이 될 것이다.

이제 부턴 ChatGPT 함수 부분에 프로세스 만드는 것에 집중하자.

실제로 문장을 만들 것이기 때문에 topic = “글 제목 입니다.” 라는 것 보단 여행에 맞는 주제로 “제주도의 숨겨진 여행 명소” 라고 주제를 변경 하였다.

# ChatGPT 컨텐츠 생성 함수
def generateChatGPT(topic, category, numTags, model='text-davinci-003', maxTokens=3900):
    # ChatGPT API 인증
    openai.organization = "나의 ChatGPT 조직 ID: org-euZ0s47nUy...."
    openai.api_key = "나의 ChatGPT API Key: sk-1tfTO3fW..."

    # 타이틀 생성
    prompt = f"""
        As a very proficient SEO writer, I am writing a blog about {category}.
        Here are 1 potential blog subjects that would fit well with the topic name "{topic}",
        recommend a sentimental title.
    """

    print(prompt)

    res = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
    title = res["choices"][0]["text"]
    title = title.replace('\n','').replace('\"','').replace('-','').strip()

    print(title)
    exit()

그럼 이제 이 부분에서 해당 프롬프트를 넘기게 되면 제대로 값이 나오는지 보도록 하자.

노란 박스에 프롬프트도 잘 만들어 졌고 그 문장안에 “여행”, “제주도의 숨겨진 여행명소 소개” 등등.. 카테고리, 주제 역시 프롬프트에 잘 녹아들어가 있는 것을 볼 수 있다.

이 프롬프트를 던져 주자 ChatGPT 는 “제주도의 따뜻한 추억: 숨겨진 여행의 장소” 라는 감성있는 글의 제목을 만들어 주었다.

이제 이 부분은 나중에 워드프레스 제목 부분에 넣어줄 값이라고 생각하면 된다.

본문 내용 코드

본문 역시도 글 제목을 만들었을때와 기본적인 구조는 같다. 다만 글 내용에 따라서는 조금 후 처리를 해줄 부분들이 존재 하는데 일단은 글 생성 하는 것 부터 순차적으로 진행 해보자.

prompt = f"""
    As a very proficient SEO writer, I am writing a blog about {category}.

    Create a blog for "{topic}". Its category is {category}.

    Write a 2000 word blog article except H1 tag in body tag of html format.
    Contains subtitles and detailed descriptions.
"""
body = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
body = body["choices"][0]["text"]

print(body)
exit()

이런 식으로 글을 해줬다. 하지만 자세히 보니 한가지 문제가 있어보이는게 첫번째 줄에 <H1> 태그를 사용하여 글의 제목을 주고 있다.

포스팅에서 H1 태그는 글의 제목 단 1개여야 하는데 이것은 이미 우리가 위에서 제목을 만들어 냈고 그것을 글의 제목으로 사용 할 것이기 때문에 이 H1 부분이 필요 없기 때문에 없애야 한다.

사실 이 H1 태그를 없애기 위해서 나름 부단히 프롬프트를 수정 해가며 노력 해봤다.

Write a 2000 word blog article except H1 tag in body tag of html format.

하지만 프롬프트 실력이 부족해서 도저히 해결이 안되었다.

그래서 생각한 것이 기술적으로 없애버리자…😅😅
좀 무식한 방법이긴 해도 확실한 방법이긴 하다. 다른 방법이 있는 분은 응용해서 수정 해보는 것도 좋을 것 같다.

아캣이가 생각한 방법은 어짜피 H1 태그 라인만 없애면 되는 거니깐 BeautifulSoup 모듈을 이용해서 없애버리는 것으로 결정 했다.

문서 상단에 모듈 호출 구문 추가

from bs4 import BeautifulSoup

H1 태그 행 삭제 및 불필요 글자 제거 구문 추가

H1 태그를 검색하여 decompose() 함수를 이용해 행을 삭제 해버렸으며, 몇번 돌리다 보니 H 태그들 앞에 간혹 # 이 추가되는 경우도 보여서 이것 역시 삭제 해주는 코드를 추가 하였다.

prompt = f"""
    As a very proficient SEO writer, I am writing a blog about {category}.

    Create a blog for "{topic}". Its category is {category}.

    Write a 2000 word blog article except H1 tag in body tag of html format.
    Contains subtitles and detailed descriptions.
"""
body = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
body = body["choices"][0]["text"]

# 특정 html H1 태그 행 삭제
soup = BeautifulSoup(body, 'html.parser')
for row in soup.select('h1'):
    row.decompose()
body = str(soup)

# 불필요 글자 제거
body = body.replace('#', '')

print(body)
exit()

이제는 H1 제목 라인이 성공적으로 나오지 않는 것을 확인 할 수 있다.

목차 코드 추가

아캣이는 기본적으로 항상 글의 최상단에 목차를 배치시키고 있으며 “럭키WP 목차” 라는 플러그인을 사용하고 있다.

그래서 이 본문을 작성하기에 앞서 제일 앞에 이 목차를 불러오는 html 태그를 추가 해줄 것이다.

목차의 html 태그는 다음과 같이 쉽게 알아올 수 있다.

문서내에 목차를 넣어두고 옵션 > 코드 편집기 로 확인 해보면 쉽게 확인이 가능하다.

# 본문 목차 포함하여 문자열 조합 완성
contents = f"<!-- wp:luckywp/tableofcontents /-->\n{body}"

print(contents)
exit()

위와 같이 작성하면 “목차” + [\n: 다음줄] + “본문내용” 의 형태가 완성이 되는 것이다.

“목차” 태그와 “다음 줄” 이 잘 들어 간 것을 볼 수 있다.

리턴 값 설정

필요한 타이틀과 본문 내용 생성을 하였으니 이 값을 WP Rest API 가 값을 받아서 글이 자동으로 써지도록 리턴 값을 설정 해주자.

# 워드프레스 포스팅
postInfo = {
    'title' : response['title'],
    'contents' : response['contents'],
    'category' : response['category'],
    'tag' : response['tag'],
    'status' : 'draft'
}

메인 프로세스에서 워드프레스에게 넘길 값을 받도록 위에서 이미 만들어 둔 코드이다. 이 형태를 잘 생각해서 각 부분에 맞는 값을 설정 하여 리턴 해줘야 할 것이다.

# 반환 값 설정
response =  {
    'title': title,
    'tag' : "",
    'category' : category,
    'contents' : contents
}

return response

이렇게 지정을 해주면 끝이며, tag 태그 부분은 생각보다 간단히 끝나지 않아서 다음 편에 별도로 다루도록 하겠다. 일단은 공백으로 넘기자.

전체 적용 및 실행 결과 확인

import requests, openai
from bs4 import BeautifulSoup
from time import sleep

# ChatGPT 컨텐츠 생성 함수
def generateChatGPT(topic, category, numTags, model='text-davinci-003', maxTokens=3900):
    # ChatGPT API 인증
    openai.organization = "나의 ChatGPT 조직 ID: org-euZ0s47nUy...."
    openai.api_key = "나의 ChatGPT API Key: sk-1tfTO3fW..."

    # 타이틀 생성
    prompt = f"""
        As a very proficient SEO writer, I am writing a blog about {category}.
        Here are 1 potential blog subjects that would fit well with the topic name "{topic}",
        recommend a sentimental title.
    """
    res = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
    title = res["choices"][0]["text"]
    title = title.replace('\n','').replace('\"','').replace('-','').strip()
    print('타이틀 생성 완료')

    # 본문 응답 프롬프트
    try:
        prompt = f"""
            As a very proficient SEO writer, I am writing a blog about {category}.

            Create a blog for "{topic}". Its category is {category}.

            Write a 2000 word blog article except H1 tag in body tag of html format.
            Contains subtitles and detailed descriptions.
        """
        body = openai.Completion.create(model=model, prompt=prompt, max_tokens=maxTokens)
        body = body["choices"][0]["text"]

        # 특정 html H1 태그 행 삭제
        soup = BeautifulSoup(body, 'html.parser')
        for row in soup.select('h1'):
            row.decompose()
        body = str(soup)

        # 불필요 글자 제거
        body = body.replace('#', '')

        # 본문 목차 포함하여 문자열 조합 완성
        contents = f"<!-- wp:luckywp/tableofcontents /-->\n{body}"

        print('본문 생성 완료')
    except Exception as e:
        print(e)
        return ""

    # 반환 값 설정
    response =  {
        'title': title,
        'tag' : "",
        'category' : category,
        'contents' : contents
    }

    print('ChatGPT 프로세스 완료')

    return response



# 워드프레스 자동 포스팅 함수
def createPost(userInfo, postInfo):
    try:
        print('워드프레스 포스팅 중...')

        # 워드프레스 JWT 인증 토큰 얻기
        url = f"https://{userInfo.get('url')}/wp-json/jwt-auth/v1/token"
        data = {
            'username': userInfo.get('username'),
            'password':userInfo.get('password')
        }
        res = requests.post(url, data=data).json()
        token = res.get('token')

        # 헤더에 JWT 인증 토큰 데이터 추가
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': f'Bearer {token}'
        }

        # 워드프레스 포스팅 데이터 설정
        postURL = f"https://{userInfo.get('url')}/wp-json/wp/v2/posts"
        postData = {
            'title': postInfo.get('title'),
            'slug': postInfo.get('title').replace(' ', '-'),
            'content': postInfo.get('contents'),
            'meta': {
                'category': postInfo.get('category')
            },
            'status': postInfo.get('status')
        }

        # 워드프레스 포스팅 생성 요청 보내기
        response = requests.post(postURL, json=postData, headers=headers)

        print('워드프레스 포스팅 완료')

    except Exception as e:
        print(e)
        return ""


"""
    메인 프로세스
"""
if __name__ == "__main__":
    # ChatGPT 새 글 생성
    topic = "제주도의 숨겨진 여행 명소"
    category = "여행"
    numTags = 5

    response = generateChatGPT(topic, category, numTags)

    # 워드프레스 접속 정보
    userInfo = {
        'url': 'ecat.kr',
        'username': '워드프레스 아이디',
        'password': '워드프레스 비밀번호'
    }

    # 워드프레스 포스팅
    postInfo = {
        'title' : response['title'],
        'contents' : response['contents'],
        'category' : response['category'],
        'tag' : response['tag'],
        'status' : 'draft'
    }

    createPost(userInfo, postInfo)

본문에서 간혹 max token 값이 오버되서 에러가 나는 경우가 있어서 try 문을 적용 시켜 주었고, 워드프레스 함수에도 만에 하나 생길지 모르는 에러를 위해 try 문을 추가 해주었다.


위와 같이 ChatGPT 로 생성 된 글이 워드프레스에 잘 등록이 된 것을 확인 할 수 있다.

마치며

아직 손 볼 곳이 많지만 우리가 목표했던 핵심 기능은 완성이 된 상태이다.

혹시나 글이 너무 짧다거나 내용이 너무 이상하다던가 라는 등의 의문은 이미 위에서 말한 것 처럼 프롬프트의 영역이다. 필자가 진행하는 것은 기능 만드는 부분을 포커스로 강의를 진행 하는 것이라는 점 알아 주었으면 좋겠다.

글이 너무 짧다면 본문을 요약 + 본문 등으로 분할 해서 ChatGPT 에게 각각 따로 답을 얻고 문자열을 조합해서 가져 올 수도 있는 것이다. 이런 응용이 필요한 부분은 스스로가 고민 해보고 코드를 나만의 스타일에 맞게 추가 해보는 것은 어떨까? 😊😊

다음 포스팅에서는 이번에 다루지 못한 태그 생성하는 기능에 대해서 다뤄 보도록 하겠다. 😎😎😎

이전 편: 워드프레스 자동 등록 : 파이썬, ChatGPT API, 워드프레스 Rest API 활용 #2

다음 편: 워드프레스 자동 등록 : 파이썬, ChatGPT API, 워드프레스 Rest API 태그 활용 #4

Posted in 강의

관련 글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다