react-native-giftedChatとQnA Makerでチャットボットアプリ作成

# はじめに
reac-native-giftedChatライブラリとQnA Makerサービスを用いてチャットボットアプリを作成します。
ReactNativeのアプリ上にチャットボット機能を実装する事がありましたので、備忘録として記事に纏めます。

# react-native-giftedChat
綺麗なチャット画面を作る為のライブラリです。チャットボットに限ったものではない為、いわゆる人間同士のチャット画面として利用できます。今回はUser(利用者)とBot(チャットボット)の2人物のやりとりという形で画面を作成します。

ステートのmessages配列で一連の会話内容を管理します。messageオブジェクトの要素は下記の通りです。

* _id  ...messages内で一意の番号
* text ...表示する文字列
* createdAt ...投稿時のタイムスタンプ
* user ...メッセージの投稿者


# QnA Maker
Microsoft社が提供しているコグニティブサービスの1つです。
専用ポータルから質問と回答の組み合わせを登録することで、簡単にボットサービスを作成できます。

詳細なデプロイ方法については割愛しますが、公式のクイックスタートがとても分かりやすかったです。
(https://docs.microsoft.com/ja-jp/azure/cognitive-services/QnAMaker/Quickstarts/create-publish-knowledge-base)

デプロイ完了後にテスト用の質問と回答のペアを登録します。
公式が提供しているチャットのデータセットがあるので、こちらをインポートします。(https://github.com/microsoft/botframework-cli/blob/main/packages/qnamaker/docs/chit-chat-dataset.md)

回答ペア登録完了後、Publishタブから公開することで、回答生成のAPIを確認できます。API呼び出しに使う為、{}で囲まれた3つの値を控えておきます。
- https://{QnA-Maker-endpoint}/knowledgebases/{knowledge-base-ID}/generateAnswer
- Authorization: EndpointKey {QnA Makerのエンドポイントキー}

![スクリーンショット 2021-12-07 0.16.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272171/f4b30f0d-8b18-3147-d296-1bd6a05fb0e9.png)



# 処理の流れ
チャットボット画面の全体の処理の流れは下記の通りです。
1. チャット画面からテキストを入力
2. 入力内容からmessageオブジェクトを作成（User側)
3. ステートのmessages配列に追加
4. QnA MakerのAPIを呼び出し
5. 返答からmessageオブジェクトを作成（Bot側）
6. ステートのmessages配列に追加

# ライブラリのインストール
'react-native-gifted-chat'をインストールします。
```
npm install react-native-gifted-chat --save
```

また、メッセージの採番用に'react-native-uuid'もインストールします。
```　
npm install react-native-uuid --save
```

# コード
App.jsは下記の通りです。expoで動作する事を確認しています。

```App.js
import { StyleSheet } from 'react-native';
import { GiftedChat } from 'react-native-gifted-chat';
import React, { useState, useCallback, useEffect } from 'react';
import uuid from 'react-native-uuid';

const CHAT_URL = 'https://{QnA-Maker-endpoint}/knowledgebases/{knowledge-base-ID}/generateAnswer'
const ENDPOINT_KEY = 'EndpointKey {QnA Makerのエンドポイントキー}'

/* 利用者(画面右側) */
const USER = {
  _id: 1,
  name: 'Me',
}
/* ボット(画面左側) */
const BOT = {
  _id: 2,
  name: 'Bot',
  avatar: 'https://placeimg.com/140/140/any',
}

export default function App() {
  /* メッセージを保持するステート */
  const [messages, setMessages] = useState([]);
  useEffect(() => {
    /* 初回画面表示時のメッセージ */
    setMessages([
      {
        _id: uuid.v4(),
        text: '質問はありますか？',
        createdAt: new Date(),
        user: BOT,
      },
    ])
  }, [])

  /* QnA MakerのgenerateAnswerAPIをコール */
  const generateAnswer = async (message) => {
    try {
     const response = await fetch(CHAT_URL, {
      method: 'POST',
      headers: {
        Authorization: ENDPOINT_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        question: message,
      })
    })
     const json = await response.json();
     const responseMessages = {
       _id: uuid.v4(),
       text: json.answers[0].answer,
       createdAt: new Date(),
       user: BOT,
     }
     /* レスポンスをmessagesに追加 */
     setMessages(previousMessages => GiftedChat.append(previousMessages, responseMessages))
    } catch (error) {
     console.error(error);
   }
 }

 /* テキスト送信時の処理　入力内容をmessagesに追加後、QnA MakerのAPIをコールする */
  const onSend = useCallback((messages = []) => {
    setMessages(previousMessages => GiftedChat.append(previousMessages, messages));
    generateAnswer(messages[0].text);
  }, [])

  return (
    <GiftedChat
      messages={messages}
      onSend={messages => onSend(messages)}
      user={USER}
    />
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

```

# 完成イメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272171/a0fb0f4e-effe-7235-7a6b-557473739fce.png" width=50%>

# まとめ
画面はチャット用のライブラリ、バックエンドはAzureのサービスという簡単な構成ではあったのですが、意外とそれっぽく動かせています。Q&Aの内容はポータルからいつでも更新も可能な上、quickRepliesを用いればマルチターン回答(選択肢つきの回答)も実現できそうなので、拡張性もあるのではと思っています。

# 参考URL
- react-native-giftedChat (https://github.com/FaridSafi/react-native-gifted-chat)
- QnA Makerポータル (https://www.qnamaker.ai/)
- QnA MakerのGenerateAnswer APIドキュメント (https://docs.microsoft.com/ja-jp/azure/cognitive-services/qnamaker/how-to/metadata-generateanswer-usage)
- Teamsで使えるQ&Aチャットボットを60分で組み立てる(QnA Maker)(https://qiita.com/abemaki29/items/b0933e3ee51cb5220400)