リモート開発メインのソフトウェア開発企業のエンジニアブログです

LINEとGoogle Cloudを連携して対話サービスを作成する(第1回)

最近、Google Apps Script(GAS)を作成する機会があり、それをきっかけにGoogleのAPIに興味を持ちました。調べてみると、普段から利用しているGmailやGoogleマップをはじめ、翻訳APIなど、さまざまなAPIとライブラリがGoogle Cloudに用意されていることを知りました。この中で今流行りの生成AIがあったので試してみることにしました。また、フロントエンドには、LINEを活用できそうだったのでこれらを組み合わせ構築してみます。

ボリュームが多くなりそうなため、全2回に分けて作成したいと思います。

  • 第1回: LINEの入力を受け取り、Gemini AIが回答する仕組みを構築
  • 第2回: Dialogflow CXで会話を管理し、サービスとして成立させる

環境

LINE

  • Messaging API:外部システムとのやり取りに使用

Google Cloud(旧Google Cloud Platform)

  • Gemini AI:Googleの生成AIモデル
  • Dialogflow CX:会話フローを管理
  • Cloud Functions:サーバーレス環境

言語

  • Node.js (v20.15.1)

フロー

LINE入力↔Messaging API ↔ Dialogflow CX ↔Cloud Functions(Node.js) ↔Gemini AI

Moba Pro

成果物

第1回分となります。以下のアカウントを友だち登録するとお試しいただけます。

  • LINE公式アカウントID : @613louqg
  • アカウント名 : もばホズLINEテスト(アカウント認証(要審査)していないため、名前検索では表示されません)
  • QRコード:https://lin.ee/sdDgLMN

構築手順

LINE側の作業

まず、LINE側の作業として、公式アカウントマネージャーとLINE Developersの2か所での登録が必要になります。LINE公式アカウントマネージャで公式アカウントを作成し、Messaging APIの利用登録を行います。
次に、LINE DevelopersでMessage APIのチャネルトークンを発行します。

  • LINE公式アカウントマネージャ:企業や店舗が公式アカウントを管理するためのツール
  • LINE Developers: LINE公式アカウントやLINEアプリと連携するための開発者向けプラットフォーム

詳細な手順は以下をご参照下さい

Google Cloud側の作業

Dialogflow CX

次に、Dialogflow CX でLINEと連携します。IntegrationsメニューでLINEを選択し、LINE DevelopersのチャネルID、チャネルシークレット、チャネルアクセストークンを設定します。このとき、表示されるWebhookのURLはLINE DevelopersのMessaging API設定画面に登録します。

実装

コードはユーザーの入力を受け取り、Gemini AIが応答するシンプルなものです。サーバレス環境のCloud Functionsで動作させます。リクエストやレスポンスの形式は公式ドキュメントに記載されてますが、デバッグログを出力するとLogs Explorerで確認できました。また、Gemini AIのモデルは今回はテキストのみに対応するため、軽量モデル「gemini-1.5-flash」を使用しました。Proバージョンを利用すると高度な推論ができるようです。どのモデルを使用するかは目的や費用と相談ですね。

参考にした公式ドキュメントは以下の通りです。

コードはこちらになります。

// Node.js

// 定数やライブラリ
const { VertexAI } = require('@google-cloud/vertexai');

const PROJECT_ID = process.env.CAIP_PROJECT_ID || 'ai-cmp';
const LOCATION = 'asia-northeast1';
const MODEL_NAME = 'gemini-1.5-flash-001';

// VertexAI クライアントのインスタンス化
const vertexAI = new VertexAI({
  project: PROJECT_ID,
  location: LOCATION,
});

// Dialogflow CX Webhookエントリーポイント
exports.cxWebhook = async (req, res) => {
  try {
    console.log('Request Body:', JSON.stringify(req.body, null, 2));

    // ユーザーの入力を取得 (Dialogflow CX のパラメータ)
    const userInput = req.body?.text || '質問がありません';
    console.log('ユーザー入力:', userInput);

    // Vertex AIに問い合わせ
    const generatedText = await callGeminiModel(userInput);

    // Dialogflow CX用レスポンス形式
    const responsePayload = {
      fulfillment_response: {
        messages: [
          {
            text: {
              text: [`Geminiの回答: ${generatedText}`],
            },
          },
        ],
      },
    };

    res.status(200).send(responsePayload);
  } catch (err) {
    console.error('Webhook Error:', err);

    res.status(200).send({
      fulfillment_response: {
        messages: [
          {
            text: {
              text: ['エラーが発生しました。詳細はログを確認してください。'],
            },
          },
        ],
      },
    });
  }
};

// Geminiモデルを呼び出す関数
async function callGeminiModel(promptText) {
  try {
    // Gemini モデルのインスタンス化
    const generativeModel = vertexAI.getGenerativeModel({
      model: MODEL_NAME,
    });

    // モデルへ送信するプロンプト
    const prompt = promptText;

    // モデルに問い合わせ
    const resp = await generativeModel.generateContent(prompt);
    const contentResponse = await resp.response;
    console.log('Gemini Response:', JSON.stringify(contentResponse, null, 2));

    // Geminiモデルの応答のテキストを抽出
    const text =
      contentResponse?.candidates?.[0]?.content?.parts?.[0]?.text?.trim() ||
      'Geminiモデルの応答が空でした';

    // 文字列として返却
    return text;
  } catch (error) {
    console.error('Gemini呼び出しエラー:', error);
    return 'Gemini呼び出し中にエラーが発生しました';
  }
}

// package.json
{
  "name": "vertexai",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@google-cloud/aiplatform": "^3.34.0",
    "@google-cloud/vertexai": "^1.9.2"
  }
}

これをローカルからCloud Functitonsにデプロイします。デプロイコマンドを使うとCloud Functionsのエンドポイントがデプロイログに表示されるので、Dialogflow CXのWebhookとして設定します。なお、前述の通りLINE Messaging APIにはDialogflow CXのエンドポイントをWebhookとして登録しており、合わせて2種類のWebhookを使用しています。また、デプロイするために事前にgcloud auth loginコマンドを実行し、Google Cloudアカウントに認証しておきます。

gcloud functions deploy cxWebhook \
       --entry-point=cxWebhook \
       --runtime=nodejs20 \
       --trigger-http \
       --region=asia-northeast1 \
       --allow-unauthenticated \
       --memory=512MB

デプロイログが表示され、最後の行にCloud Functionsのエンドポイントが表示される

簡潔な説明となっておりますが、以上がLINEからの入力によりGemini AIが回答を返す手順とコードになります。

まとめ

Google Cloudを使うのは初めてで、環境を構築してもコードを書いても思うように動かず苦戦しましたが、ドキュメントやデバッグログを確認しながら、なんとか構築できました。現状はLINEからの入力にGemini AIが応答するだけなので、DialogFlow CXで会話フローを設計し、ブラッシュアップしてサービスとして価値を生み出せたらとい思います。(第2回へ続く)

← 前の投稿

Alpine Linux 3.20 以降の chromium-chromedriver で E2E テストが動かない件の解消法

次の投稿 →

4つのDBクライアントソフトの使用感について

コメントを残す