LINE WebhookとVertexAIを使って、生成AIチャットボットを作ってみた②

# はじめに
この投稿は以下記事の続編になります。

https://qiita.com/piapepper/items/2ffe57471df515006cd8

### 範囲
ローカル環境で機能の作成、検証　←前回
クラウド環境にデプロイ　　　　　←今回

前回までで一通りローカル環境で動かせるようになったことから、今回はクラウド環境にデプロイしてチャットボットを常時利用できるようにします。

## GCP環境の準備
### GCPのサービスアカウントに権限を付与する
サービスアカウントは、GCPのアプリケーションやシステムが、APIやリソースを利用するためのアカウントです。通常のGoogleアカウントが「人間」がAPIやリソースにアクセスする時に必要であるのに対して、サービスアカウントは「プログラム」が認証・認可を受けるために利用されます。IAMと管理 > IAM に 名前が"Default compute service account"と記載されたアカウントに対して権限を付与することで、Cloud Runのシステムがその権限を利用することができます。

"Default compute service account"のプリンシパルをコピーしておき、Windows PowerShellにて、以下のコマンドを入力しました。

```bash
gcloud projects add-iam-policy-binding <PROJECT_ID> \
    --member="serviceAccount:<プリンシパル>" \
    --role="roles/secretmanager.secretAccessor"
```

### SeceretManagerを使ってアクセストークンなどを管理
Secret ManagerはAPI キー、パスワード、証明書、その他のセンシティブ データを保存するための安全で便利なストレージシステムです。ここに、ローカル環境では.envファイルで管理していたLINE_CHANNEL_ACCESS_TOKENとLINE_CHANNEL_SECRETを入れます。

https://cloud.google.com/security/products/secret-manager?hl=ja

#### シークレットの作成
1. Google Cloud Console の Secret Manager にアクセス
2. 「シークレットを作成」 をクリック
3. シークレット名 を入力（LINE_CHANNEL_ACCESS_TOKEN、LINE_CHANNEL_SECRET）
4. レプリケーション設定 は「自動」または「カスタム」を選択
4. 「続行」 をクリック
6. 「シークレットの値」 に暗号キーやパスワードを入力
7. 「作成」 をクリックして完了

#### Pythonスクリプトの修正
シークレットマネージャーを利用できるように修正します。

```python webhook.py
### 冒頭のみ記載 ###
import os
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
from google_api import google_api
import sys

app = Flask(__name__)

google_api_ins = google_api()

# 環境変数をシークレットマネージャから取得
CHANNEL_ACCESS_TOKEN = google_api_ins.get_secret_value("LINE_CHANNEL_ACCESS_TOKEN")
CHANNEL_SECRET = google_api_ins.get_secret_value("LINE_CHANNEL_SECRET")

```

```python google_api.py
### google_apiクラスに追加する関数のみ記載 ###

class google_api:

    # シークレットマネージャからシークレットを取得する関数
    def get_secret_value(self, secret_id: str) -> str:
        """
        Secret Managerからシークレットの最新バージョンの値を取得する。
        """
        client = secretmanager.SecretManagerServiceClient()

        name = f"projects/{self.project_id}/secrets/{secret_id}/versions/latest"
        response = client.access_secret_version(name=name)
        secret_string = response.payload.data.decode("UTF-8")
        return secret_string

```

## CloudRunへデプロイ
いよいよアプリケーションをクラウドにデプロイしていきます。今回はコンテナを利用してデプロイするので、Dockerファイルを作成します。
### Dockerファイルの作成
```Dockerfile
FROM continuumio/miniconda3

WORKDIR /app
COPY environment.yml /app/environment.yml

# environment.yml に定義した環境を作成
RUN conda env create -f environment.yml && \
    conda clean -afy && \
    echo "conda activate line Gemini" >> ~/.bashrc

# 環境変数を設定し、デフォルトのシェルでconda環境を有効にする
ENV PATH="/opt/conda/envs/lineGemini/bin:$PATH"

# アプリのソースコードコピー
COPY . /app

# ポート設定
EXPOSE 8080

CMD ["python", "webhook_event.py"] 
```
#### 解説
コンテナに関する詳細の説明は省きます。
- 筆者はminiconda環境を使ってpythonの仮想環境を構築したため、miniconda3イメージを利用してかつ、ymlファイルを利用してライブラリのインストールを実施できるようにしています。以下のようなサイトが参考になります。
 
https://qiita.com/suzuki0430/items/0bda6a04019cef2eb319

- 外部からのアクセスは常に 443 (HTTPS) で受けつけられ、Cloud Run がコンテナ内部の 8080番ポートへ自動的にルーティングされます。
- コンテナ起動時にwebhook_event.pyが実行され、Flaskサーバが立ち上がります。

### コマンドを使ってデプロイ
Dockerファイルなどが存在するディレクトリにおいて、以下のコマンドを実行します。
```bash
gcloud run deploy --source .
```

### LINE Webhookにリクエスト先を指定
LINEの公式アカウントの管理画面のWebhhok URLにデプロイしたCloud RunアプリケーションのURLを入力します。
このとき、本アプリケーションでは、/callbackにアクセスすることでLINEメッセージ認証を実施しているので、{URL}/callbackをここに入力してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4009423/516a6c10-e51f-4e99-a1fc-ed18f86ddda5.png)


# 実際のアプリケーションの様子
![IMG_6718.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4009423/58875791-dba6-419c-84ac-5f081c76a1e1.jpeg)


# まとめ

### 感想
- 自分が普段使っているアプリケーションの一部の機能を使うことだけあって、出来上がった時の達成感は大きかったです。
- 通常のLLMアプリケーションとの違いが、複数人のグループチャットで生成AIを利用できる点です。会話履歴をある程度保存して、その内容を上手くまとめてくれる等に利用できそうだと思いました。

### 今後
- 打ち返しができるアプリケーションにする。
データベースとの連携、データの効率的な利用方法を検討。
- RAGとの連携で専門的な回答をできるようにする。