アルパカのメモ

Language Generator

はじめに

参考:

Language Generator は、ボットからのメッセージをテンプレート化する仕組み。 ボットのセリフをリソースファイルに隔離して管理できる。 リソースファイルには条件式の指定やStateの参照が可能で、より自然なボットのセリフを構築できる。

リソースファイルの拡張子は .lg で、通常は利用する Dialog クラスと1対1で作成し、Dialog クラスと同じフォルダに配置する。 lgファイルのプロパティを変更し、「出力ディレクトリにコピー」するようにしておくこと。 文字コードは、UTF-8-BOM にする(BOM無しでも大丈夫っぽい)。

サンプルとして、 Dialogs/RootDialog.lg を作成した。

# Nothing
- nothing1!
- nothing2!

次に RootDialog をLGを使うように変更する。

public class RootDialog : AdaptiveDialog
{
    public RootDialog() : base(nameof(RootDialog))
    {
        Triggers = new List<OnCondition>
        {
            new OnConversationUpdateActivity()
            {
                Actions =
                {
                    new CodeAction(WelcomeUser)
                }
            },
            new OnUnknownIntent()
            {
                Actions =
                {
                    new SendActivity("${Nothing()}")
                }
            },
        };

        string[] paths = { ".", "Dialogs", "RootDialog.lg" };
        string fullPath = Path.Combine(paths);

        Generator = new TemplateEngineLanguageGenerator(Templates.ParseFile(fullPath));
    }
    // 略
}

これでボットをテストすると、「nothing1!」か「nothing2!」のいずれかを返すようになる。

CodeAction 内でLGを使う

Adaptive Dialog の Action 類からLGを使うときは ${テンプレート名()} で良いが、自分で Action の内容を実装したときにLGを使う方法を示す。

private static async Task<DialogTurnResult> OriginalAction(DialogContext dc, object options)
{
    var template = new ActivityTemplate("${Greeting()}");
    var message = await template.BindAsync(dc, dc.State);
    await dc.Context.SendActivityAsync(message);
}

条件式や関数

LGファイルに以下のような定義を追加し、時間帯に合わせて挨拶を変えることができたりする。

# timeOfDay
- ${getTimeOfDay(convertFromUTC(utcNow(), 'Asia/Tokyo'))}

# Greeting
- IF: ${timeOfDay() == 'morning'}
  - おはよう!
- ELSEIF: ${timeOfDay() == 'afternoon'}
  - こんにちは!
- ELSE:
  - こんばんは!

Dialog の方で ${Greeting()} を参照すれば、朝なら「おはよう」、昼なら「こんにちは」と喋らせることができる。 Greeting のIF文で timeOfDay を参照しているように、LGのあるテンプレートから他のテンプレートを参照することが可能。 変数を定義&参照するような感覚で使える。

Adaptive Card をつかう

.lg ファイルには Adaptive Card の付いたメッセージも定義できる。 まずカードの json をテンプレートとして定義する。

# SampleCard
- ```
{
    "type": "AdaptiveCard",
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.3",
    "body": [
        {
            "type": "TextBlock",
            "text": "Hello!",
            "wrap": true
        }
    ]
}
```

次に、カードの json を Attachment として取り込むテンプレートを定義する。

# Greeting
[Activity
    Attachments = ${json(SampleCard())}
]

SendActivity のアクションで、このテンプレート(Greeting)を指定するとカードが送られる。