Blog

๐Ÿš€ Hasilkan dan optimalkan gambar unggulan postingan menggunakan AI, dengan Gato GraphQL v2 yang baru

Leonardo Losoviz
Oleh Leonardo Losoviz ยท

Kami dengan senang hati mengumumkan bahwa Gato GraphQL v2.0 kini telah dirilis!

Dengan versi baru ini, dan ekstensi PRO, Anda dapat menggunakan AI generatif untuk membuat gambar unggulan bagi postingan yang belum memiliki thumbnail.

Berikut adalah perubahan terpenting yang ditambahkan pada v2.0 (untuk melihat semua perubahan, kunjungi catatan rilis di GitHub).

Ditambahkan mutasi createMediaItem

Mutasi createMediaItem memungkinkan pengunggahan file ke Perpustakaan Media. Terdapat 2 cara untuk menyediakan file sumber:

  1. Melalui URL
  2. Langsung dengan kontennya

Menjalankan query ini:

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
}

...akan menghasilkan:

{
  "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!"
      }
    }
  }
}

Ditambahkan field myMediaItemCount, myMediaItems dan myMediaItem

Pengguna yang sudah masuk kini dapat mengambil semua file media mereka.

Menjalankan query ini:

query GetMediaItems {
  me {
    slug
  }
  
  myMediaItemCount
 
  myMediaItems(pagination: {
    limit: 3
  }) {
    ...MediaItemData
  }
 
  myMediaItem(by: { id: 1380 }) {
    ...MediaItemData
  }
}
 
fragment MediaItemData on Media {
  id
  mimeType
  src
  author {
    slug
  }
}

...akan menghasilkan:

{
  "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"
      }
    }
  }
}

(Fungsionalitas ini memerlukan ekstensi PRO.)

Persisted query bawaan baru, dengan judul "Generate a post's featured image using AI and optimize it", telah ditambahkan.

Fitur ini menggunakan AI generatif untuk membuat gambar bagi postingan yang belum memiliki gambar unggulan, menggunakan judul postingan sebagai prompt. Kita dapat memilih dari penyedia layanan berikut:

Query pertama-tama memeriksa apakah sebuah postingan memiliki gambar unggulan. Jika belum ada, query akan membuatnya dengan memanggil layanan AI generatif. Kita harus menyediakan API key yang sesuai untuk layanan yang dipilih.

Karena gambar AI generatif tidak dioptimalkan untuk web (gambar dari OpenAI bisa berbobot 3MB!), query juga mengirimkan gambar yang baru dihasilkan ke TinyPNG untuk dikompres. Kita harus menyediakan API key untuk menggunakan layanan ini.

Terakhir, query membuat item media baru dengan gambar tersebut (menggunakan judul postingan sebagai nama file untuk lampiran, dipotong hingga 20 karakter), dan menetapkannya sebagai gambar unggulan postingan.

Ini adalah query GraphQL-nya:

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] Ditambahkan field _dataMatrixOutputAsCSV pada ekstensi Helper Function Collection

(Fungsionalitas ini ditambahkan ke ekstensi PRO.)

Field _dataMatrixOutputAsCSV telah ditambahkan ke ekstensi Helper Function Collection (dan semua bundle yang berisi ekstensi ini).

Field ini mengambil matriks data, dan menghasilkan string CSV. Misalnya, query ini:

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],
  ]
)

...akan menghasilkan:

{
  "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"
  }
}

Fungsionalitas ini memungkinkan kita untuk mengekspor data dari situs WordPress kita ke Google Sheets atau yang lainnya.

Misalnya, query ini akan mengambil data untuk 100 postingan, dan membuat file CSV yang diunggah ke Perpustakaan Media, dengan kolom ID, Title, Slug, Author name, Published date, URL, dan Content:

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
    }
  }
}

Persiapan menuju v3.0

Kami berharap Anda menikmati fitur-fitur baru dalam rilis terbaru ini.

Apakah ada fitur baru yang ingin Anda lihat di Gato GraphQL berikutnya? Kirimkan pesan kepada kami dan beri tahu kami.

Selamat menikmati!


Berlangganan newsletter kami

Tetap update dengan semua pembaruan Gato GraphQL.