WordPressとOpenAI APIで投稿要約を自動生成する方法

記事の要約を自動生成するOpenAI APIを活用したWordPressプラグインの作り方を解説。投稿内容を理解した上で自然な要約を生成でき、SEOや読者体験の向上が期待できます。

広告ここから
広告ここまで

目次

    WordPressブログを運営していると、各記事の要約(抜粋)を手動で作成する作業は意外と手間がかかります。特に記事数が多いサイトでは、この作業だけでもかなりの時間を要します。本記事では、OpenAI APIを活用してWordPress投稿の要約を自動生成する方法をご紹介します。

    なぜ投稿要約の自動生成が必要なのか

    WordPressの投稿には「抜粋(excerpt)」という機能があります。この抜粋は以下のような場面で利用されます:

    • アーカイブページでの記事プレビュー表示
    • RSSフィードでの記事概要
    • SNSシェア時のメタディスクリプション
    • 検索エンジン向けのメタディスクリプション

    しかし、多くの場合、この抜粋を手動で入力する作業は後回しにされがちです。結果として、WordPress組み込みの自動抜粋機能が使われることになりますが、これは単純に記事の冒頭部分を切り取るだけのものです。

    今回紹介するOpenAI APIを使った方法では、記事全体の内容を理解した上で、自然な日本語(または英語)で要約を自動生成できます。これにより、SEOや読者体験の向上が期待できます。

    OpenAI APIについて

    OpenAI APIは、GPT-3.5やGPT-4などの大規模言語モデルを利用できるAPIサービスです。テキスト生成、要約、翻訳、質問応答など、様々な自然言語処理タスクに活用できます。

    今回は、この中でも「chat completions API」を利用して、投稿内容を要約します。

    必要な準備

    1. OpenAIのアカウント作成(まだの方はOpenAIのサイトから)
    2. APIキーの取得(OpenAIダッシュボードから発行可能)
    3. WordPressサイトの管理者権限

    実装手順

    それでは、実際にOpenAI APIを使ってWordPress投稿の要約を自動生成する機能を実装していきましょう。

    1. OpenAIWordPressクラスの作成

    まずはOpenAI APIとやり取りするためのユーティリティクラスを作成します。これをテーマのfunctions.phpや専用のプラグインファイルに追加しましょう。

    /**
     * OpenAI utilities 
     **/
    class OpenAIWordPress {
        private $api_key = 'sk-xxx';
        public function __construct( $api_key = '' ) {
            if ( $api_key ) $this->api_key = $api_key;
        }
        public function create_completions( $content , $lang, $summary_length ) {
            $url = 'https://api.openai.com/v1/chat/completions';
            $data = array(
                'model' => 'gpt-3.5-turbo',
                'messages' => array(
                    array(
                        'role' => 'system',
                        'content' => "You're the blog writer good at the summarizing existing posts. Please generate a short summary of the user input text by the following conditions. rule1: The summary should be written in ' . $lang . '. rule2: The summary should less than ' . $summary_length . ' words. rule3: The summary should not include any code example."
                    ),
                    array(
                        'role' => 'user',
                        'content' => $content,
                    )
                )
            );
            $headers = array(
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $this->api_key,
            );
    
            $response = wp_remote_post($url, array(
                'body' => json_encode($data),
                'headers' => $headers,
                'timeout' => 100
            ));
    
            if (is_wp_error($response)) {
                $error_message = $response->get_error_message();
                error_log( print_r( $error_message, true ) );
                return '';
            }
            $json = json_decode( wp_remote_retrieve_body( $response ) , true);
            if ( ! $json ) {
                return '';
            }
            if ( ! isset( $json['choices'][0]['message']['content'] ) ) {
                return '';
            }
    
            return $json['choices'][0]['message']['content'];
        }
        public function generate_excerpt_from_content( $content, $lang , $summary_length ) {
            // Make sure the content is long enough to generate an excerpt
            if (strlen($content) < $summary_length) {
                return $content;
            }
    
            // Clean up the content by removing HTML tags and newlines
            $content = strip_tags($content);
            $content = str_replace(array("\r", "\n"), '', $content);
    
            return $this->create_completions( 'Generate a short summary of this text: ' . $content, $lang, $summary_length );
        }
        public function generate_excerpt_by_post( $post ) { 
            if ( $post->post_excerpt ) {
                return;
            }
            $content = get_post_field( 'post_content', $post->ID );
    
            $lang_type = get_post_meta( $post->ID, '_locale', true );
            $is_en_post = preg_match( '/en/', $lang_type );
            $summarize_language = $is_en_post? 'english' : '日本語';
            $summary_length = $is_en_post ? 200 : 100;
    
            $generated_excerpt = $this->generate_excerpt_from_content( $content , $summarize_language, $summary_length );
            error_log(print_r(array('$generated_excerpt' => $generated_excerpt), true));
            if ( ! $generated_excerpt ) {
                return;
            }
    
            wp_update_post( array(
                'ID' => $post->ID,
                'post_excerpt' => $generated_excerpt,
            ) );
        }
        public function generate_excerpt_by_id( $post_id ) {
            $post = get_post( $post_id );
            if ( ! $post ) return;
            return $this->generate_excerpt_by_post( $post );
        }
    }
    
    add_action( 'transition_post_status', function( $new_status, $old_status, $post ) {
        if ( 'publish' !== $new_status ) {
            return;
        }
        $OpenaiWP = new OpenAIWordPress();
        $OpenaiWP->generate_excerpt_by_post( $post );
    }, 10, 3 );

    2. APIキーの設定

    上記のコードでは、APIキーをハードコーディングしていますが、実際の運用ではより安全な方法で管理することをお勧めします。例えば、以下のような方法があります:

    1. WordPressの定数としてwp-config.phpに定義

    define( 'OPENAI_API_KEY', 'sk-xxxxxxxxxxxxxxxxxxxxxxxx' );

    1. 環境変数から取得

    $api_key = getenv('OPENAI_API_KEY');

    1. データベースに保存(プラグイン設定ページから管理)

    セキュリティの観点から、APIキーは公開リポジトリにコミットしないよう注意しましょう。

    コード解説

    このコードがどのように動作するのか、主要な部分を詳しく解説します。

    OpenAIWordPressクラス

    このクラスは、OpenAI APIとのやり取りを担当する中心的なクラスです。

    create_completions メソッド

    public function create_completions( $content , $lang, $summary_length ) {
        // ... 
    }

    このメソッドは、OpenAIのChat Completions APIを呼び出して要約を生成します。ポイントは以下の部分です:

    1. システムメッセージで要約の条件を指定

    • 言語(日本語/英語)
    • 要約の長さ(単語数)
    • コード例を含めない

    1. WordPressのwp_remote_post関数を使用してAPIリクエスト

    • タイムアウトを長めに設定(100秒)して、大きな記事でも処理できるようにしています

    1. エラーハンドリング

    • APIからのレスポンスエラーを適切に処理し、エラーログに記録

    generate_excerpt_from_content メソッド

    public function generate_excerpt_from_content( $content, $lang , $summary_length ) {
        // ...
    }

    このメソッドは、投稿コンテンツから要約を生成する前処理を行います:

    1. コンテンツの長さチェック

    • コンテンツが要約長より短い場合は、そのままコンテンツを返す

    1. HTMLタグと改行の除去

    • OpenAI APIに送信する前にテキストをクリーンアップ

    generate_excerpt_by_post メソッド

    public function generate_excerpt_by_post( $post ) { 
        // ...
    }

    このメソッドは、WordPress投稿オブジェクトから要約を生成します:

    1. 既存の抜粋チェック

    • すでに抜粋がある場合は処理をスキップ

    1. 言語判定

    • _localeメタデータに基づいて言語を判断
    • 英語記事の場合は200単語、日本語記事の場合は100単語を上限に設定

    1. 自動生成した要約でpost_excerptを更新

    • wp_update_post関数を使用して投稿を更新

    フック設定

    add_action( 'transition_post_status', function( $new_status, $old_status, $post ) {
        // ...
    }, 10, 3 );

    transition_post_statusフックを使って、投稿が「公開」ステータスになったときに自動的に要約を生成します。これにより、新規投稿時や下書きから公開に変更された時に要約が自動生成されます。

    デプロイと運用のポイント

    1. APIコスト管理

    OpenAI APIは使用量に応じて課金されます。GPT-3.5-turboモデルは比較的安価ですが、大量の投稿を処理する場合はコストに注意が必要です。

    • 無駄なAPI呼び出しを減らす(既に抜粋がある場合はスキップするなど)
    • レート制限に注意する(短時間に大量のリクエストを送らない)
    • 使用量上限を設定して予期せぬ請求を防ぐ

    2. パフォーマンス考慮

    APIリクエストには時間がかかるため、ユーザー体験に影響しないよう考慮が必要です。

    • バックグラウンド処理を検討(WP Cronなど)
    • 大規模サイトでは一度に多数の投稿を処理しない
    • タイムアウト設定を適切に調整

    3. エラーハンドリング

    APIとの通信には様々な問題が発生する可能性があります。

    • ネットワークエラー
    • APIレート制限
    • レスポンスタイムアウト
    • 予期せぬAPIの仕様変更

    こうした問題に備えて、適切なエラーログ記録とフォールバック処理を実装しましょう。

    4. セキュリティ対策

    APIキーは重要な認証情報です。以下の点に注意しましょう。

    • APIキーを公開リポジトリにコミットしない
    • 適切なアクセス制限を設定(管理者のみが機能を使用できるようにする)
    • APIキーの定期的な更新

    まとめ

    今回は、OpenAI APIを活用してWordPress投稿の要約を自動生成する方法を紹介しました。この仕組みを導入することで、以下のメリットが得られます

    OpenAI APIの可能性は要約だけにとどまりません。タグ自動生成、関連記事の提案、コンテンツ改善提案など、さまざまな用途に応用できます。ぜひ皆さんも自分のWordPressサイトに合わせたカスタマイズを試してみてください。

    参考リソース

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark