AWSの機械学習サービスを使ってアプリ開発!ChatGPTのオススメプロジェクトに挑戦②

M10i
2024-10-24
2024-10-24

はい、M10iです。
前回はサイコロで「多言語カスタマーサポートチャットボット」を作ろう!
とテーマだけ決まったところで終了しました。
前回はこちら

おさらい
ルール:
AWSの機械学習サービスをふたつランダムに組み合わせてアプリを作る。
どんなアプリかはchatGPTにオススメを聞いてその中から選ぶ。
サービスは以下の6つ。
1.Comprehend NLP。環状分析、言語検出
2.Rekognition 画像・動画解析、物体検出
3.Lex 会話型インターフェース。botなど
4.Polly テキスト読み上げ
5.Translate 自動翻訳
6.Transcribe 音声からのテキスト起こし


回は
Amazon Lex × Amazon Translateですね。M10iも触るの初めてです(楽しみ)

では早速LexでBotを作っていきたいと思います!

Amazon Lexを開いてBotを作成。なんと、サンプルが選べます。
lex_sumple
サンプルは執筆時点(2024/7/23)で3つありますが、そのうちの「Orderflowers」を選択。
そのままdefaultで作っていきます。
lex_intent
名前の通りにお花の注文ができるbotですね。
サンプルだけあって、サンプル発語やスロットがすでに設定されています。
lex_order
lex_slot
試しにテストしてみます。

lex_test
何もしなくてもBotが出来てしまいました。すごい!
chatGPT提案されたからの提案された内容が「グローバルなカスタマーサポートを多言語で提供し、よくある質問に自動応答」だったんですが、何についての質問かとかがふわっとしてたんですよね・・・・
ここでちょっと路線変更します!プロジェクトは
多言語カスタマーサポートチャットボット」から
花購買サービス多言語カスタマーサポートチャットボット」に進化しました!

ではBotを呼び出すwebページを作ります。
機械学習やってると言語はPythonを使う事が多いですよね?
てことでサーバサイドはPython、FWはdjangoで書いていきます。
(M10iのお気に入りなだけで、JavaでもNodejsでもaws sdkが使えれば何でもOKです)

スペースの都合でdjangoの詳細は省略して、サーバサイドのコードだけ記載しますー。

views.py

import boto3
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
import json

lex = boto3.client('lexv2-runtime')

def index(req):
    return render(req, 'test/index.html')

@csrf_exempt
def chat(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        user_message = data.get('message')
        session_id = data.get('sessionId')  # セッションIDを取得
        # Lex V2に送信
        lex_response = lex.recognize_text(
            botId='botid',
            botAliasId='AliasId',
            localeId='ja_JP',
            sessionId= session_id,
            text=user_message
        )
       # 結果を返す
        return JsonResponse({"response": lex_response['messages'][0]['content']})
return JsonResponse({"error": "Invalid request method"}, status=400)

 

コードはこれだけです。
boto3(aws用のライブラリ)を使ってlexを生成します。
※ここで"lex-runtime"だとlexのv1を参照してしまうので"lexv2-runtime"を指定します。
(ハマりポイント。1と2でfunctionが違うので注意)

botにテキストを送信するrecognize_textにパラメータを設定して実行します。
  botId='botのID'
  botAliasId='AliasのID'
  localeId='ja_JP'※テキストの言語 
  sessionId= 'ユニークキー'※会話を一意にするための値
text=テキスト(画面で入力したテキスト)

botのIDとAliasのIDはLexの設定画面で表示されてます。
あとはbotからのお返事を画面に返してます。

script.js

// セッションIDの生成と保存
function generateSessionId() {
    return 'session-' + Date.now();
}

// セッションIDをローカルストレージから取得または生成
function getSessionId() {
    let sessionId = localStorage.getItem('sessionId');
    if (!sessionId) {
        sessionId = generateSessionId();
        localStorage.setItem('sessionId', sessionId);
    }
    return sessionId;
}

// セッションIDをリセット
function resetSessionId() {
    localStorage.removeItem('sessionId');
    return generateSessionId();
}

// ページリロード時にセッションIDをリセット
window.addEventListener('beforeunload', () => {
    resetSessionId();
});

async function sendMessage() {
    const userInput = document.getElementById('user-input').value;
    const chatBox = document.getElementById('chat-box');
    const language = document.getElementById('language-selector').value;
    const sessionId = getSessionId(); // 現在のセッションIDを取得
    
    // ユーザーのメッセージをチャットボックスに追加
    chatBox.innerHTML += `<div class="message user-message">${userInput}</div>`;
    
    // メッセージをサーバーに送信
    const response = await fetch('chat', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ message: userInput, language: language, sessionId: sessionId })
    });
    const data = await response.json();
    
    // ボットのレスポンスをチャットボックスに追加
    chatBox.innerHTML += `<div class="message bot-message">${data.response}</div>`;
    
    // チャットボックスのスクロールを最新のメッセージまで自動で移動
    chatBox.scrollTop = chatBox.scrollHeight;

    // ユーザー入力フィールドをクリア
    document.getElementById('user-input').value = '';
}

botとの会話をキープ&リロードでクリアのため、sessionIdを生成してます。
以外は選択言語と入力テキストをpost、戻ってきたbotの返事を画面に表示してます。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flower Order Chatbot</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="chat-container">
        <div id="chat-box"></div>
        <div id="user-input-container">
            <select id="language-selector">
                <option value="ja">日本語</option>
                <option value="en">English</option>
                <option value="fr">Français</option>
                <option value="zh">中文</option>
            </select>
            <input type="text" id="user-input" placeholder="Type your message here...">
            <button id="send-button" onclick="sendMessage()">Send</button>
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>

style.css

body {
    font-family: Arial, sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    margin: 0;
    background-color: #f4f4f4;
}

#chat-container {
    width: 90%;
    max-width: 800px;
    border: 1px solid #ccc;
    border-radius: 10px;
    background-color: #fff;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

#chat-box {
    padding: 10px;
    height: 400px;
    overflow-y: scroll;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.message {
    padding: 10px;
    border-radius: 10px;
    max-width: 70%;
    word-wrap: break-word;
}

.user-message {
    align-self: flex-end;
    background-color: #d1f7d6;
    color: #000;
}

.bot-message {
    align-self: flex-start;
    background-color: #e0e0e0;
    color: #000;
}

#user-input-container {
    display: flex;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
    background-color: #f9f9f9;
    border-top: 1px solid #ddd;
}

#user-input {
    flex: 1;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    margin-right: 10px;
}

#send-button {
    padding: 10px 20px;
    border: none;
    background-color: #007bff;
    color: #fff;
    border-radius: 5px;
    cursor: pointer;
}

#send-button:hover {
    background-color: #0056b3;
}

 

では実行してみましょう!
lex_no_tran
左がbotの返事、右が筆者です。
これだけで普通にbotが出来てますね。
htmlとcssはchatGPT君にお願いしただけですが、いい感じにbotアプリ感があります。素敵。

では、ここにAmazon Translateを実装していきます。
え?まだやるの?って思いました?汗
実はTranslateはboto3で使えるのです。用意不要なんです!
あとここに数行の追加で完成しちゃいますのでもう少しだけお付き合いくださいm(_ _)m

views.py(ピンクの字の部分が追加・変更コード)

import boto3
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
import json

translate = boto3.client('translate')
lex = boto3.client('lexv2-runtime')

def index(req):
    return render(req, 'test/index.html')

def translate_text(text, source_language, target_language):
    response = translate.translate_text(
        Text=text,
        SourceLanguageCode=source_language,
        TargetLanguageCode=target_language
    )
    return response['TranslatedText']

@csrf_exempt
def chat(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        user_message = data.get('message')
        user_language = data.get('language')
        session_id = data.get('sessionId')  # セッションIDを取得

        # ユーザーメッセージを日本語に翻訳
        translated_message = translate_text(user_message, user_language, 'ja')

        # Lex V2に送信
        lex_response = lex.recognize_text(
            botId='botid',
            botAliasId='AliasId',
            localeId='ja_JP',
            sessionId= session_id,
            text=translated_message
        )
        
        # Lex V2からのレスポンスをユーザーの言語に翻訳
        bot_response = translate_text(lex_response['messages'][0]['content'], 'ja', user_language)
        
        return JsonResponse({"response": bot_response})

    return JsonResponse({"error": "Invalid request method"}, status=400)

translateを生成して、translate_textにテキストとその言語、翻訳対象の言語(ここではbotが日本語で作ってあるので日本語)を渡すと翻訳されます。
画面からはドロップダウンで送る言語を選んでからその言語でテキストを入力します。

では、さっそく英語で注文してみます。

lex_en
結果は・・・
ちゃんと英語で動作しますね!
lex_en2

続いて中国語も試してみましょう。
lex_ch
※薔薇って薔薇じゃなくて「玫瑰」なんですね。
こんな複雑な漢字なのに日本でしか通じないんですね薔薇・・・

結果は・・・
ちゃんと中国語で動作しますね!
lex_ch2

フランス語、日本語も問題なさそうです。
lex_all
※demain=フランス語で「明日」 
 記事書いてるのが2024/7/23なので2024/7/24が受取日になります。

なんと、わずかこれだけの手間とコードでアプリが出来てしまいました。
イレギュラー処理や権限など、いろいろすっ飛ばしてるのでそこはご愛敬ですが汗
あと気づいたんですが、入力されたテキストをComprehendにかけてあげればドロップダウンの言語選択不要で実装できますね。

・・すごいですね、aws。恐ろしい子・・・

ではでは。次回はサイコロと同時にアプリ作っていきたいと思います!
何がでるかな、何がでるかな~♪・・・M10iでした。