自分用GPTサービスをAWS Copilot CLI × AWS App Runner × Chatbot UIでホスティングする

## はじめに
NTTテクノクロス株式会社の渡邉洋平です。

今回はいま流行りのChatGPTを模したサービスをApp Runnerでホスティングしていきたいと思います。
Copilot CLIでのApp Runner管理を試してみたかったので、CDKでなくそちらを利用しています。

### 用語解説

いろいろ用語が出てくるので、簡単に整理します。

- ChatGPT:
    - OpenAIが開発したGPT-4アーキテクチャをベースとする大規模な言語モデル。自然言語処理タスクにおいて高度な文章生成や理解が可能であり、質問応答、文章要約、翻訳など多岐にわたる用途に利用できます。

- Chatbot UI
    - ChatGPT風のChatUI。OSSとして公開されており 2023/4/25時点で12000 Starを集めています。
   
- AWS App Runner:
    - コンテナ化されたアプリケーションのデプロイとスケーリングを自動化するサービスで、開発者がインフラストラクチャ管理にかかる手間を削減し、簡単にアプリケーションを実行できるように設計されています。

- AWS Copilot CLI:
    - AWSのCLIを用いて、コンテナ化されたアプリケーションの開発、リリース、運用を簡単に行うことができるツールです。ECSやApp Runnerにも対応しています。

## 環境構築

前置きはこのくらいにして早速作ってみましょう。
前提としてAWS Cloud9環境(Amazon Linux2)で実施しています。

### 1. install

公式の手順に従い、AWS Copliot CLIを導入します。

https://github.com/aws/copilot-cli#installation

```bash
curl -Lo copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-linux && chmod +x copilot && sudo mv copilot /usr/local/bin/copilot && copilot --help
```

また、Chatbot UIの資材もダウンロードしておきます。

https://github.com/mckaywrigley/chatbot-ui

```bash
git clone https://github.com/mckaywrigley/chatbot-ui.git
```


### 2. deploy

まずはひな形としてアプリケーションをデプロイします。

```bash
copilot init
```

対話式に入力していくので、指定する選択肢は、こんな感じです。
- Use existing application: No
- Application name: my-chatgpt
- Workload type: Request-Driven Web Service
- Service name: my-chatgpt-svc
- Dockerfile: ./Dockerfile
- Deploy: Yes

大量のリソースが構築されるのを待ちつつ、10分ほど経つとサンプルアプリがデプロイされます。

![chatgpt-jp-deploy-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528454/68ce060c-8d7e-68ad-db00-efea9418a005.jpeg)


#### Error

- AWS Cloud9のデフォルトのIAM権限(AWS Managed Temporary Credentials)で実施すると、クレデンシャルがタイムアウトしてしまうので、必ずIAM Role下で実施しましょう。
- `copilot init`コマンドが失敗したのちリトライすると色々上手くいかないことがありました。環境が汚れたら、以下のコマンドでまっさらにするのも手ですね。

```bash
copilot svc delete <作りかけのService>
copilot app delete <作りかけのApplication>
```

---

### 3. Setting Credential

Webサイトとしてのモックはできたのですが、さすがにUIからOpenAIのクレデンシャルを入れたくないため、事前に設定されたクレデンシャルを読み込む実装にします。

具体的にはSecret StringのSSM ParameterStoreはCloudFormationからは作成できないので。任意の手段で準備します。以下はCLIで実施する例です。

```bash
aws ssm put-parameter --type "SecureString" --name "OPENAI_API_KEY" --value "sk-<something>"     
```

Copilot CLIで自動生成された設定ファイルがあるので、以下の様に書き換えます。
※Secretの書き換え以外にも、適宜必要そうな箇所のコメントアウトを外しています。

```yaml:chatbot-ui/copilot/environments/test/manifest.yaml
# The manifest for the "my-chatgpt-svc" service.
# Read the full specification for the "Request-Driven Web Service" type at:
# https://aws.github.io/copilot-cli/docs/manifest/rd-web-service/

# Your service name will be used in naming your resources like log groups, App Runner services, etc.
name: my-chatgpt-svc
# The "architecture" of the service you're running.
type: Request-Driven Web Service

image:
  # Docker build arguments.
  # For additional overrides: https://aws.github.io/copilot-cli/docs/manifest/rd-web-service/#image-build
  build: Dockerfile
  # Port exposed through your container to route traffic to it.
  port: 3000

http:
  healthcheck:
    path: /
    healthy_threshold: 3
    unhealthy_threshold: 5
    interval: 10s
    timeout: 5s

# Number of CPU units for the task.
# cpu: 1024
cpu: 512
# Amount of memory in MiB used by the task.
# memory: 2048
memory: 1024

# Connect your App Runner service to your environment's VPC.
# network:
#   vpc:
#     placement: private


# Enable tracing for the service.
observability:
  tracing: awsxray

# Optional fields for more advanced use-cases.
#
# variables:                    # Pass environment variables as key value pairs.
#   LOG_LEVEL: info
#
# tags:                         # Pass tags as key value pairs.
#   project: project-name
#
secrets:                      # Pass secrets from AWS Systems Manager (SSM) Parameter Store and Secrets Manager.
  OPENAI_API_KEY: OPENAI_API_KEY  # The key is the name of the environment variable, the value is the name of an SSM parameter.

# You can override any of the values defined above by environment.
# environments:
#   test:
#     variables:
#       LOG_LEVEL: debug        # Log level for the "test" environment.
```


あとは再デプロイを行うだけで更新できます！ 簡単。

```bash
copilot svc deploy
```

左下の「APIキー」に関する記述が消え、利用できていることがわかります。

![chatgpt-jp-deploy-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528454/d1379e7a-a0a5-b4ed-3eb3-0d434b66eb64.jpeg)


## まとめ

ということで、ChatGPT UIをAWS App Runnerでホスティングすることができました。

今回は簡単に立ち上げるために`copilot init`で起動してしまいましたが、実際はこの記事のようにapp, env, svcそれぞれで設定するのが良さそうです。

https://aws.amazon.com/jp/builders-flash/202212/apprunner-deploy-copilot-cli/?awsf.filter-name=*all


生成AI周りのトレンドは激しく動きがありそうですが、「DockerベースのUIをホスティングして、事前指定したAPIキーで生成AIを呼び出す」という運用なら汎用的に実施できそうですね。

実運用ではWAFでのIP制御、Cognitoでの認証処理などを組み合わせると便利そうです。それでは。

## 参考資料

https://zenn.dev/noid11/articles/07d3dd30f0ccf27491d4

https://dev.classmethod.jp/articles/chatgpt-webui-chatbot-ui/