0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WordPressプラグインからロリポップ!AIゲートウェイを使う実装手順

0
Posted at

カゴシマニアックスで動かしている WordPress プラグイン「PRTIMES記事ジェネレーター」に、ロリポップ!AIゲートウェイ を足しました。

この記事は、その実装手順のメモです。Claude / ChatGPT / Gemini の直APIに加えて、ゲートウェイ経由でも記事生成できるようにしたときの記録です。

プラグインが元々やっていること

PR TIMES の URL を管理画面に貼ると、次の流れで下書きができます。

  1. プレスリリースの HTML を取得する
  2. タイトル・企業名・日付・本文を抜き出す
  3. 生成AIに渡してニュース記事にする
  4. WordPress の下書きとして保存する

生成AIは、もともと次の3つを直接呼んでいました。

  • Claude(Anthropic)
  • ChatGPT(OpenAI)
  • Gemini(Google)

ここに第4のプロバイダーとして、ロリポップ!AIゲートウェイを足しました。プラグインの版は v1.3.0 です。

なぜゲートウェイを足したか

直APIは、プロバイダーごとにキーもエンドポイントも違います。モデルを切り替えたいたびに、Anthropic / OpenAI / Google の契約と請求が分かれます。

ロリポップ!AIゲートウェイは、1つのAPIキーと1つの接続先で複数モデルを呼べます。支払いは日本円で、許可モデルや自動選択もゲートウェイ側で管理できます。カゴシマニアックスのサーバーがロリポップなので、同じ系列のサービスを足す判断にしました。

公式ドキュメントで確認したこと

実装前に見たのは、次のページです。

今回のプラグインで使ったのは、この4点だけです。

項目
ベースURL https://ai-gateway.lolipop.jp
認証 Authorization: Bearer <APIキー>
生成 POST /v1/chat/completions(OpenAI Chat Completions 互換)
モデル確認 GET /v1/models

ゲートウェイは Responses API と Anthropic Messages API にも対応しています。既存プラグインが OpenAI 形式だったので、今回は Chat Completions だけ使いました。コードを大きく書き換えずに足せます。

モデルIDの扱い

ドキュメントの注意が重要でした。

  • model には GET /v1/models が返す公開名をそのまま指定する
  • アプリケーションへモデルIDを固定で埋め込まない
  • auto が使えるAPIキーなら、それを指定すると許可候補から自動選択される
  • Claude も anthropic/claude-sonnet-4-6 のような接頭辞ではなく、公開名(例: claude-sonnet-4-6)で返る

公開カタログの表は openai/gpt-5-6-luna のような表記ですが、APIに渡すのは一覧APIが返す文字列です。迷ったら auto にします。

max_tokens を省略すると、ゲートウェイ側が 4096 を補います。このプラグインでは他プロバイダーに合わせて 2048 を明示しています。

実装手順

既存のプロバイダー追加と同じ型に乗せました。直APIを3本持っているので、ゲートウェイも「キー・モデル・プロンプト・呼び出し関数」のセットです。

1. 設定項目を登録する

wp_options に次を足します。接頭辞は既存どおり prtag_ です。

  • prtag_lolipop_api_key
  • prtag_lolipop_model
  • prtag_prompt_lolipop
$fields = [
    'prtag_provider',
    'prtag_claude_api_key',   'prtag_claude_model',
    'prtag_openai_api_key',   'prtag_openai_model',
    'prtag_gemini_api_key',   'prtag_gemini_model',
    'prtag_lolipop_api_key',  'prtag_lolipop_model',
    'prtag_default_category',
    'prtag_prompt_claude',
    'prtag_prompt_openai',
    'prtag_prompt_gemini',
    'prtag_prompt_lolipop',
];
foreach ( $fields as $f ) {
    register_setting( 'prtag_options_group', $f, [
        'sanitize_callback' => 'sanitize_textarea_field',
    ] );
}

2. 生成時の振り分けに lolipop を足す

AJAX の providersanitize_key() 済みです。許可リストへ lolipop を追加し、既存の prtag_call_ai() から呼びます。

if ( ! in_array( $provider, [ 'claude', 'openai', 'gemini', 'lolipop' ], true ) ) {
    $provider = 'claude';
}

switch ( $provider ) {
    case 'openai':  return prtag_call_openai( $system, $user_msg );
    case 'gemini':  return prtag_call_gemini( $system, $user_msg );
    case 'lolipop': return prtag_call_lolipop( $system, $user_msg );
    default:        return prtag_call_claude( $system, $user_msg );
}

内部キーは lolipop、画面上のラベルは「AIゲートウェイ」にしています。ユーザーが見る名前と、option 名を分けた方が後から追いやすいです。

3. Chat Completions を叩く

ここが本体です。既存の OpenAI 呼び出しとほぼ同じで、エンドポイントとキーの option 名だけ変えています。

function prtag_call_lolipop( string $system, string $user_msg ): array|WP_Error {
    $api_key = get_option( 'prtag_lolipop_api_key', '' );
    if ( empty( $api_key ) ) {
        return new WP_Error( 'no_key', 'ロリポップ!AIゲートウェイのAPIキーが未設定です。設定ページで入力してください。' );
    }

    $model = get_option( 'prtag_lolipop_model', 'auto' );
    if ( $model === '' ) {
        $model = 'auto';
    }

    $res = wp_remote_post( 'https://ai-gateway.lolipop.jp/v1/chat/completions', [
        'timeout' => 90,
        'headers' => [
            'Content-Type'  => 'application/json',
            'Authorization' => 'Bearer ' . $api_key,
        ],
        'body' => wp_json_encode( [
            'model'      => $model,
            'max_tokens' => 2048,
            'messages'   => [
                [ 'role' => 'system', 'content' => $system ],
                [ 'role' => 'user',   'content' => $user_msg ],
            ],
        ] ),
    ] );

    if ( is_wp_error( $res ) ) {
        return $res;
    }

    $code = wp_remote_retrieve_response_code( $res );
    $data = json_decode( wp_remote_retrieve_body( $res ), true );
    if ( $code !== 200 ) {
        $msg      = $data['error']['message'] ?? "AIゲートウェイ APIエラー (HTTP {$code})";
        $err_code = $data['error']['code'] ?? '';
        $hints    = [
            'model_not_found'        => 'モデルIDが一覧にありません。「auto」にするか、ダッシュボードで確認した公開名を指定してください。',
            'model_not_allowed'      => 'このAPIキーでは指定モデルが許可されていません。ダッシュボードの許可モデルを確認してください。',
            'auto_required'          => 'このAPIキーは自動選択が必須です。モデルを「auto」に設定してください。',
            'auto_resolution_failed' => 'auto で実行できる候補がありません。ダッシュボードの許可モデルと自動選択候補を確認してください。',
        ];
        if ( isset( $hints[ $err_code ] ) ) {
            $msg .= ' — ' . $hints[ $err_code ];
        }
        return new WP_Error( 'lolipop_error', $msg );
    }

    $text = $data['choices'][0]['message']['content'] ?? '';
    if ( empty( $text ) ) {
        return new WP_Error( 'empty', 'AIからの応答が空でした' );
    }
    return prtag_parse_generated( $text );
}

成功時の本文は choices[0].message.content です。クイックスタートのレスポンス例と同じ形です。auto を指定した場合、レスポンスの model には実際に応答した公開名が入ります。

エラーコードは公式の「使えないモデルを指定したとき」に合わせています。ゲートウェイ特有の失敗を、管理画面で日本語のまま見られるようにしました。

4. 管理画面のタブと設定ページ

生成画面のプロバイダー選択へ、キーが保存されているときだけ有効なタブを足します。

$has_lolipop = (bool) get_option( 'prtag_lolipop_api_key' );

$provider_labels = [
    'claude'  => [ 'label' => 'Claude',        'icon' => '🟠', 'set' => $has_claude  ],
    'openai'  => [ 'label' => 'ChatGPT',       'icon' => '🟢', 'set' => $has_openai  ],
    'gemini'  => [ 'label' => 'Gemini',        'icon' => '🔵', 'set' => $has_gemini  ],
    'lolipop' => [ 'label' => 'AIゲートウェイ', 'icon' => '🍭', 'set' => $has_lolipop ],
];

設定ページのモデル候補は、よく使う公開名と auto です。一覧に無いIDは、既存の「カスタムモデル名」入力に任せています。

$lolipop_models = [
    'auto'                  => 'auto(推奨・ゲートウェイが自動選択)',
    'claude-sonnet-4-6'     => 'Claude Sonnet 4.6',
    'claude-haiku-4-5'      => 'Claude Haiku 4.5',
    'gpt-5-6-luna'          => 'GPT-5.6 Luna(低コスト)',
    'gpt-5-6-terra'         => 'GPT-5.6 Terra',
    'gemini-2.5-flash'      => 'Gemini 2.5 Flash',
    'gemini-3-5-flash-lite' => 'Gemini 3.5 Flash Lite',
];

フロントの admin.js は、ローディング文言と結果バッジに lolipop を足すだけです。生成・下書き保存のAJAXは、既存の provider パラメータを流用しています。

WordPress での設定手順

コードを上げたあとの操作です。

  1. ロリポップ!AIゲートウェイ のダッシュボードでプロジェクトを開く
  2. APIキーを発行する
  3. WordPress 管理画面の PR記事生成 → 設定 を開く
  4. 「ロリポップ!AIゲートウェイ」にAPIキーを貼る
  5. モデルはまず auto にする
  6. 設定を保存する
  7. PR記事生成 の画面で「AIゲートウェイ」タブを選ぶ
  8. PR TIMES の URL を入れて生成する

キーが空だと、タブは「APIキー未設定」で選べません。既存の Claude / ChatGPT / Gemini はそのまま残っています。直APIを止める必要はありません。

特定モデルを使いたい場合は、ダッシュボードか GET /v1/models で公開名を確認してから指定します。

curl "https://ai-gateway.lolipop.jp/v1/models" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY"

本番への上げ方

カゴシマニアックスでは、ローカルのプラグインディレクトリを wp-content/plugins/prtimes-article-generator/ へ同期しました。上げる前に、稼働中の v1.2.0 をサーバー側で tar バックアップしています。

上げる対象は次だけです。

  • prtimes-article-generator.php
  • assets/admin.js
  • assets/admin.css

.git は本番へ出していません。PHP の構文チェックは、上げたあとサーバー上でも実行しています。

今回やらなかったこと

実装を小さく保つために、次は入れていません。

  • GET /v1/models を設定画面から自動取得する
  • Responses API / Anthropic Messages API
  • ストリーミング
  • BYOK(手元の Anthropic / OpenAI キーをゲートウェイへ預ける)

ドキュメントは「モデルIDをアプリへ固定で埋め込まない」と書いています。今回はプリセット+カスタム入力で逃しています。モデルが増えたら、一覧APIから select を埋める方が正しいです。

参考

既存の直APIを残したまま、OpenAI互換の1本を足すだけでゲートウェイに載せられました。同じ型の WordPress プラグインなら、呼び出し関数を1つ追加する作業です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?