Blog

🚀 Generuj i optymalizuj wyróżniony obraz posta za pomocą AI, z nowym Gato GraphQL v2

Leonardo Losoviz
Autor: Leonardo Losoviz ·

Z przyjemnością ogłaszamy, że Gato GraphQL v2.0 zostało wydane!

Dzięki tej nowej wersji i rozszerzeniom PRO możesz używać generatywnej AI do tworzenia wyróżnionych obrazów dla postów, które nie mają miniatury.

Poniżej znajdują się najważniejsze zmiany dodane w v2.0 (aby zobaczyć wszystkie zmiany, przejdź do informacji o wydaniu na GitHub).

Dodano mutację createMediaItem

Mutacja createMediaItem umożliwia przesyłanie plików do Biblioteki multimediów. Oferuje 2 sposoby dostarczenia pliku źródłowego:

  1. Przez URL
  2. Bezpośrednio z jego zawartości

Wykonanie tego zapytania:

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
}

...wyprodukuje:

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

Dodano pola myMediaItemCount, myMediaItems i myMediaItem

Zalogowani użytkownicy mogą teraz pobierać wszystkie swoje pliki multimedialne.

Wykonanie tego zapytania:

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

...wyprodukuje:

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

(Ta funkcjonalność wymaga rozszerzeń PRO.)

Nowe predefiniowane utrwalone zapytanie z tytułem "Generate a post's featured image using AI and optimize it" zostało dodane.

Używa generatywnej AI do tworzenia obrazów dla postów bez wyróżnionego obrazu, korzystając z tytułu posta jako promptu. Możemy wybrać spośród następujących dostawców usług:

Zapytanie najpierw sprawdza, czy post ma wyróżniony obraz. Jeśli nie ma, tworzy go, wywołując usługę generatywnej AI. Musimy podać odpowiedni klucz API dla wybranej usługi.

Ponieważ obrazy generatywnej AI nie są zoptymalizowane dla sieci (obrazy OpenAI mogą ważyć nawet 3 MB!), zapytanie wysyła również nowo wygenerowany obraz do TinyPNG, aby go skompresować. Musimy podać klucz API do korzystania z tej usługi.

Na koniec zapytanie tworzy nowy element multimedialny z obrazem (używając tytułu posta jako nazwy pliku dla załącznika, obciętego do 20 znaków) i ustawia go jako wyróżniony obraz posta.

Oto zapytanie 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] Dodano pole _dataMatrixOutputAsCSV w rozszerzeniu Helper Function Collection

(Ta funkcjonalność została dodana do rozszerzeń PRO.)

Pole _dataMatrixOutputAsCSV zostało dodane do rozszerzenia Helper Function Collection (i wszystkich pakietów zawierających to rozszerzenie).

To pole przyjmuje macierz danych i produkuje ciąg CSV. Na przykład to zapytanie:

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

...wyprodukuje:

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

Ta funkcjonalność pozwala nam eksportować dane z naszej witryny WordPress do Google Sheets lub innych narzędzi.

Na przykład to zapytanie pobierze dane 100 postów i utworzy plik CSV, który zostanie przesłany do Biblioteki multimediów, z kolumnami ID, Title, Slug, Author name, Published date, URL i 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
    }
  }
}

Przygotowanie do v3.0

Mamy nadzieję, że spodoba ci się nowe funkcje w tej najnowszej wersji.

Czy jest jakaś nowa funkcja, którą chciałbyś, aby Gato GraphQL miało w przyszłości? Wyślij nam wiadomość i daj nam znać.

Ciesz się!


Zapisz się do naszego newslettera

Bądź na bieżąco ze wszystkimi aktualizacjami Gato GraphQL.