1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🚀 Cloud Run + LINE Bot + Gemini を使った Webhook のデプロイ手順

Posted at

このガイドでは、Cloud Run に LINE Bot の Webhook をデプロイし、Gemini API を使った自動返信 を実装する方法をまとめます。

実際に動作確認も出来ましたが、あくまで忘備録です。記事はいつも通りChatGPTに書いてもらっています。この手順もChatGPTと相談させてもらいながら作りました。


📌 1. 全体の構成

🎯 目標

  • LINE メッセージの Webhook を受信
  • Gemini API を使って返信を生成
  • LINE Bot を通じて返信
  • Cloud Run にデプロイ
  • Secret Manager で API キーを管理

🗂 ファイル構成

webhook_project/
│── app.py                    # LINE Webhook のメイン処理
│── reply_generator.py         # Gemini API で返信を生成
│── requirements.txt           # 必要な Python ライブラリ
│── Dockerfile                 # Cloud Run 用の Docker 設定
│── cloudbuild.yaml            # Cloud Build でビルド & デプロイ
└── .gcloudignore              # GCP に不要なファイルをアップしないための設定

📌 2. Secret Manager のセットアップ

LINE と Gemini API のキーを Secret Manager に保存して管理します。

🔹 1️⃣ Secret Manager に LINE_CHANNEL_ACCESS_TOKEN を作成

gcloud secrets create LINE_CHANNEL_ACCESS_TOKEN --replication-policy="automatic"

🔹 2️⃣ LINE_CHANNEL_ACCESS_TOKEN の登録

echo -n "YOUR_LINE_ACCESS_TOKEN" | gcloud secrets versions add LINE_CHANNEL_ACCESS_TOKEN --data-file=-

🔹 3️⃣ Secret Manager に GEMINI_API_KEY を作成

gcloud secrets create GEMINI_API_KEY --replication-policy="automatic"

🔹 4️⃣ GEMINI_API_KEY の登録

echo -n "YOUR_GEMINI_API_KEY" | gcloud secrets versions add GEMINI_API_KEY --data-file=-

📌 3. Webhook の実装

📝 app.py(Webhook のメイン処理)

import os
import logging
import requests
from flask import Flask, request, jsonify
from reply_generator import generate_reply  # Gemini API の処理

app = Flask(__name__)

# Secret Manager から取得した環境変数を使用
LINE_CHANNEL_ACCESS_TOKEN = os.getenv("LINE_CHANNEL_ACCESS_TOKEN")

logging.basicConfig(level=logging.INFO)

@app.route('/webhook', methods=['POST'])
def webhook():
    """LINE Webhook を受信し、Gemini API の返信を送信"""
    data = request.json
    logging.info(f"Received data: {data}")

    if "events" in data and len(data["events"]) > 0:
        event = data["events"][0]
        if event["type"] == "message" and event["message"]["type"] == "text":
            text = event["message"]["text"]
            reply_token = event["replyToken"]

            # Gemini の API から適切な応答を取得
            gemini_reply = generate_reply(text)

            # LINE に返信
            reply_message(reply_token, gemini_reply)

    return jsonify({"message": "Webhook received"}), 200

def reply_message(reply_token, text):
    """LINE にメッセージを返信する"""
    if not LINE_CHANNEL_ACCESS_TOKEN:
        logging.error("LINE_CHANNEL_ACCESS_TOKEN is not set!")
        return

    url = "https://api.line.me/v2/bot/message/reply"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {LINE_CHANNEL_ACCESS_TOKEN}"
    }
    payload = {
        "replyToken": reply_token,
        "messages": [{"type": "text", "text": text}]
    }
    
    response = requests.post(url, headers=headers, json=payload)
    logging.info(f"LINE API response: {response.status_code} {response.text}")

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

📝 reply_generator.py(Gemini API で返信を生成)

import os
import google.generativeai as genai

# Gemini API Key を環境変数から取得
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")

# Gemini API の初期化
genai.configure(api_key=GEMINI_API_KEY)

def generate_reply(text):
    """Gemini API を使用して返信を生成"""
    if not GEMINI_API_KEY:
        return "Gemini API Key が設定されていません。"

    try:
        model = genai.GenerativeModel("gemini-pro")
        response = model.generate_content(text)
        return response.text.strip() if response and response.text else "適切な応答を生成できませんでした。"
    
    except Exception as e:
        return f"エラーが発生しました: {str(e)}"

📌 4. Cloud Run のデプロイ

📝 requirements.txt

Flask
gunicorn
requests
google-generativeai

📝 Dockerfile

FROM python:3.9

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8080", "app:app"]

📝 cloudbuild.yaml(ビルド & デプロイ)

steps:
  # 1️⃣ Docker イメージをビルド
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/${_PROJECT_ID}/webhook02', '.']

  # 2️⃣ Docker イメージをプッシュ
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/${_PROJECT_ID}/webhook02']

  # 3️⃣ Cloud Run にデプロイ(Secret Manager も設定)
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'webhook02'
      - '--image'
      - 'gcr.io/${_PROJECT_ID}/webhook02'
      - '--platform'
      - 'managed'
      - '--region'
      - 'asia-northeast1'
      - '--allow-unauthenticated'
      - '--set-secrets'
      - 'LINE_CHANNEL_ACCESS_TOKEN=LINE_CHANNEL_ACCESS_TOKEN:latest'
      - '--set-secrets'
      - 'GEMINI_API_KEY=GEMINI_API_KEY:latest'

substitutions:
  _PROJECT_ID: webhook2sns02-449820

📌 5. ビルド & デプロイ

gcloud builds submit --config cloudbuild.yaml

これで Cloud Build によって:

  1. Dockerfile をもとにコンテナをビルド
  2. Artifact Registry にコンテナをプッシュ
  3. Cloud Run にデプロイ
  4. Secret Manager の値 (LINE_CHANNEL_ACCESS_TOKEN, GEMINI_API_KEY) を適用
    が一括で実行される。

📌 6. 動作確認

1️⃣ Cloud Run のログ確認

gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=webhook02" --limit 5 --format="table(timestamp, textPayload)"

2️⃣ curl で Webhook をテスト

curl -X POST https://webhook02-rsz34pmfaa-an.a.run.app/webhook \
     -H "Content-Type: application/json" \
     -d '{"events": [{"type": "message", "replyToken": "dummy_reply_token", "message": {"type": "text", "text": "こんにちは"}}]}'

🚀 まとめ

Secret Manager を使って API キーを安全に管理
Cloud Build を使って ビルド & デプロイ を自動化
Cloud Run で LINE Webhook をホスト
Gemini API で AI 返信を生成

🎯 これで LINE Bot が Cloud Run で動作し、Gemini AI を使った応答が可能になります! 🚀

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?