QnAMakerのmetadataとfilter機能について

Qiita初投稿です🎉
QnAmakerのチャットボット開発をしています。
今回はQnAMakerのmetadataとfilter機能について紹介します。

## QnAmakerとは
MicrosoftのCognitiveServiceの一つで、質問と回答を用意すれば簡単にお問合せチャットボットを作れるというものです。
用意した質問文と回答文を学習して、問いかけを投げると、問いかけの質問文と近いQAのペアを返してくれます。

## metadataとは
metadataとは、QnAmakerにQAを学習させる際に、質問文と回答文以外に情報を付加することができます。付加する情報は、{key:value}の形で付加します。
QnAmakerの画面で見ると下記のような感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/41085726-1d10-466a-8855-b5b51898e283.png)


## filter機能を使う
filter機能は先ほどのmetadataを利用して回答をフィルターします。
QnAmakerが回答を返す際に、返す回答の中からのQAに指定した{Key}の{value}でフィルターして回答を返してくれます。

#### どういうときに使うのか？
使い方は工夫次第で色々と使えますが、
**同じ質問文でも回答文が違う場合**に使うのが基本です。
上述のmetadataの例の通り、同じ質問文「ログインできません」に対してOSによって回答が違う場合です。
上記のナレッジを使ってボットを作るとこんな感じ↓
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/230c9b16-f970-353f-87a2-b732db92a4b5.png)



#### 実装方法
上記のチャットボットは、下記フローで実装しています。

1. welcomeメッセージ「質問はございますか？」
2. ユーザーが質問文を投げる
3. QnAmakerを呼ぶ（filter機能なし）
4. 回答のmetadataのkeyにOSが含まれていれば、OSの種類を聞く
5. **再度QnAmakerを呼ぶ（{OS:ユーザーの回答したOS}でfilter）**

会話フローはbotbuilderV3.0のBasicテンプレート（C#）をカスタマイズして実装しています。
filter機能を使っている部分のサンプルコードは以下になります。

```C#:GetQnafilter.cs
public class GetQnAmakerResult
   
    {
        static string qnamakerhost = ConfigurationManager.AppSettings["hostId"];
        static string endpoint_key = ConfigurationManager.AppSettings["endpointKey"];
        static string knowleadgebaseid = ConfigurationManager.AppSettings["QnAKnowledgebaseId"];
        static string service = "/qnamaker";

        public class QnamakerReslt
        {
            public Answer[] answers { get; set; }
        }

        public class Answer
        {
            public string[] questions { get; set; }
            public string answer { get; set; }
            public float score { get; set; }
            public string id { get; set; }
            public string source { get; set; }
            public Meta[] metadata { get; set; }
        }
        public class Meta
        {
            public string name { get; set; }
            public string value { get; set; }
        }

        public class PostQnamaker
        {
            public string question { get; set; }
            public int top { get; set; }
            public List<Filters> strictFilters { get; set; }

            public PostQnamaker()
            {
                strictFilters = new List<Filters>();
            }

        }

        public class Filters
        {
            public string name { get; set; }
            public string value { get; set; }
        }


        public static async Task<QnamakerReslt> GetResult(string question, int option)
        {
            PostQnamaker postqnamaker = new PostQnamaker();
            Filters filters = new Filters();

            string method = "/knowledgebases/" + knowleadgebaseid + "/generateAnswer?/";

            var client = new HttpClient();
            var request = new HttpRequestMessage();

            var queryString = HttpUtility.ParseQueryString(string.Empty);

            postqnamaker.question = question;
            postqnamaker.top = option;

            filters.name = "keyの名前を入れる！";
            filters.value = "valueの名前を入れる！";

            postqnamaker.strictFilters.Add(filters);

            string requestquestion = JsonConvert.SerializeObject(postqnamaker);

            var uri = qnamakerhost + service + method;

            request.Method = HttpMethod.Post;

            request.RequestUri = new Uri(uri);

            request.Headers.Add("Authorization", "EndpointKey " + endpoint_key);

            request.Content = new StringContent(requestquestion, Encoding.UTF8, "application/json");

            var response = await client.SendAsync(request);

            QnamakerReslt jres = await response.Content.ReadAsAsync<QnamakerReslt>(new[] { new JsonMediaTypeFormatter() });

            return jres;

        }

    }

```


## その他使用例
##### カテゴリー毎のお問い合わせ対応
metadataには｛category:categoryname｝を入れます。
例えば下記のようなチャットで使えます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/abe33d6f-fa5c-5cfd-35a2-962c746d62c0.png)
office365の問い合わせでは製品ごとに同じ質問文があるので最初に製品名（カテゴリー）を聞いて回答をフィルターするといったケースです。
ナレッジを分ける方法もありますが、ナレッジを作りすぎるとお金かかるので。


##### 画像付きで回答する
本来QnAmakerの回答コンテンツは文字のみですが、metadataを利用すると画像付きで回答を返すことができます。(正攻法ではないですが。)
metadataに{picurl:url}を入れます。例｛picurl:http://blob~｝
取得したmetadataのURLから回答を作成するといった感じです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/195221/45a61aac-61a9-31a8-07fc-4ab1b13296a7.png)

QnAmakerで画像を出すことができますが、管理が難しくなるため（ポータル上ではURLしかわからないため）私はWordPressでQAを管理して、QnAmakerと連携しています。詳細はまた記事にしようと思います。


## 最後に
QnAmakerは質問と回答だけではなく、metadataを使って少し応用すれば問い合わせチャットボットの幅も広がります。
みなさんのチャットボット開発の少しでも手助けになれば幸いです。

あっ、早くbotserviceV4.0試さないと。。。