.lg ファイル形式

この記事の対象: SDK v4

.lg ファイルでは、エンティティ参照とそれらの合成が含まれる言語生成テンプレートについて記述します。 この記事では、.lg ファイル形式で表現されるさまざまな概念について説明します。

特殊文字

Comments

> を使用してコメントを作成します。 このプレフィックスが付いたすべての行は、パーサーでスキップされます。

> This is a comment.

エスケープ文字

\ をエスケープ文字として使用します。

# TemplateName
- You can say cheese and tomato \[toppings are optional\]

配列とオブジェクト

配列を作成する

配列を作成するには、${[object1, object2, ...]} という構文を使用します。 たとえば、次の式の場合

${['a', 'b', 'c']}

配列 ['a', 'b', 'c'] を返します。

オブジェクトを作成します

オブジェクトを作成するには、${{key1:value1, key2:value2, ...}} という構文を使用します。 たとえば、次の式の場合

${{user: {name: "Wilson", age: 27}}}

次の JSON オブジェクトを返します。

{
  "user": {
    "name": "Wilson",
    "age": 27
  }
}

テンプレート

テンプレートは、言語生成システムの中核的な概念です。 各テンプレートに名前が付いていて、以下のいずれかが含まれています。

  • one-of バリエーションのテキスト値のリスト
  • 構造化されたコンテンツ定義
  • 条件のコレクション。それぞれに以下が含まれています。

テンプレート名

テンプレート名では大文字と小文字が区別され、文字、アンダースコア、数字のみを含めることができます。 TemplateName という名前のテンプレートの例を次に示します。

# TemplateName

テンプレートは数字で始めることはできません。また、「.」で分割されたテンプレート名のどの部分も数字で始めることはできません。

テンプレート応答のバリエーション

バリエーションは、Markdown リストとして表現されます。 各バリエーションには、-'、または + 文字を使用してプレフィックスを付けることができます。

# Template1
- text variation 1
- text variation 2
- one
- two

# Template2
* text variation 1
* text variation 2

# Template3
+ one
+ two

単純な応答テンプレート

単純な応答テンプレートには、合成と展開に使用されるテキストのバリエーションが 1 つ以上含まれています。 提供されているバリエーションの 1 つが、LG ライブラリによってランダムに選択されます。

次に、2 つのバリエーションが含まれる単純なテンプレートの例を示します。

> Greeting template with two variations.
# GreetingPrefix
- Hi
- Hello

条件付き応答テンプレート

条件付き応答テンプレートでは、条件に基づいて選択されるコンテンツを作成できます。 すべての条件は、アダプティブ式を使用して表します。

重要

1 つの条件付き応答テンプレートの中で、条件付きテンプレートを入れ子にすることはできません。 構造化された応答テンプレートで合成を使用して、条件を入れ子にします。

if-else テンプレート

if-else テンプレートでは、連鎖している条件の順序に基づいてコレクションを選択するテンプレートを作成できます。 評価は、上から実行され、条件が true に評価されたとき、または ELSE ブロックにヒットしたときに停止します。

条件付きの式は中かっこの ${} で囲みます。 次の例は、単純な IF ELSE 条件付き応答テンプレート定義を示しています。

> time of day greeting reply template with conditions.
# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - good morning
- ELSE:
    - good evening

次の別の例は、if-else 条件付き応答テンプレート定義を示していす。 どの条件のバリエーションにも、その他の単純な応答テンプレートや条件付き応答テンプレートへの参照を含められることに注意してください。

# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - ${morningTemplate()}
- ELSEIF: ${timeOfDay == 'afternoon'}
    - ${afternoonTemplate()}
- ELSE:
    - I love the evenings! Just saying. ${eveningTemplate()}

switch テンプレート

switch テンプレートでは、式の値を CASE 句に一致させるテンプレートを設計し、その場合に基づいた出力を生成できます。 条件式は中かっこの ${} で囲みます。

次に、LG 内に SWITCH CASE DEFAULT ブロックを指定できる方法を示します。

# TestTemplate
- SWITCH: ${condition}
- CASE: ${case-expression-1}
    - output1
- CASE: ${case-expression-2}
    - output2
- DEFAULT:
   - final output

次に、より複雑な SWITCH CASE DEFAULT の例を示します。

> Note: Any of the cases can include reference to one or more templates.
# greetInAWeek
- SWITCH: ${dayOfWeek(utcNow())}
- CASE: ${0}
    - Happy Sunday!
-CASE: ${6}
    - Happy Saturday!
-DEFAULT:
    - ${apology-phrase()}, ${defaultResponseTemplate()}

Note

条件付きテンプレートと同様に、switch テンプレートも入れ子にすることはできません。

構造化された応答テンプレート

構造化された応答テンプレートでは、テンプレート作成や合成などの主な LG 機能をサポートする複雑な構造を定義できます。その一方で、構造化された応答の解釈は LG ライブラリの呼び出し元に任せます。

ボット アプリケーションの場合、以下がネイティブでサポートされています。

  • アクティビティ定義
  • カード定義

詳細については、応答テンプレートの構造化に関するページを参照してください。

テンプレートの合成と展開

テンプレートへの参照

バリエーション テキストには、洗練された応答の合成と解決を助けるため、別の名前付きテンプレートへの参照を含めることができます。 その他の名前付きテンプレートへの参照は、${<TemplateName>()} などの中かっこを使用して示されます。

> Example of a template that includes composition reference to another template.
# GreetingReply
- ${GreetingPrefix()}, ${timeOfDayGreeting()}

# GreetingPrefix
- Hi
- Hello

# timeOfDayGreeting
- IF: ${timeOfDay == 'morning'}
    - good morning
- ELSEIF: ${timeOfDay == 'afternoon'}
    - good afternoon
- ELSE:
    - good evening

GreetingReply テンプレートを呼び出すと、次のいずれかの展開による解決となる可能性があります。

Hi, good morning
Hi, good afternoon
Hi, good evening
Hello, good morning
Hello, good afternoon
Hello, good evening

エンティティ

one-of バリエーション テキスト内で直接使用する場合、エンティティ参照は、$ {entityName} のように中かっこで囲むことによって示されます。パラメーターとして使用する場合は中かっこを使用しません。

エンティティは、パラメーターとして使用できます。

バリエーションでの事前構築済み関数の使用

アダプティブ式でサポートされている事前構築済み関数は、one-of バリエーション テキスト内でインラインで使用し、さらに強力なテキスト合成を実現することもできます。 式をインラインで使用するには、単にそれを中かっこで囲みます。

# RecentTasks
- IF: ${count(recentTasks) == 1}
    - Your most recent task is ${recentTasks[0]}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) == 2}
    - Your most recent tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSEIF: ${count(recentTasks) > 2}
    - Your most recent ${count(recentTasks)} tasks are ${join(recentTasks, ', ', ' and ')}. You can let me know if you want to add or complete a task.
- ELSE:
    - You don't have any tasks.

上の例では、recentTasks コレクション内のすべての値を一覧表示するために、join 事前構築済み関数を使用しています。

テンプレートと事前定義済み関数が同じ呼び出しシグネチャを共有しているとすると、テンプレートの名前を、事前定義済み関数の名前と同じにすることはできません。

テンプレート名は、事前構築済み関数名と一致してはいけません。 事前構築済み関数が優先されます。 このような競合を回避するには、テンプレート名を参照するときに、lg. を前に付加します。 次に例を示します。

> Custom length function with one parameter.
# length(a)
- This is use's customized length function

# myfunc1
> will call prebuilt function length, and return 2
- ${length('hi')}

# mufunc2
> this calls the lg template and output 'This is use's customized length function'
- ${lg.length('hi')}

バリエーション内の複数行テキスト

各 one-of バリエーションには、3 つの引用符で囲んだ複数行テキストを含めることができます。

# MultiLineExample
    - ```This is a multiline list
        - one
        - two
        ```
    - ```This is a multiline variation
        - three
        - four
    ```

複数行のバリエーションでは、要求された操作を中かっこ ${} で囲むことによって、テンプレートの展開とエンティティの置換を要求できます。

# MultiLineExample
    - ```
        Here is what I have for the order
        - Title: ${reservation.title}
        - Location: ${reservation.location}
        - Date/ time: ${reservation.dateTimeReadBack}
    ```

複数行のサポートにより、言語生成サブシステムで複雑な JSON や XML (ボットの音声応答を制御するための、SSML でラップされたテキストなど) を完全に解決できます。

テンプレートのパラメーター化

コンテキストの再利用性を促進するために、テンプレートをパラメーター化できます。 テンプレートに対するさまざまな呼び出し元は、展開解決で使用するさまざまな値を渡すことができます。

# timeOfDayGreetingTemplate (param1)
- IF: ${param1 == 'morning'}
    - good morning
- ELSEIF: ${param1 == 'afternoon'}
    - good afternoon
- ELSE:
    - good evening

# morningGreeting
- ${timeOfDayGreetingTemplate('morning')}

# timeOfDayGreeting
- ${timeOfDayGreetingTemplate(timeOfDay)}

外部参照のインポート

言語生成テンプレートを個々のファイルに分割し、1 つのファイルから別のファイルのテンプレートを参照することができます。 Markdown スタイルのリンクを使用して、別のファイルで定義されているテンプレートをインポートできます。

[Link description](filePathOrUri)

ターゲット ファイルで定義されているすべてのテンプレートが取り込まれます。 取り込まれるファイルにわたってテンプレート名が一意である (または # \<namespace>.\<templatename> を使用して名前空間が指定されている) ようにします。

[Shared](../shared/common.lg)

LG によって挿入される関数

アダプティブ式には、関数のカスタム セットを挿入する機能が用意されています。 詳細については、LG ライブラリから挿入される関数に関するページを参照してください。

[オプション]

開発者は、パーサー オプションを設定して、入力の評価方法をさらにカスタマイズできます。 > !# 表記を使用してパーサー オプションを設定します。

重要

ファイルで見つかった最後の設定が、同じドキュメントで前に見つかったすべての設定よりも優先されます。

strict オプション

開発者は、null の評価結果に対して null の結果を許容しない場合、strict オプションを実装できます。 次に、strict オプションの簡単な例を示します。

> !# @strict = true
# template
- hi

strict オプションがオンの場合、null エラーはわかりやすいメッセージをスローします。

# welcome
- hi ${name}

name が null の場合、診断は、"'name' evaluated to null. [welcome] Error occurred when evaluating '- hi ${name}'. ('name' が null に評価されました。[welcome] '- hi $ {name} ' の評価中にエラーが発生しました。)" になります。 strict が false に設定されていか、設定されていない場合、互換性のある結果が得られます。 上のサンプルでは、hi null が生成されます。

replaceNull オプション

開発者は、replaceNull オプションを使用して、評価された式内の null 値を置換するデリゲートを作成できます。

> !# @replaceNull = ${path} is undefined

上の例では、path 変数の null 入力は、${path} is undefined (${path} は未定義です) に置き換えられます。 次の入力で、user.name が null である場合は、

hi ${user.name}

hi user.name is undefined (やあ、user.name は未定義です) になります。

lineBreakStyle オプション

開発者は lineBreakStyle オプションを使用して、LG システムで改行をレンダリングする方法のオプションを設定できます。 現在、次の 2 つのモードがサポートされています。

  • default: 複数行テキスト内の改行は、通常の改行になります。
  • markdown: 複数行テキスト内の改行は、改行を作成するために自動的に 2 行に変換されます

次の例は、lineBreakStyle オプションを markdown に設定する方法を示しています。

> !# @lineBreakStyle = markdown

Namespace オプション

エクスポートする LG テンプレートの名前空間を登録できます。 名前空間が指定されていない場合、名前空間は拡張子のないファイル名に設定されます。

次の例は、namespace オプションを foo に設定する方法を示しています。

> !# @Namespace = foo

Exports オプション

エクスポートする LG テンプレートの一覧を指定できます。 エクスポートされたテンプレートは、事前に構築された関数と同様に呼び出すことができます。

次の例は、exports オプションを template1, template2 に設定する方法を示しています。

> !# @Namespace = foo
> !# @Exports = template1, template2

# template1(a, b)
- ${a + b}

# template2(a, b)
- ${join(a, b)}

これらのエクスポートされたテンプレートを呼び出すには、foo.template1(1,2), foo.template2(['a', 'b', 'c'], ',') を使用します。

キャッシュ スコープ

キャッシュ スコープ オプションを使用すると、LG エバリュエーターが以前に見た式を再評価するタイミングと、キャッシュされた結果を格納して使用するタイミングを制御できます。

  • グローバル キャッシュは、評価のライフ サイクルで有効です。 LG はすべての評価結果をキャッシュし、テンプレート名とパラメーターが同じ場合は、キャッシュから結果を返します。
  • 既定値はローカル キャッシュ スコープです。 同じレイヤで、前のテンプレートが同じテンプレート名と同じパラメーターで呼び出された場合、キャッシュされた結果が直接返されます。
  • None キャッシュ スコープではすべてのキャッシュ スコープが無効になり、毎回新しい結果が返されます。

例については、グローバル キャッシュ スコープとローカル キャッシュ スコープの例を参照してください。

> !# @cacheScope= global // global cache
> !# @cacheScope= local // local cache
> !# @cacheScope= none // none cache
> !# @cacheScope= xxx // fallback to local cache

キャッシュ スコープ オプションでは大文字と小文字は区別されません。

> !# @cacheScope= global // ok
> !# @CACHESCOPE= global // ok
> !# @cachescope= global // ok

キャッシュ スコープは、Microsoft Entrance .lg ファイルのスコープに従います。

次に示すように、a.lgb.lg という 2 つのファイルがあるとします。

a.lg

> !# @cacheScope= global
 [import](b.lg)

b.lg

> !# @cacheScope= none
# template1
- ${template2()} ${template2()}

# template2
- ${rand(1, 10000000)}

次のコードを実行すると、a.lgglobal キャッシュ スコープ オプションが原因で、template2 では最初に評価された結果のキャッシュされた結果が使用されていることがわかります。

var templates = Templates.ParseFile("a.lg");
var result = templates.Evaluate("template1"); // the second "template2" would use the cache of the first evaluate result

再実行マークの影響

テンプレート名が "!"で終わる場合、テンプレートは強制的に再実行します。 キャッシュ スコープに関係なく、この結果はキャッシュに追加されません。

次のテンプレートがあるとします。

# template2
- ${template1()} ${template1!()} ${template1()}

template1!() が起動し、結果がキャッシュに追加されます。 2 つ目の template1() は、最初の template1() の結果を上書きします。 最後の呼び出しでは、キャッシュに格納されている結果が使用されます。

グローバル キャッシュ スコープの例

次のテンプレートがあるとします。

# template1
- ${template2()} ${template3()}

# template2
- ${rand(1, 10)}
- abc
- hi

# template3
- ${template2()}

template2 は 1 回評価され、template3 の 2 回目の実行では最初の実行のキャッシュが適用されます。

別の例を次のコード スニペットで示します。

var templates = Templates.ParseFile("xxx.lg");
var result1 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});

// The second evaluation would drop all the results cached before.
var result2 = templates.Evaluate("template", null, new EvaluationOptions { CacheScope = LGCacheScope.Global});

テンプレートは Templates.ParseFile() 関数を使用して解析され、テンプレートの評価結果は result1 に格納されます。 2 番目の評価結果 result2 では、以前にキャッシュされたすべての結果が削除されることに注意してください。

ローカル キャッシュ スコープの例

次の例は、ローカル キャッシュ スコープが機能する場合と機能しない場合を示しています。 パラメーターを受け取る t()subT() というテンプレートを想定します。

>  Cache works, the second template call would re-use the first's result.
# template1
- ${t(param)} ${t(param)}

> Cache doesn't work because param1's value is different with param2's. value)
# template2
- ${t(param1)} ${t(param2)}

> Cache doesn't work because of different layers.
# template3
- ${subT(param1)} ${t(param2)}

# subT(param)
- ${t(param)}

その他のリソース