๐ AI๋ฅผ ์ฌ์ฉํ์ฌ ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ณ ์ต์ ํํ๊ธฐ โ ์๋ก์ด Gato GraphQL v2 ์ฌ์ฉ๋ฒ
Gato GraphQL v2.0์ด ์ถ์๋์์์ ๊ธฐ์๊ฒ ์๋ ค๋๋ฆฝ๋๋ค!
์ด ์ ๋ฒ์ ๊ณผ PRO ํ์ฅ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด, ์์ฑํ AI๋ฅผ ํตํด ์ธ๋ค์ผ์ด ์๋ ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์๋๋ v2.0์ ์ถ๊ฐ๋ ๊ฐ์ฅ ์ค์ํ ๋ณ๊ฒฝ ์ฌํญ์
๋๋ค (๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ํ์ธํ๋ ค๋ฉด GitHub ๋ฆด๋ฆฌ์ค ๋
ธํธ๋ฅผ ์ฐธ์กฐํ์ธ์).
createMediaItem ๋ฎคํ
์ด์
์ถ๊ฐ
createMediaItem ๋ฎคํ
์ด์
์ ๋ฏธ๋์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ์ผ์ ์
๋ก๋ํ ์ ์๊ฒ ํด์ค๋๋ค. ์์ค ํ์ผ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ 2๊ฐ์ง์
๋๋ค:
- URL์ ํตํด
- ์ฝํ ์ธ ๋ฅผ ์ง์ ์ ๋ ฅ
์ด ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฉด:
mutation CreateMediaItems {
fromURL: createMediaItem(input: {
from: {
url: {
source: "https://gatographql.com/assets/GatoGraphQL-logo.png"
}
}
caption: "Gato GraphQL logo"
altText: "This is the Gato GraphQL logo"
}) {
mediaItemID
status
errors {
__typename
...on ErrorPayload {
message
}
}
mediaItem {
...MediaItemData
}
}
directlyByContents: createMediaItem(input: {
from: {
contents: {
body: """
<html>
<body>
Hello world!
</body>
</html>
"""
filename: "hello-world.html"
}
}
title: "Hello world!"
}) {
mediaItemID
status
errors {
__typename
...on ErrorPayload {
message
}
}
mediaItem {
...MediaItemData
}
}
}
fragment MediaItemData on Media {
altText
caption
mimeType
slug
src
title
}...๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์์ฑ๋ฉ๋๋ค:
{
"data": {
"fromURL": {
"mediaItemID": 1380,
"status": "SUCCESS",
"errors": null,
"mediaItem": {
"altText": "This is the Gato GraphQL logo",
"caption": "Gato GraphQL logo",
"mimeType": "image/png",
"slug": "gatographql-logo-png",
"src": "https://mysite.com/wp-content/uploads/GatoGraphQL-logo.png",
"title": "GatoGraphQL-logo.png"
}
},
"directlyByContents": {
"mediaItemID": 1381,
"status": "SUCCESS",
"errors": null,
"mediaItem": {
"altText": "",
"caption": "",
"mimeType": "text/html",
"slug": "hello-world-html",
"src": "https://mysite.com/wp-content/uploads/hello-world.html",
"title": "Hello world!"
}
}
}
}myMediaItemCount, myMediaItems, myMediaItem ํ๋ ์ถ๊ฐ
๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ ์ด์ ์์ ์ ๋ชจ๋ ๋ฏธ๋์ด ํ์ผ์ ์กฐํํ ์ ์์ต๋๋ค.
์ด ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฉด:
query GetMediaItems {
me {
slug
}
myMediaItemCount
myMediaItems(pagination: {
limit: 3
}) {
...MediaItemData
}
myMediaItem(by: { id: 1380 }) {
...MediaItemData
}
}
fragment MediaItemData on Media {
id
mimeType
src
author {
slug
}
}...๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์์ฑ๋ฉ๋๋ค:
{
"data": {
"me": {
"slug": "admin"
},
"myMediaItemCount": 2,
"myMediaItems": [
{
"id": 1380,
"mimeType": "image/png",
"src": "https://mysite.com/wp-content/uploads/GatoGraphQL-logo.png",
"author": {
"slug": "admin"
}
},
{
"id": 1365,
"mimeType": "image/png",
"src": "https://mysite.com/wp-content/uploads/browser.png",
"author": {
"slug": "admin"
}
}
],
"myMediaItem": {
"id": 1380,
"mimeType": "image/png",
"src": "https://mysite.com/wp-content/uploads/GatoGraphQL-logo.png",
"author": {
"slug": "admin"
}
}
}
}[PRO] "AI๋ฅผ ์ฌ์ฉํ์ฌ ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ณ ์ต์ ํํ๊ธฐ" ๋ฏธ๋ฆฌ ์ ์๋ ํผ์์คํฐ๋ ์ฟผ๋ฆฌ ์ถ๊ฐ
(์ด ๊ธฐ๋ฅ์ PRO ํ์ฅ ๊ธฐ๋ฅ์ด ํ์ํฉ๋๋ค.)
"AI๋ฅผ ์ฌ์ฉํ์ฌ ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ณ ์ต์ ํํ๊ธฐ"๋ผ๋ ์ ๋ชฉ์ ์๋ก์ด ๋ฏธ๋ฆฌ ์ ์๋ ํผ์์คํฐ๋ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
์ด ์ฟผ๋ฆฌ๋ ์์ฑํ AI๋ฅผ ์ฌ์ฉํ์ฌ ๋ํ ์ด๋ฏธ์ง๊ฐ ์๋ ๊ฒ์๋ฌผ์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ฉฐ, ๊ฒ์๋ฌผ ์ ๋ชฉ์ ํ๋กฌํํธ๋ก ํ์ฉํฉ๋๋ค. ๋ค์ ์๋น์ค ๊ณต๊ธ์ ์ค์์ ์ ํํ ์ ์์ต๋๋ค:
์ด ์ฟผ๋ฆฌ๋ ๋จผ์ ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๊ฐ ์๋์ง ํ์ธํฉ๋๋ค. ์๋ ๊ฒฝ์ฐ, ์์ฑํ AI ์๋น์ค๋ฅผ ํธ์ถํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์์ฑํฉ๋๋ค. ์ ํํ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ํด๋น API ํค๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
์์ฑํ AI ์ด๋ฏธ์ง๋ ์น์ ์ต์ ํ๋์ด ์์ง ์์ผ๋ฏ๋ก (OpenAI ์ด๋ฏธ์ง๋ 3MB์ ๋ฌํ ์ ์์ต๋๋ค!), ์ฟผ๋ฆฌ๋ ์๋ก ์์ฑ๋ ์ด๋ฏธ์ง๋ฅผ TinyPNG๋ก ์ ์กํ์ฌ ์์ถํฉ๋๋ค. ์ด ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด API ํค๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก, ์ฟผ๋ฆฌ๋ ํด๋น ์ด๋ฏธ์ง๋ก ์ ๋ฏธ๋์ด ํญ๋ชฉ์ ์์ฑํ๊ณ (๊ฒ์๋ฌผ ์ ๋ชฉ์ ์ฒจ๋ถ ํ์ผ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ๋ฉฐ, 20์๋ก ์๋ผ๋), ๊ฒ์๋ฌผ์ ๋ํ ์ด๋ฏธ์ง๋ก ์ค์ ํฉ๋๋ค.
๋ค์์ GraphQL ์ฟผ๋ฆฌ์ ๋๋ค:
query InitializeVariables(
$openAIAPIKey: String
$stableDiffusionAPIKey: String
$tinyPngAPIKey: String
)
@configureWarningsOnExportingDuplicateVariable(enabled: false)
{
isFeaturedImageMissing: _echo(value: false)
@export(as: "isFeaturedImageMissing")
@remove
generatedImageURL: _echo(value: null)
@export(as: "generatedImageURL")
@remove
isImageGenerated: _echo(value: false)
@export(as: "isImageGenerated")
@remove
mimeType: _echo(value: null)
@export(as: "mimeType")
@remove
isMediaItemCreated: _echo(value: false)
@export(as: "isMediaItemCreated")
@remove
useOpenAI: _notEmpty(value: $openAIAPIKey)
@export(as: "useOpenAI")
@remove
useStableDiffusion: _notEmpty(value: $stableDiffusionAPIKey)
@export(as: "useStableDiffusion")
@remove
useTinyPng: _notEmpty(value: $tinyPngAPIKey)
@export(as: "useTinyPng")
@remove
}
query ExportPostData(
$postId: ID!
)
@depends(on: "InitializeVariables")
{
post(by: { id: $postId }) {
hasFeaturedImage
isFeaturedImageMissing: hasFeaturedImage
@boolOpposite
@export(as: "isFeaturedImageMissing")
title
@export(as: "postTitle")
mediaItemFilename: rawTitle
@default(value: "untitled", condition: IS_EMPTY)
@strLowerCase
@strSubstr(offset: 0, length: 20)
@export(as: "filename")
@remove
}
}
query MaybeGenerateImageUsingOpenAI(
$openAIAPIKey: String
$imageSize: String! = "1024x1024" # 256x256, 512x512, or 1024x1024 pixels
)
@depends(on: "ExportPostData")
@include(if: $isFeaturedImageMissing)
@include(if: $useOpenAI)
{
openAIResponse: _sendJSONObjectItemHTTPRequest(input: {
url: "https://api.openai.com/v1/images/generations",
method: POST,
options: {
auth: {
password: $openAIAPIKey
},
json: {
prompt: $postTitle,
size: $imageSize,
n: 1,
response_format: "url",
}
}
})
@underJSONObjectProperty(by: { key: "data" })
@underArrayItem(index: 0)
@underJSONObjectProperty(by: { key: "url" })
@export(as: "generatedImageURL")
openAPIImageCaption: _sprintf(
string: "Image created by DALL-E using prompt: '%s'",
values: [$postTitle]
)
@export(as: "imageCaption")
openAIMediaItemFilename: _sprintf(
string: "%s.png",
values: [$filename]
)
@export(as: "filename")
}
query MaybeGenerateImageUsingStableDiffusion(
$stableDiffusionAPIKey: String
$width: Int! = 1024
$height: Int! = 1024
)
@depends(on: "ExportPostData")
@include(if: $isFeaturedImageMissing)
@include(if: $useStableDiffusion)
{
stableDiffusionResponse: _sendJSONObjectItemHTTPRequest(input: {
url: "https://stablediffusionapi.com/api/v3/text2img",
method: POST,
options: {
json: {
key: $stableDiffusionAPIKey
prompt: $postTitle,
width: $width
height: $height
samples: 1
}
}
})
@underJSONObjectProperty(by: { key: "output" })
@underArrayItem(index: 0)
@export(as: "generatedImageURL")
stableDiffusionImageCaption: _sprintf(
string: "Image created by Stable Diffusion using prompt: '%s'",
values: [$postTitle]
)
@export(as: "imageCaption")
stableDiffusionMediaItemFilename: _sprintf(
string: "%s.png",
values: [$filename]
)
@export(as: "filename")
}
query CheckIsImageGenerated
@depends(on: [
"MaybeGenerateImageUsingOpenAI",
"MaybeGenerateImageUsingStableDiffusion"
])
@include(if: $isFeaturedImageMissing)
{
isImageGenerated: _notEmpty(value: $generatedImageURL)
@export(as: "isImageGenerated")
}
query MaybeCompressGeneratedImage(
$tinyPngAPIKey: String
)
@depends(on: "CheckIsImageGenerated")
@include(if: $isImageGenerated)
@include(if: $useTinyPng)
{
compressedImageResponse: _sendHTTPRequest(input: {
url: "https://api.tinify.com/shrink",
method: POST,
options: {
auth: {
password: $tinyPngAPIKey
},
headers: [
{
name: "Content-Type",
value: "application/json"
}
],
json: {
source: {
url: $generatedImageURL
}
}
}
}) {
body
@remove
bodyJSONObject: _strDecodeJSONObject(string: $__body)
mimeType: _objectProperty(
object: $__bodyJSONObject
by: { path: "output.type" }
)
@export(as: "mimeType")
generatedImageURL: header(name: "Location")
@export(as: "generatedImageURL")
}
}
mutation CreateMediaItemFromGeneratedImage
@depends(on: "MaybeCompressGeneratedImage")
@include(if: $isImageGenerated)
{
createMediaItem(input: {
from: {
url: {
source: $generatedImageURL
filename: $filename
}
}
title: $postTitle
caption: $imageCaption
altText: $postTitle
mimeType: $mimeType
}) {
mediaItemID
@export(as: "mediaItemID")
isMediaItemCreated: _notNull(value: $__mediaItemID)
@export(as: "isMediaItemCreated")
@remove
status
errors {
__typename
...on ErrorPayload {
message
}
}
mediaItem {
altText
caption
mimeType
slug
src
title
}
}
}
mutation SetMediaItemAsPostFeaturedImage(
$postId: ID!
)
@depends(on: "CreateMediaItemFromGeneratedImage")
@include(if: $isMediaItemCreated)
{
setFeaturedImageOnCustomPost(input: {
customPostID: $postId
mediaItemBy: { id: $mediaItemID }
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
customPost {
__typename
...on CustomPost {
featuredImage {
id
altText
caption
mimeType
slug
src
title
}
}
}
}
}[PRO] Helper Function Collection ํ์ฅ ๊ธฐ๋ฅ์ _dataMatrixOutputAsCSV ํ๋ ์ถ๊ฐ
(์ด ๊ธฐ๋ฅ์ PRO ํ์ฅ ๊ธฐ๋ฅ์ ์ถ๊ฐ๋์์ต๋๋ค.)
_dataMatrixOutputAsCSV ํ๋๊ฐ Helper Function Collection ํ์ฅ ๊ธฐ๋ฅ(๋ฐ ํด๋น ํ์ฅ ๊ธฐ๋ฅ์ ํฌํจํ๋ ๋ชจ๋ ๋ฒ๋ค)์ ์ถ๊ฐ๋์์ต๋๋ค.
์ด ํ๋๋ ๋ฐ์ดํฐ ๋งคํธ๋ฆญ์ค๋ฅผ ๋ฐ์ CSV ๋ฌธ์์ด์ ์์ฑํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ค์ ์ฟผ๋ฆฌ๋:
csv: _dataMatrixOutputAsCSV(
fields:
["Name", "Surname", "Year"]
data: [
["John", "Smith", 2003],
["Pedro", "Gonzales", 2012],
["Manuel", "Perez", 2008],
["Jose", "Pereyra", 1999],
["Jacinto", "Bloomberg", 1998],
["Jun-E", "Song", 1983],
["Juan David", "Santamaria", 1943],
["Luis Miguel", null, 1966],
]
)...๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์์ฑ๋ฉ๋๋ค:
{
"data": {
"csv": "Name,Surname,Year\nJohn,Smith,2003\nPedro,Gonzales,2012\nManuel,Perez,2008\nJose,Pereyra,1999\nJacinto,Bloomberg,1998\nJun-E,Song,1983\nJuan David,Santamaria,1943\nLuis Miguel,,1966\n"
}
}์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด WordPress ์ฌ์ดํธ์ ๋ฐ์ดํฐ๋ฅผ Google ์คํ๋ ๋์ํธ ๋ฑ์ผ๋ก ๋ด๋ณด๋ผ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋ค์ ์ฟผ๋ฆฌ๋ 100๊ฐ ๊ฒ์๋ฌผ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ID, Title, Slug, Author name, Published date, URL, Content ์ด์ด ํฌํจ๋ CSV ํ์ผ์ ์์ฑํ๊ณ ๋ฏธ๋์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์
๋ก๋ํฉ๋๋ค:
query ExportPostData(
$limit: Int! = 100,
$offset: Int! = 0
) {
posts(
pagination: { limit: $limit, offset: $offset },
sort: { by: ID, order: ASC }
) {
id @export(as: "postIds", type: LIST)
title @export(as: "postTitles", type: LIST)
slug @export(as: "postSlugs", type: LIST)
author {
name @export(as: "postAuthorNames", type: LIST)
}
dateStr(format: "d/m/Y") @export(as: "postPublishedDates", type: LIST)
url @export(as: "postUrls", type: LIST)
content @export(as: "postContents", type: LIST)
}
}
query CreateDataMatrix
@depends(on: "ExportPostData")
{
csvDataMatrix: _echo(value: $postIds)
@underEachArrayItem(
passIndexOnwardsAs: "key"
passValueOnwardsAs: "postId"
affectDirectivesUnderPos: [1, 2, 3, 4, 5, 6, 7]
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postTitles,
position: $key,
},
passOnwardsAs: "postTitle"
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postSlugs,
position: $key,
},
passOnwardsAs: "postSlug"
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postAuthorNames,
position: $key,
},
passOnwardsAs: "postAuthorName"
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postPublishedDates,
position: $key,
},
passOnwardsAs: "postPublishedDate"
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postUrls,
position: $key,
},
passOnwardsAs: "postUrl"
)
@applyField(
name: "_arrayItem",
arguments: {
array: $postContents,
position: $key,
},
passOnwardsAs: "postContent"
)
@applyField(
name: "_echo",
arguments: {
value: [
$postId,
$postTitle,
$postSlug,
$postAuthorName,
$postPublishedDate,
$postUrl,
$postContent
]
},
setResultInResponse: true
)
@export(as: "csvDataMatrix")
}
query OutputCSV
@depends(on: "CreateDataMatrix")
{
csvString: _dataMatrixOutputAsCSV(
fields: [
"ID",
"Title",
"Slug",
"Author name",
"Published date",
"URL",
"Content",
]
data: $csvDataMatrix
)
@export(as: "csvString")
}
mutation CreateMediaItem
@depends(on: "OutputCSV")
{
createMediaItem(input: {
from: {
contents: {
body: $csvString
filename: "posts.csv"
}
}
title: "Post data as CSV"
}) {
mediaItemID
status
errors {
__typename
...on ErrorPayload {
message
}
}
mediaItem {
mimeType
slug
src
title
}
}
}v3.0์ ์ค๋นํ๋ฉฐ
์ด๋ฒ ์ต์ ๋ฆด๋ฆฌ์ค์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ฆ๊ฒจ ์ฌ์ฉํ์๊ธธ ๋ฐ๋๋๋ค.
Gato GraphQL์ ์ถ๊ฐ๋์์ผ๋ฉด ํ๋ ์๋ก์ด ๊ธฐ๋ฅ์ด ์์ผ์ ๊ฐ์? ๋ฉ์์ง๋ฅผ ๋ณด๋ด์ฃผ์ธ์.
์ฆ๊ฒ๊ฒ ์ฌ์ฉํ์ธ์!