【改】【GAS】RSSフィードから最新のニュースをWordPress へ投稿する(アイキャッチ自動生成)

作ったもの紹介

DALL-E-3がAPI利用できるようになったので、さっそく以前作った「アイキャッチ自動生成して自動ブログ投稿する」ためのGASスクリプトを書き換えた。
(サイドバーに載せてるサイトです。)
画像の質がだいぶ向上したと個人的には思います。


どうですかね?(画質が悪すぎますね。サイトから直接見てもらったほうが分かりやすいかも)

ついでに、以前の無知だった頃から一歩進化したので、varを使ってた部分を全部constとletを使うように直した。

過去記事
【GAS】RSSフィードから最新のニュースをWordPress へ投稿する(アイキャッチ自動生成) https://laketonem.org/gasrassposttowp/

目次

DALL-E-3利用部分の改変

以前のコード

/**
 * DALL·Eで画像を生成する関数
 * @param {string} prompt - DALL·Eに送信するプロンプト
 * @return {string} 生成された画像のURL
 */
function requestDallEImage(prompt) {
  const apiUrl = 'https://api.openai.com/v1/images/generations';
  let headers = {
    'Authorization':'Bearer '+ OPENAI_APIKEY,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  let options = {
    'muteHttpExceptions' : true,
    'headers': headers, 
    'method': 'POST',
    'payload': JSON.stringify({
      'n': 1,
      'size' : '1024x1024',
      'prompt': prompt})
  };
  const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
  const response = JSON.parse(responseText);

  // APIの応答をログに出力
  Logger.log(responseText);

  // 応答の形式を確認
  if (!response.data || !response.data[0] || !response.data[0].url) {
    throw new Error('Unexpected API response.');
  }

  return response.data[0].url;
}

DALL-E-3利用に改変。

function requestDallEImage(prompt) {
const apiUrl = 'https://api.openai.com/v1/images/generations';
const headers = {
'Authorization': 'Bearer ' + OPENAI_APIKEY,
'Content-type': 'application/json'
};
const options = {
'muteHttpExceptions': true,
'headers': headers,
'method': 'POST',
'payload': JSON.stringify({
'model': 'dall-e-3', // モデルをDALL-E 3に設定
'prompt': prompt,
'n': 1, // DALL-E 3は現時点でn=1のみをサポート
'size': '1024x1024', // DALL-E 3のサポートするサイズ
// 以下のパラメータはDALL-E 3専用
'quality': 'standard', // 'hd' と 'standard' から選択可能
'style': 'vivid' // 'vivid' と 'natural' から選択可能
})
};
const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
const response = JSON.parse(responseText);

Logger.log(responseText);

if (!response.data || !response.data[0] || !response.data[0].url) {
throw new Error('Unexpected API response.');
}

return response.data[0].url;
}

改良版コード全体

// OpenAIのAPIキーとWordPressのユーザー名とパスワードを環境変数から取得
const OPENAI_APIKEY = PropertiesService.getScriptProperties().getProperty('OPENAI_APIKEY');
const WP_USERNAME = PropertiesService.getScriptProperties().getProperty('WP_USERNAME');
const WP_PASSWORD = PropertiesService.getScriptProperties().getProperty('WP_PASSWORD');
const SITE_URL = 'YOUR_WORDPRESS_SITE_URL'; // WordPressのサイトURLをここで定義

// APIリクエスト用の共通ヘッダーを生成する関数
const getAuthHeaders = () => ({
  "Authorization": "Basic " + Utilities.base64Encode(WP_USERNAME + ':' + WP_PASSWORD)
});

/**
 * WordPressに最新のAI関連ニュースを投稿する関数
 */
function postToWordPress() {
  // GoogleアラートのRSSフィードのURLリスト
  const rssFeedUrls = [
    'RSS_FEED_URL_1',
    'RSS_FEED_URL_2',
    'RSS_FEED_URL_3'
  ];

  const apiEndpoint = '/wp-json/wp/v2/posts';
  const headers = getAuthHeaders(); // 共通ヘッダーを使用

  let allEntries = [];

  rssFeedUrls.forEach((url) => {
    const xml = UrlFetchApp.fetch(url).getContentText();
    const document = XmlService.parse(xml);
    const root = document.getRootElement();
    const atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');

    const entries = root.getChildren('entry', atom);
    entries.forEach((entry) => {
      const title = entry.getChild('title', atom).getText();
      const link = entry.getChild('link', atom).getAttribute('href').getValue();
      const published = entry.getChild('published', atom).getText();

      allEntries.push({
        title: title,
        link: link,
        published: new Date(published)
      });
    });
  });

  allEntries.sort((a, b) => b.published - a.published);

  const topEntries = allEntries.slice(0, 20);
  const titleList = topEntries.map((entry) => '- ' + entry.title).join('\n');

  const gptPrompt = "Summarize the overarching theme or trend from the entire list of news titles provided in one single sentence.: " + "\n" + titleList;
  const gptResponse = requestGpt35Completion(gptPrompt);
  const dallEImageURL = requestDallEImage(gptResponse);
  const imageBlob = UrlFetchApp.fetch(dallEImageURL).getBlob();
  const imageId = uploadImageToWordpress(imageBlob);
  const content = topEntries.map((entry) => `<p><a href="${entry.link}">${entry.title}</a> (${entry.published})</p>`).join('');

  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;
  const day = now.getDate();
  const weekDay = ["日", "月", "火", "水", "木", "金", "土"][now.getDay()];
  const hours = now.getHours();
  const formattedDate = `【${month < 10 ? '0' : ''}${month}/${day < 10 ? '0' : ''}${day}/${weekDay}/${hours < 10 ? '0' : ''}${hours}時】現時点でのAI関連最新ニュース一覧【${year}】`;

  const data = {
    title: formattedDate,
    content: content,
    status: 'publish',
    categories: [2],
    featured_media: imageId
  };

  UrlFetchApp.fetch(`${SITE_URL}${apiEndpoint}`, {
    method: 'POST',
    headers: headers,
    payload: JSON.stringify(data),
    contentType: 'application/json'
  });
}

function requestGpt35Completion(prompt) {
  const apiUrl = 'https://api.openai.com/v1/chat/completions';
  const headers = {
    'Authorization': 'Bearer ' + OPENAI_APIKEY,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  const options = {
    'muteHttpExceptions': true,
    'headers': headers,
    'method': 'POST',
    'payload': JSON.stringify({
      'model': 'gpt-3.5-turbo',
      'max_tokens': 1000,
      'temperature': 0.9,
      'messages': [{'role': 'user', 'content': prompt}]
    }),
  };
  const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
  const response = JSON.parse(responseText);
  
  if (response && response.choices && response.choices[0] && response.choices[0].message && response.choices[0].message.content) {
    return response.choices[0].message.content;
  } else {
    Logger.log(responseText);
    throw new Error('Unexpected GPT-3 API response.');
  }
}

function requestDallEImage(prompt) {
  const apiUrl = 'https://api.openai.com/v1/images/generations';
  const headers = {
    'Authorization': 'Bearer ' + OPENAI_APIKEY,
    'Content-type': 'application/json'
  };
  const options = {
    'muteHttpExceptions': true,
    'headers': headers,
    'method': 'POST',
    'payload': JSON.stringify({
      'model': 'dall-e-3', // モデルをDALL-E 3に設定
      'prompt': prompt,
      'n': 1, // DALL-E 3は現時点でn=1のみをサポート
      'size': '1024x1024', // DALL-E 3のサポートするサイズ
      // 以下のパラメータはDALL-E 3専用
      'quality': 'standard', // 'hd' と 'standard' から選択可能
      'style': 'vivid' // 'vivid' と 'natural' から選択可能
    })
  };
  const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
  const response = JSON.parse(responseText);

  Logger.log(responseText);

  if (!response.data || !response.data[0] || !response.data[0].url) {
    throw new Error('Unexpected API response.');
  }

  return response.data[0].url;
}

/**
 * 画像をWordPressにアップロードする関数
 * @param {Blob} blob - アップロードする画像のBlob
 * @return {number} アップロードされた画像のID
 */
function uploadImageToWordpress(blob) {
  const apiEndpoint = '/wp-json/wp/v2/media';
  const headers = {
    ...getAuthHeaders(),
    "Content-Disposition": 'attachment; filename="image.png"'
  };
  const options = {
    method: 'POST',
    headers: headers,
    payload: blob,
    muteHttpExceptions: true
  };
  const response = UrlFetchApp.fetch(`${SITE_URL}${apiEndpoint}`, options);
  const responseData = JSON.parse(response.getContentText());
  return responseData.id;
}

/**
 * WordPressからメディアのURLを取得する関数
 * @param {number} mediaId - 取得するメディアのID
 * @return {string} メディアのURL
 */
function getMediaUrl(mediaId) {
  const apiEndpoint = '/wp-json/wp/v2/media/' + mediaId;
  const headers = getAuthHeaders();
  const options = {
    method: 'GET',
    headers: headers,
    muteHttpExceptions: true
  };
  const response = UrlFetchApp.fetch(`${SITE_URL}${apiEndpoint}`, options);
  const responseData = JSON.parse(response.getContentText());
  return responseData.source_url;
}

以前のコード

/**
 * WordPressに投稿するためのGASスクリプト
 */
// OpenAIのAPIキーとWordPressのユーザー名とパスワードを環境変数から取得
const OPENAI_APIKEY = PropertiesService.getScriptProperties().getProperty('OPENAI_APIKEY');
const WP_USERNAME = PropertiesService.getScriptProperties().getProperty('WP_USERNAME');
const WP_PASSWORD = PropertiesService.getScriptProperties().getProperty('WP_PASSWORD');
/**
 * WordPressに最新のAI関連ニュースを投稿する関数
 */
function postToWordPress() {
  // GoogleアラートのRSSフィードのURLリスト
  var rssFeedUrls = [
    'RSS_FEED_URL_1',
    'RSS_FEED_URL_2',
    'RSS_FEED_URL_3'
  ];
  // WordPressのサイトURLとAPIエンドポイント
  var siteUrl = 'YOUR_WORDPRESS_SITE_URL';
  var apiEndpoint = '/wp-json/wp/v2/posts';
  // 認証ヘッダーの設定
  var headers = {
    "Authorization": "Basic " + Utilities.base64Encode(WP_USERNAME + ':' + WP_PASSWORD)
  };
  var allEntries = [];
  // 各RSSフィードからエントリを取得
  rssFeedUrls.forEach(function(url) {
    var xml = UrlFetchApp.fetch(url).getContentText();
    var document = XmlService.parse(xml);
    var root = document.getRootElement();
    var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');
    var entries = root.getChildren('entry', atom);
    entries.forEach(function(entry) {
      var title = entry.getChild('title', atom).getText();
      var link = entry.getChild('link', atom).getAttribute('href').getValue();
      var published = entry.getChild('published', atom).getText();
      allEntries.push({
        title: title,
        link: link,
        published: new Date(published)
      });
    });
  });
  // エントリを公開日時でソート
  allEntries.sort(function(a, b) {
    return b.published - a.published;
  });
  // 上位20件のエントリを取得
  var topEntries = allEntries.slice(0, 20);
  var titleList = topEntries.map(function(entry) {
    return '- ' + entry.title;
  }).join('\n');
  // GPT-3.5でニュースタイトルの要約を取得
  var gptPrompt = "Summarize the overarching theme or trend from the entire list of news titles provided in one single sentence.: " + "\n" + titleList;
  var gptResponse = requestGpt35Completion(gptPrompt);
  // DALL·Eで画像を生成
  var dallEImageURL = requestDallEImage(gptResponse);
  var imageBlob = UrlFetchApp.fetch(dallEImageURL).getBlob();
  // 画像をWordPressにアップロード
  var imageId = uploadImageToWordpress(imageBlob);
  // 投稿のコンテンツを作成
  var content = topEntries.map(function(entry) {
    return '' + entry.title + ' (' + entry.published + ')';
  }).join('');
  // 投稿のタイトルを現在の日時でフォーマット
  var now = new Date();
  var year = now.getFullYear();
  var month = now.getMonth() + 1;
  var day = now.getDate();
  var weekDay = ["日", "月", "火", "水", "木", "金", "土"][now.getDay()];
  var hours = now.getHours();
  var formattedDate = '【' + (month < 10 ? '0' : '') + month + '/' + (day < 10 ? '0' : '') + day + '/' + weekDay + '/' + (hours < 10 ? '0' : '') + hours + '時】現時点でのAI関連最新ニュース一覧【' + year + '】';
  // 投稿データを設定
  var data = {
    title: formattedDate,
    content: content,
    status: 'publish',
    categories: [2],
    featured_media: imageId
  };
  // WordPressに投稿
  UrlFetchApp.fetch(siteUrl + apiEndpoint, {
    method: 'POST',
    headers: headers,
    payload: JSON.stringify(data),
    contentType: 'application/json'
  });
}
/**
 * GPT-3.5での完了リクエストを行う関数
 * @param {string} prompt - GPT-3.5に送信するプロンプト
 * @return {string} GPT-3.5の応答
 */
function requestGpt35Completion(prompt) {
  const apiUrl = 'https://api.openai.com/v1/chat/completions';
  const headers = {
    'Authorization':'Bearer '+ OPENAI_APIKEY,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  const options = {
    'muteHttpExceptions' : true,
    'headers': headers,
    'method': 'POST',
    'payload': JSON.stringify({
      'model': 'gpt-3.5-turbo',
      'max_tokens' : 1000,
      'temperature' : 0.9,
      'messages': [{'role': 'user', 'content': prompt}]}),
  };
  const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
  const response = JSON.parse(responseText);
  // 応答の形式を確認
  if (response && response.choices && response.choices[0] && response.choices[0].message && response.choices[0].message.content) {
    return response.choices[0].message.content;
  } else {
    // デバッグのための完全な応答をログに出力
    Logger.log(responseText);
    throw new Error('Unexpected GPT-3 API response.');
  }
}
/**
 * DALL·Eで画像を生成する関数
 * @param {string} prompt - DALL·Eに送信するプロンプト
 * @return {string} 生成された画像のURL
 */
function requestDallEImage(prompt) {
  const apiUrl = 'https://api.openai.com/v1/images/generations';
  let headers = {
    'Authorization':'Bearer '+ OPENAI_APIKEY,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  let options = {
    'muteHttpExceptions' : true,
    'headers': headers,
    'method': 'POST',
    'payload': JSON.stringify({
      'n': 1,
      'size' : '1024x1024',
      'prompt': prompt})
  };
  const responseText = UrlFetchApp.fetch(apiUrl, options).getContentText();
  const response = JSON.parse(responseText);
  // APIの応答をログに出力
  Logger.log(responseText);
  // 応答の形式を確認
  if (!response.data || !response.data[0] || !response.data[0].url) {
    throw new Error('Unexpected API response.');
  }
  return response.data[0].url;
}
/**
 * 画像をWordPressにアップロードする関数
 * @param {Blob} blob - アップロードする画像のBlob
 * @return {number} アップロードされた画像のID
 */
function uploadImageToWordpress(blob) {
  var siteUrl = 'YOUR_WORDPRESS_SITE_URL';
  var apiEndpoint = '/wp-json/wp/v2/media';
  var headers = {
    "Authorization": "Basic " + Utilities.base64Encode(WP_USERNAME + ':' + WP_PASSWORD),
    "Content-Disposition": 'attachment; filename="image.png"'
  };
  var options = {
    method: 'POST',
    headers: headers,
    payload: blob,
    muteHttpExceptions: true
  };
  var response = UrlFetchApp.fetch(siteUrl + apiEndpoint, options);
  var responseData = JSON.parse(response.getContentText());
  return responseData.id;
}
/**
 * WordPressからメディアのURLを取得する関数
 * @param {number} mediaId - 取得するメディアのID
 * @return {string} メディアのURL
 */
function getMediaUrl(mediaId) {
  var siteUrl = 'YOUR_WORDPRESS_SITE_URL';
  var apiEndpoint = '/wp-json/wp/v2/media/' + mediaId;
  var headers = {
    "Authorization": "Basic " + Utilities.base64Encode(WP_USERNAME + ':' + WP_PASSWORD)
  };
  var options = {
    method: 'GET',
    headers: headers,
    muteHttpExceptions: true
  };
  var response = UrlFetchApp.fetch(siteUrl + apiEndpoint, options);
  var responseData = JSON.parse(response.getContentText());
  return responseData.source_url;
}

コメント

タイトルとURLをコピーしました