Vue.js と AWS サービスを使って問合せした人の感情を判定するフォームを作る

2020-11-02
デベロッパーのためのクラウド活用方法

松井 英俊 (JAWS-UG 浜松支部)

こんにちは、JAWS-UG 浜松支部の松井です。
近年、機械学習、AI に対する注目が集まっています。しかし、何らかの機械学習を活用した仕組みを 1 人で 0 から作るのはなかなかハードルが高く、機械学習で重要になってくるビッグデータの収集も大きな問題になってきます。

AWS では、こうした問題を解決してくれる、機械学習を誰でも簡単に活用できるサービスが多数提供されています。 今回はその中でも、機械学習を使用してテキスト内でインサイトや関係性を検出する自然言語処理 (NLP) サービス Amazon Comprehend を活用して、 問合せした人の感情を判定してくれるフォームを作ってみようと思います。

  • 機械学習、AI 活用といっても、どこから手をつけたらいいか分からない
    日常の生活や業務でどの様に役に立てれば良いか分からない

という方も多くいらっしゃると思いますが、Amazon Comprehend を活用したこちらのハンズオンが一助となれば幸いです。

ご注意

本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。

*ハンズオン記事およびソースコードにおける免責事項 »

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. 前提環境

今回のハンズオンは下記の環境&ツールにて検証しています。 ※必要なツールが揃っていればPCやOSは問いません

  • OS: Mac OS X
  • node: v14.6.0
  • npm: 6.14.7
  • vue: @vue/cli 4.4.6
  • amplify: 4.27.3

また、こちらの記事をご参考に、上記の必要なツールを揃えた環境を AWS Cloud9 上に構築していただくこともできます。

始める前にサンプルコードをこちらからダウンロードしてください。


2. 今回のアーキテクチャ

今回のハンズオンで作成するシステムの構成図です。 

  • 動作の起点となるお問い合わせフォームは Vue.js を使って作成し、AWS Amplify を使って Amazon S3 バケット上にデプロイします。煩雑な環境構築のステップを省略し、証明書付きの URL を自動生成してくれるのでとても便利です。
  • お問い合わせフォームの入力内容は非同期通信を使って POST リクエストを送信し、Amazon API Gateway が受け取り、AWS Lambda へプロキシします。
  • AWS Lambda では Amazon Comprehend を使って問合せ内容を解析し、文章から感情を判定します。その判定内容を添えて、Amazon SES へ管理者へのメール送信をリクエストします。

3. Amazon SES の設定

Amazon SES を使って管理者 (自分) にメールを送れるように設定を行います。

AWS マネジメントコンソールにアクセスし、「ses」と入力し、検索結果 (プルダウン) の「Simple Email Service」をクリックします。

クリックすると拡大します

左側の「Email Address」をクリックし、「Verify a New Mail Address」ボタンをクリックします。 

クリックすると拡大します

フォームにメールアドレスを入力し、「Verify This Email Address」ボタンをクリックします。
※こちらの見本アドレスはテスト用です。ご自身の実在するメールアドレスを使用してください。

クリックすると拡大します

入力したメールアドレス宛に上記のようなメールが届くので、リンクをクリックしてメールアドレスの検証を完了させます。 

クリックすると拡大します


4. AWS Lambda 関数の作成

Amazon Comprehend を使って送られてきた問合せ内容を解析して感情判定し、判定結果を加えた上で Amazon SES を使って管理者にメールを送信する関数を作成します。

AWS マネジメントコンソールにアクセスし、「lambda」と入力し、検索結果 (プルダウン) の「Lambda」をクリックします。

クリックすると拡大します

「関数の作成」をクリックします。 

クリックすると拡大します

  • 「関数名」に「contactFunction」と入力します。 (命名は何でも構いません)
  • 「ランタイム」に、今回は「Python 3.7」を選択します。
  • 「実行ロールの選択または作成」の項目を展開し、「基本的な Lambda アクセス権限で新しいロールを作成」を選択します。
  • 最後に「関数の作成」をクリックします。

クリックすると拡大します

関数が正常に作成できたら、「アクセス権限」タブをクリックして、「ロール名」に表示されるロールをクリックします。 

クリックすると拡大します

「ポリシーをアタッチします」ボタンをクリックします。

クリックすると拡大します

  • 検索フォームに「comprehend」と入力します。
  • 「ComprehendFullAccess」にチェックを入れます。
  • 「ポリシーのアタッチ」ボタンをクリックします。

クリックすると拡大します

  • 同じ要領で再度「ポリシーをアタッチします」ボタンを押してから、検索フォームに「ses」と入力します。
  • 「AmazonSESFullAccess」にチェックを入れます。
  • 「ポリシーのアタッチ」ボタンをクリックします。

クリックすると拡大します

作成した Lambda 関数「contactFunction」に戻り、「設定」タブの「関数コード」のエディタで以下の通りコードを記述していきます。

#lambda_function.py

import json
import boto3

REGION = 'ap-northeast-1'
SRC_MAIL = "test@example.com"#SESに登録したメールアドレス
DST_MAIL = "test@example.com"#SESに登録したメールアドレス
SENTIMENTS = {
    "NEUTRAL": "中立的",
    "POSITIVE": "肯定的",
    "NEGATIVE": "否定的",
    "MIXED": "混在"
}
LANGUAGE_CODE = 'ja'

def detect_text_sentiment(text):#Comprehendを使って感情を検知するメソッド
    comprehend = boto3.client('comprehend', region_name=REGION)
    response = comprehend.detect_sentiment(Text=text, LanguageCode=LANGUAGE_CODE)
    return response

def send_email(source, to, subject, body):#SESでメールを送るメソッド
    ses = boto3.client('ses', region_name=REGION)
 
    response = ses.send_email(
        Source=source,
        Destination={
            'ToAddresses': [
                to,
            ]
        },
        Message={
            'Subject': {
                'Data': subject,
            },
            'Body': {
                'Text': {
                    'Data': body,
                },
            }
        }
    )
     
    return response

def lambda_handler(event, context):
    sentiment = detect_text_sentiment(event['content'])['Sentiment']
    body = "件名:\n" + event['title'] + "\n" + "\n連絡先:\n" + event['contact'] + "\n" + "\n感情:\n" + SENTIMENTS[sentiment] + "\n" + "\n内容:\n" + event['content']
    mail = send_email(SRC_MAIL, DST_MAIL, 'お問い合わせがありました', body)
    
    return {
        'statusCode': 200,
        'body': {
            'sentiment': sentiment,
            'mail': mail
        }
    }

クリックすると拡大します

  • 関数のテストイベントを作成して、動作確認します。
  • 上記の「テスト」ボタンをクリックします。

クリックすると拡大します

上記の通り、「イベント名」(任意ですのでなんでも構いません) とテスト用のパラメータを記述して、「作成」ボタンをクリックします。

クリックすると拡大します

もう一度「テスト」ボタンをクリックすると、テストが実行されます。

クリックすると拡大します

登録したアドレスに、上記の通りのメールが送られていれば成功です。
「感情」という項目に、感情の判定結果が表示されているかと思います。

クリックすると拡大します


5. Amazon API Gateway の設定

作成した Lambda 関数を API として呼び出しできる様に、Amazon API Gateway を設定していきます。

引き続き作成した Lambda 関数「contactFunction」の画面で、「+ トリガーを追加」ボタンをクリックします。

クリックすると拡大します

選択肢はそれぞれ「API Gateway」「Create an API」「REST API」「オープン」を選択し、「追加」ボタンをクリックします。 

クリックすると拡大します

Lambda 関数の画面に戻るので、「contactFunction-API」をクリックします。

クリックすると拡大します

「アクション」をクリックし、プルダウンメニューから「メソッドの作成」をクリックします。 

クリックすると拡大します

表示されるプルダウンメニューの「POST」をクリックして、右側のチェックマークをクリックします。 

クリックすると拡大します

  • その後表示されるメソッドのセットアップ画面で、Lambda 関数の項目で「contactFunction (作成した Lambda 関数名)」を入力 (入力中に候補が表示されるので、クリックで OK です) します。
  • 「保存」ボタンをクリックします。

クリックすると拡大します

「OK」ボタンをクリックします。 

クリックすると拡大します

続いて、「統合リクエスト」をクリックします。

クリックすると拡大します

「マッピングテンプレート」をクリックし、「テンプレートが定義されていない場合 (推奨) 」を選択し、「マッピングテンプレートの追加」をクリックします。 

クリックすると拡大します

「application/json」と入力し、チェックマークをクリックします。

クリックすると拡大します

下にスクロールして、マッピングテンプレートの入力フィールドをクリックします。

下記の通りのテンプレートを入力して、「保存」をクリックします。

{
  "contact": $input.json("$.contact"),
  "title": $input.json("$.title"),
  "content": $input.json("$.content")
}

クリックすると拡大します

「アクション」から「CORS の有効化」をクリックします。

クリックすると拡大します

「CORS を有効にして既存の CORS ヘッダーを置換」ボタンをクリックします。 

クリックすると拡大します

「はい、既存の値を置き換えます」ボタンをクリックします。

クリックすると拡大します

「アクション」から「API のデプロイ」をクリックします。

クリックすると拡大します

「デプロイされるステージ」に「default」を選択し、「デプロイ」をクリックします。

クリックすると拡大します

次のページの上記に表示される URL の末尾に「/contactFunction」を追加した URL に対して、curl で POST メソッドのリクエストを送信して、動作確認しましょう。

クリックすると拡大します

curl -X POST -H "Content-Type: application/json" -d '{"title":"curl", "contact":"curl@example.com", "content": "I am so happy."}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/default/contactFunction
  • ターミナルにて、上記コマンドを実行して、登録したアドレスに正常にメールが送信されれば OK です。
  • xxxxxxxxxx」の部分は、実際に生成された URL の「https://」に続く部分を記述してください。
  • この「xxxxxxxxxx」の部分は後から使用しますので、コピーして撮っておいてください (忘れてしまった場合は再度マネジメントコンソールから Lambda 関数を表示して、API Gateway > 詳細 > API エンドポイントで確認していただけます)。

6. Vue.js プロジェクトを作成

Vue CLI を使って、必要な設定を行いながら Vue.js プロジェクトを作成していきます。

vue create コマンドを使って、contact という名前でプロジェクトを作成します。 

vue create contact

npm リポジトリの設定をします。
n を入力し Enter を押します。

?  Your connection to the default npm registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) n

設定方法の選択をします。
↑↓ でカーソル移動し、Manually select features を選択して Enter を押します。

Vue CLI v4.1.2
? Please pick a preset: 
  default (babel, eslint) 
❯ Manually select features 

追加パッケージを選択します。
下記の通り、Babel, Progressive Web App (PWA) Support, Router, Linter / Formatter を選択します。 ↑↓ でカーソル移動、Space で選択、Enter で決定します。

? Check the features needed for your project: 
 ◉ Babel
 ◯ TypeScript
 ◉ Progressive Web App (PWA) Support
❯◉ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

History モードを選択します。
y を入力し Enter を押します。

? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) y

ESLint の設定を選択します。
↑↓ でカーソル移動し、デフォルトの ESLint with error prevention only を選択して、Enter を押します。

 ? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only 
  ESLint + Airbnb config 
  ESLint + Standard config 
  ESLint + Prettier 

Lint のタイミングの設定をします。
↑↓ でカーソル移動、デフォルトの Lint on save を選択して、Enter を押します。

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

Config ファイルの設定をします。
↑↓ でカーソル移動し、デフォルトの In dedicated config files を選択して、Enter を押します。

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files 
  In package.json

今回の設定を保存指定次回以降に転用するかの選択を聞かれます。
任意ですが、今回は n を入力し Enter を押します。

? Save this as a preset for future projects? (y/N) n

Cloud9 環境をお使いの方は、Vue.js プロジェクトに Cloud9 向けの設定の追加が必要になります。

Cloud9 の仕組み上起動した開発環境のサーバーをうまくプレビューできないため設定を追加します。

参考リポジトリのcontact/vue.config.js を、作成しているプロジェクトで同じ階層になる様に

contact/vue.config.js

の様にコピーします

ここまで進めたら、テスト起動をしてみましょう。
開発環境のローカルサーバーを起動してプレビューし、問題なく Vue.js プロジェクトが立ち上がることを確認します。

次に Vue.js プロジェクトフォルダ (contact) に移動します。

cd contact

サーバーを起動します。

npm run serve

ローカルの PC をご利用の場合はブラウザで localhost:8080 にアクセスします。
Cloud9 をご利用の場合、画面の上部の Preview→Preview Running Application をクリックし、 Vue.js のデフォルト画面が表示されれば OK です。


7. フロントエンド側のコードを作成

ここまでで、API の作成と Vue.js のプロジェクトの作成ができました。
続いて、ユーザーが実際に問合せできる様にフォームを作成していきます。

今回は簡単な問合せフォームを作成するだけですが、手軽にマテリアルデザインを導入できるデザインフレームワークの Vuetify を導入します。
これにより、優れた UI のフォームを簡単に作成することができます。

以下を実行します。

vue add vuetify

Preset の選択をします。
Default (recommended) のまま、Enter を押します。 

? Choose a preset: (Use arrow keys)
❯ Default (recommended) 
  Prototype (rapid development) 
  Configure (advanced)

作成した API へリクエストを送信するためにライブラリ axios をインストールします。
以下のコマンドを実行します。

npm i axios

続いて、必要なコードを参考リポジトリからコピーしていきます。 

まずはお問い合わせフォームページのビューをコピーします。

./src/views/Contact.vue

contact/src/views/Contact.vue

となる様にコピーします。

また、169 行目に先ほど 5. Amazon API Gateway の設定の項目の最後に生成された API Gateway のエンドポイントを設定します。

# contact/src/views/Contact.vue#169

- baseURL: 'https://example_url.execute-api.ap-northeast-1.amazonaws.com'
+ baseURL: 'https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com' //3.API Gatewayの設定で生成されたエンドポイント

router/index.js ファイルを作成します。ルーティングの設定を記述するファイルです。
ログイン状態を管理してページのアクセス制御をします。

./src/router/index.js

の内容を

contact/src/router/index.js

に上書きします。

次に App.vue ファイルの作成をします。アプリケーションの共通レイアウトのコンポーネントです。
各ページへのナビゲーションを追加します。

./src/App.vue

の内容を

contact/src/App.vue

に上書きします。

最後に動作確認してみましょう。
すでにアプリケーションがローカルで起動している状態でしたら、一旦 ctrl + c でサーバーを停止してから、以下を実行してアプリケーションを起動し、プレビューしてみてください。

npm run serve

Contact ページからお問い合わせを送信し、設定したメールアドレスに感情解析の結果とともにお問い合わせ内容が届けば OK です。


8. フロントエンドのデプロイ

ここまでで、

  • バックエンドの本番環境
  • フロントエンドのコード

が完成しました。あとは、フロントエンドの本番環境のホスティングができれば完成です。

GitHub にコードをプッシュします。
まず、今までの変更を Git でコミットしていきます。

git add .
git commit -m 'built application'

その後、GitHub にサインインしてください。 
ユーザー名またはメールアドレスとパスワードを入力し、「Sign in」をクリックします。

クリックすると拡大します

上部ナビゲーションバー右上の をクリックし、New repository をクリックしてください。

クリックすると拡大します

Repository name に、contactと入力し、それ以外はデフォルトのまま Create repository をクリックしてください。

クリックすると拡大します

…or push an existing repository from the command line という項目をコピーし、ターミナルでプロジェクトフォルダにて実行してください。

git remote add origin https://github.com/ユーザー名/contact.git
git push -u origin master

クリックすると拡大します

下記のようにユーザー名、パスワードを求められるので、GitHubの ユーザー名 パスワードを入力してください。

Username for 'https://github.com/matsuihidetoshi/contact.git':ユーザー名
Password for 'https://matsuihidetoshi@github.com/matsuihidetoshi/contact.git':パスワード

これで、GitHub にコードがプッシュされ、デプロイの準備ができました。 

ここからは AWS Amplify コンソールを使ってデプロイします。
通常、Web ページをホスティングするには、サーバー構築・ネットワーク設定・ミドルウェアのインストール及び設定等が必要ですが、 Amplify コンソールを使用すると Web インターフェースから少ないステップで簡単にデプロイできます。

AWSマネジメントコンソールから、Amplify を検索し、選択します。  

クリックすると拡大します

GET STARTED をクリックします。  

クリックすると拡大します

Github の連携をします。
GitHub を選択し、Connect branch をクリックしてください。

クリックすると拡大します

GitHub の認証ページが開く場合は、ユーザー名またはメールアドレス と パスワード を入力してログインしてください。
OAuth によるアクセス許可の画面が表示されますので、Authorize aws-amplify-console をクリックしてください。

クリックすると拡大します

リポジトリは GitHub ユーザー名/contact を選択し、ブランチは master を選択し、次へ をクリックしてください。  

クリックすると拡大します

次へをクリックします。

クリックすると拡大します

確認画面が表示されますが、保存してデプロイをクリックしてください。  

クリックすると拡大します

ここから少し時間がかかりますが (10 分ほど)、デプロイのフローが終わるまでお待ちください。デプロイが完了してから URL のリンクをクリックすると、アプリケーションが開きます。

動作確認し、問題なければ完成です。おめでとうございます !

クリックすると拡大します


9. アプリケーションの削除

デプロイしたアプリケーションは、そのままにしておくとオンデマンドで費用が発生します。 料金をゼロにするためには、以下のようにアプリケーションリソース全体の削除を行います。

まずは Lambda 関数を呼び出すための API Gateway を削除します。

AWS マネジメントコンソールにアクセスし、「api」と入力し、検索結果 (プルダウン) の「API Gateway」をクリックします。

クリックすると拡大します

contactFunction-API のラジオボタンをクリックして、Actions のプルダンメニューの Delete をクリックします。

クリックすると拡大します

削除をクリックすれば、API Gateway の削除完了です。

クリックすると拡大します

続いて、Lambda 関数を削除していきます。

AWSマネジメントコンソールにアクセスし、「lambda」と入力し、検索結果 (プルダウン) の「Lambda」をクリックします。

クリックすると拡大します

contactFunction のラジオボタンをクリックして、アクションのプルダンメニューの削除をクリックします。

クリックすると拡大します

削除をクリックすれば、Lambda 関数の削除完了です。

クリックすると拡大します

続いて、Amplify コンソールからも削除をします。S3 にデプロイされたアプリケーションのフロントエンドも削除する必要があります。

Amplify コンソールを開き、全てのアプリ→ contact を選択してください。

クリックすると拡大します

画面右上のアクションから、アプリの削除を選択してください。  

クリックすると拡大します

確認用ダイアログが表示されるので、フォームに delete を入力し、Delete を押してください。

クリックすると拡大します

これで、今回のハンズオンで作成したアプリケーションの全てのリソースが削除されます。

今回のハンズオンのために Cloud9 環境を作成され、またその Cloud9 環境をこれ以降使用しない場合は、EC2 インスタンスタイプに応じた料金が発生しますので、そちらも別途削除しておいてください。

 

以上で終了です。お疲れ様でした !


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

松井 英俊 (まつい ひでとし)

浜松市の Web 制作会社でエンジニアをしながら、JAWS-UG 浜松支部の運営にも関わる。
プログラミングスクール講師も務める。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する