![]() |
こんにちは、SCSKの木澤です。
夏休みクラウド自由研究2025も最後の記事ですね。
アクセス頂いた皆様、記事投稿にご協力いただいた皆様、ありがとうございました。
今年の投稿を総括すると、特にAWSエンジニアからAmazon Q Developer CLIやKiroを用いてVibe Codingにチャレンジしてみた系の記事発信が多かったですね。
Kiroは仕様(Spec)駆動開発と、弊社のようなSIerのシステム開発手法に馴染みある開発手法に近いので私も期待しています。
自社のシステム開発(アプリケーション開発)に直接適用するには、まだハードルはあると感じますが、インフラ系の部署に所属する属するメンバーが多いTechHarmonyへの寄稿者(登録者)からの発信が多いことを踏まえると、今後の変革に期待できるなと思いました。
さて、今日は本サイトのようなWordPressサイトの管理業務を少しだけ改善する話をしたいと思います。
はじめに
本サイトはCMSとしてWordPressを利用しているのですが、WordPressでの記事の寄稿においては記事のタイトルと本文以外にも設定が必要な項目が多数あります。主なものとしては
- カテゴリ設定
- タグの付与
- メタディスクリプション(記事概要文)の入力
- アイキャッチ画像の設定
特にアイキャッチ画像については作成が多少面倒なところもあり、寄稿者からの設定が漏れていることが多いかと思います。
本サイトでも一旦差し戻して設定をお願いしていますが、アイキャッチ画像は記事の本質的な部分でも無いので

寄稿者の手間を煩わすのもなぁ…
というのが、当サイトのレビュー担当者としての感覚でした。
そこで今回は生成AIを利用してアイキャッチ画像の自動生成にチャレンジしてみたいと思います。
アーキテクチャ
WordPress投稿時に自動的にCloudFrontのキャッシュクリアを行う方法について投稿について以前に記事化していますが、基本の仕組みとしては同じです。
今回はアイキャッチ画像が設定されていない際に、以下の処理を行い要件を満たすことにします。
- 記事本文から要約文を作成
- 要約文からアイキャッチ画像を作成
- 作成された画像をWordPressサイトのメディアライブラリにアップロード
- 当該記事にアイキャッチ画像を付与
なお今回、Amazon Bedrock上のLLMモデルにはAmazon Novaを利用しました
- 要約:Amazon Nova Pro
- 画像生成:Amazon Nova Canvas
要約する際に渡すプロンプトは以下のようにしました。
以下のブログ記事を要約して、200文字程度の紹介文形式にしてください (本文)
画像生成の際のプロンプトは以下のようにしました。
あなたは優秀なWebデザイナーです。 技術ブログの記事「(タイトル)」のアイキャッチ画像を作成してください。 記事の概要文は以下の通りです。 (概要)
設定方法
今回の手順の概要は以下の通りです。
- WordPressサイトのアプリケーションパスワードを取得
- Amazon Bedrock上でモデルアクセスを有効化
- IAMロールを作成
- Systems Managerパラメーターストアにプロンプトを保存
- RequestsとBeattifulSoupを含んだLambdaレイヤーを作成
- Lambda関数を作成し、レイヤーを割り当て、環境変数を設定
- API Gatewayを設定しLambdaと紐付け
- WP Webhooksから呼び出す設定
WordPressアプリケーションパスワード取得
メディアライブラリへのアップロード及び記事の更新にWordPressのREST APIを利用します。
ユーザプロフィール内のアプリケーションパスワードでパスワードを発行しておきます。
Amazon Bedrockのモデルアクセス有効化
前述の通り、今回は Nova ProとNova Canvasを用います。
東京リージョンのNova Proはオンデマンド呼び出しに対応していないようなので、今回は別々のリージョンにしました。
- Nova Pro : 北バージニアリージョン(us-east-1)
- Nova Canvas:東京リージョン(ap-northeast-1)
IAMロール作成
最小権限の法則に則りIAMロールを作成します。
今回の仕組みの場合、IAMロールに与えるポリシーは以下となります。
- AWS Systems Manager(Parameter Store)からの値の取得
- ssm:GetParameterHistory
- ssm:GetParametersByPath
- ssm:GetParameters
- ssm:GetParameter
- Amazon Bedrockでの推論実行
- bedrock:InvokeModel
- CloudWatch Logsへのログ送信
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvent
Systems Managerパラメーターストアにプロンプトを保存
今回は2回LLMを呼び出しますので、2つのストアを作成します。
要約用プロンプト
新規にtextデータ形式のパラメータストアを作成し、以下の文書を入力します。
以下のブログ記事を要約して、200文字程度の紹介文形式にしてください (本文)
画像生成用プロンプト
同様に以下の文書を入力します。
あなたは優秀なWebデザイナーです。 技術ブログの記事「(タイトル)」のアイキャッチ画像を作成してください。 記事の概要文は以下の通りです。 (概要)
Lambdaレイヤーを作成
後述のLambda関数では、Pythonプログラムの外部ライブラリとしてRequestsとBeattifulSoupを利用していますので、Lambdaレイヤーを作成します。
CloudShellにログインし、以下のようにコマンドを実行します。
$ mkdir ~/python $ cd python $ pip install beautifulsoup4 requests -t . $ cd $ zip -r lambda-layer.zip ./python
CloudShellのアクションボタンからファイルのダウンロードができますので
~/lambda-layer.zip と指定しダウンロードします。
続いてLambdaのAWSコンソールよりレイヤーを作成します。
互換設定はもう少しシビアに見た方が良いと思いますが。
Lambda関数の作成
いよいよLambda関数を作成します。
Python 3.13で新規関数を作成し、上述で設定したIAMロールを割り当てます。
ソースコードは以下のようにしました。
import os import boto3 import json import base64 import random import requests from datetime import datetime from bs4 import BeautifulSoup # boto3の初期設定 bedrock = boto3.client('bedrock-runtime', 'us-east-1') ssm = boto3.client('ssm', 'ap-northeast-1') def lambda_handler(event, context): # メタディスクリプションが未設定の場合に実行 if event['post_thumbnail'] == 0: result = create_eyecatch(event) else: result = {"message":"Eyecatch image was exists."} print(result) return { 'statusCode': 200, 'body': result } def create_eyecatch(event): # ブログ本文から文字列抽出 soup = BeautifulSoup(event['post']['post_content'], 'html.parser') title = event['post']['post_title'] texts = soup.get_text() # WordPressの記事IDを取得 postid = event['post_id'] # Bedrockで要約を実施 summary = get_summary(texts) # 画像を生成 image = create_image(title,summary) # WordPressのメディアライブラリにアップロード imageid = upload_media(postid, image) # 記事を更新 result = update_post(postid, imageid) return imageid def get_summary(texts): # AWS Systems Managerパラメータストアの読み込み pstore = os.environ['PARAMETER_STORE1'] prompt = ssm.get_parameters(Names=[pstore])['Parameters'][0]['Value'].replace('(本文)',texts) # Amazon Bedrockで要約する modelId = 'amazon.nova-pro-v1:0' inferenceConfig = { "temperature": 0.1, "topP": 0.9, "maxTokens": 500, "stopSequences":[] } message = [ { "role": "user", "content": [{"text":prompt}] } ] response = bedrock.converse( modelId = modelId, messages = message, inferenceConfig = inferenceConfig ) # 要約を取得 summary = response['output']['message']['content'][0]['text'] return summary def create_image(title,summary): # AWS Systems Managerパラメータストアの読み込み pstore = os.environ['PARAMETER_STORE2'] prompt = ssm.get_parameters(Names=[pstore])['Parameters'][0]['Value'] prompt = prompt.replace('(タイトル)',title).replace('(概要)',summary) # Amazon Bedrockでイメージ生成を行う modelId = 'amazon.nova-canvas-v1:0' seed = random.randint(0, 858993460) request_body = { "taskType": "TEXT_IMAGE", "textToImageParams": { "text": prompt }, "imageGenerationConfig": { "numberOfImages": 1, "width": 1280, "height": 640, "cfgScale": 6.5, "seed": seed, "quality": "standard" } } response = bedrock.invoke_model( body=json.dumps(request_body), contentType='application/json', accept='application/json', modelId=modelId ) response_body = json.loads(response['body'].read()) image_data = base64.b64decode(response_body['images'][0]) return image_data def upload_media(postid, image): # WordPressのメディアライブラリにアップロード # 環境変数の読み込み url = os.environ['WP_URL'] + "wp-json/wp/v2/media" username = os.environ['WP_USER'] password = os.environ['WP_PASSWORD'] filename = str(postid) + ".png" headers = { 'Content-Type': 'image/png', 'Content-Disposition': 'attachment; filename=' + filename } # メディアのアップロード result = requests.post(url, headers=headers, data=image, auth=(username, password)) # メディアのIDを取得 res_dict = result.json() imageid = res_dict['id'] return imageid def update_post(postid,imageid): # WordPressに書き込み # 環境変数の読み込み url = os.environ['WP_URL'] + "wp-json/wp/v2/posts/" + str(postid) username = os.environ['WP_USER'] password = os.environ['WP_PASSWORD'] headers = {'Content-Type': 'application/json'} payload = { 'featured_media': imageid } result = requests.post(url, headers=headers, json=payload, auth=(username, password)) return result
Novaの呼び出し方法には本サイトの以下記事を参考にしました。

なお、本Lambda関数の実行時間は10秒を超えることがあるので、タイムアウトは20秒以上に設定することを推奨します。
続いて環境変数に必要なパラメータを指定します。
- PARAMETER_STORE1:要約用プロンプト
- PARAMETER_STORE2:画像生成用プロンプト
- WP_URL:WordPressサイトのURL(トップ)
- WP_USER:WordPressユーザーID
- WP_PASSWORD:WordPressアプリケーションパスワード
API Gatewayを設定しLambdaと紐付け
本手順は過去の記事と同じですが、画面イメージが変更されているので改めて記載します。

APIの作成から名前を指定しREST APIを作成します。
メソッドの作成からPOSTを選択し、Lambda関数を指定します。
メソッドリクエストの設定から、APIキーを有効にしてください。
任意のステージでデプロイ後、左側のメニュー「APIキー」からAPIキーを作成します。
使用量プランを作成し、APIキーと紐付けます。
WP Webhooksからの呼び出し設定
最後にWordPressのプラグイン、WP Webhooksからの呼び出し設定を行います。
プラグインの設定画面を開き「Send Data」⇒「Post Updated」に、API GatewayのURLを追加します。
続いて「Authentication」⇒「Create Template」からAPIキーの箱を作成します。
API Gatewayで発行されたAPIキーを入力します。
最後に、先程作成したAPI設定を開き「Add authentication template」から作成したAPIキーを割り当てます。
結果・今後に向けて
以上の設定で、記事更新時にアイキャッチ画像が付与されていない際に、Amazon Nova自動設定されるようになりました。
試しに本記事の内容を掛けてみたところ、こんな画像が生成されました。
WordPressっぽい画像を生成しようとしてますね・・・w
但し、技術ブログのアイキャッチ画像としては品質的にまだまだ厳しい感じで。
プロンプトエンジニアリングの話もありますが、Amazon Nova Canvasではファインチューニングもできるようになっているので、オリジナルの画像生成にチャレンジしてみたいと思います。
コストも気になりますが・・・
