Формат файлов .lg
ОБЛАСТЬ ПРИМЕНЕНИЯ: ПАКЕТ SDK версии 4
В lg-файле описываются шаблоны создания языка со ссылками на сущности и их композицией. В этой статье рассматриваются различные понятия, выраженные в формате LG-файла.
Специальные символы
Комментарии
> позволяет создать комментарий. Средство синтаксического анализа будет пропускать все строки с этим префиксом.
> This is a comment.
Escape-символ
Используйте \ в качестве escape-символа.
# 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
}
}
Шаблоны
Шаблоны можно считать основным понятием в системе создания текста. Каждый шаблон имеет имя и что-то одно из следующего:
- список текстовых значений для однократных вариантов;
- определение структурированного содержимого;
- коллекция условий, каждая из которых:
- адаптивное выражение;
- список текстовых значений для однократных вариантов по условиям.
Имена шаблонов
Имена шаблонов чувствительны к регистру и могут содержать только буквы, подчеркивания и цифры. Ниже приведен пример шаблона с именем TemplateName
.
# TemplateName
Шаблоны не могут начинаться с числа, и любая часть имени шаблона, разделенная на число, не может начинаться с числа.
Варианты ответа шаблона
Вариации выражаются в виде списков разметки Markdown. Вы можете добавить для каждой вариации префикс с помощью символов -, ' или +.
# Template1
- text variation 1
- text variation 2
- one
- two
# Template2
* text variation 1
* text variation 2
# Template3
+ one
+ two
Шаблон простого ответа
Шаблоны простого ответа могут содержать один или несколько вариантов текста, используемых для составления и расширения ответов. Один из доступных вариантов выбирается случайным образом библиотекой создания речи.
Вот пример такого шаблона с двумя вариантами ответа.
> Greeting template with two variations.
# GreetingPrefix
- Hi
- Hello
Шаблон условного ответа
Шаблоны условного ответа позволяют создавать содержимое на основе условия. Эти условия выражаются с помощью адаптивных выражений.
Важно!
Условные шаблоны нельзя вложить в один шаблон условного ответа. Для реализации вложенности используйте строение структурированного шаблона ответа.
Шаблон 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 и формирует результат по правилам для этого варианта. Условные выражения заключаются в скобки ${}.
Ниже показано, как указать блок переключателя 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()}
Примечание.
Как и условные шаблоны, нельзя вложить шаблоны переключения.
Структурированный шаблон ответа
Структурированный шаблон ответа позволяет определить сложную структуру с поддержкой большого набора функций из системы создания текста, таких как использование шаблонов, компоновка и подстановка, передавая задачу составления структурированного ответа объекту, вызывающему библиотеку создания текста.
Для ботов реализована встроенная поддержка следующих возможностей:
- определение действий;
- определение карточек.
Дополнительные сведения см. в статье Шаблон структурированного ответа.
Строение и расширение шаблона
Ссылки на шаблоны
Текст вариации может содержать ссылки на другой именованный шаблон, чтобы упростить построение и разрешение в сложных ответах. Ссылки на другие именованные шаблоны указываются с помощью фигурных скобок, таких как ${<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
Сущности
При использовании непосредственно в тексте однократной вариации ссылки на сущности заключаются в фигурные скобки, например так: ${entityName
}, или указываются без фигурных скобок в качестве параметра.
Сущности можно использовать в качестве параметра в следующих случаях:
- во встроенной функции;
- в условии шаблона условного ответа;
- для вызова разрешения шаблона.
Использование встроенных функций в вариациях
Встроенные функции, которые поддерживаются адаптивными выражениями, можно использовать прямо в тексте однократной вариации, чтобы дополнительно расширить возможности составления текста. Чтобы использовать выражение как встроенное, просто заключите его в скобки.
# 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.
В приведенном выше примере встроенная функция join используется для перечисления всех значений коллекции recentTasks
.
В заданных шаблонах и предварительно созданных функциях используется та же подпись вызова, имя шаблона не может совпадать с предварительно созданным именем функции.
Имя шаблона не должно соответствовать предварительно созданному имени функции. Встроенные функции имеют приоритет при разрешении конфликтов. Чтобы избежать этих проблем, добавляйте префикс 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')}
Многострочный текст в вариациях
Каждая однократная вариация может содержать многострочный текст, заключенный в тройные кавычки.
# 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)}
Импорт внешних ссылок
Шаблоны создания текста можно разделить на отдельные файлы и в любом файле указывать ссылки на другой файл. Для импорта шаблонов, определенных в другом файле, можно использовать ссылки в формате разметки Markdown.
[Link description](filePathOrUri)
Такое действие подключает все шаблоны, определенные в целевом файле. Следите за уникальностью имен шаблонов (ее можно обеспечить добавлением пространств имен с помощью # \<namespace>.\<templatename>
) во всех подключаемых файлах.
[Shared](../shared/common.lg)
Функции, внедренные с помощью Создания текста
Адаптивные выражения предоставляют возможность внедрять пользовательские наборы функций. Дополнительные сведения можно получить в статье Внедрение функций из библиотеки создания текста.
Параметры
Разработчики могут задать параметры синтаксического анализа для дальнейшего настройки способа оценки входных данных. Используйте нотацию > !#
, чтобы задать параметры средства синтаксического анализа.
Важно!
Последний параметр в файле переопределяет все предыдущие параметры в том же документе.
Параметр strict
Разработчики, которые не хотят разрешать результат null для вычисляемого результата null, могут реализовать строгий параметр. Ниже показан пример простого применения strict.
> !# @strict = true
# template
- hi
Если включен параметр strict, для значений NULL будут создаваться ошибки с понятным сообщением.
# welcome
- hi ${name}
Если имя имеет значение NULL, диагностическое сообщение будет выглядеть так: 'name' evaluated to null. [welcome] Error occurred when evaluating '- hi ${name}' (Результат вычисления выражения "name" равен значению NULL. [приветствие] Произошла ошибка при вычислении "-hi ${Name}"). Если параметр strict не задан или имеет значение false, возвращается результат в допустимом формате. Тогда указанный выше пример кода создаст текст hi null.
Параметр replaceNull
Разработчики могут создавать делегаты для замены значений NULL в вычисляемых выражениях с помощью параметра replaceNull :
> !# @replaceNull = ${path} is undefined
В приведенном выше примере входные данные NULL в переменной path
будут заменены текстом ${path} is undefined (значение пути не определено). Для следующих входных данных, где user.name
имеет значение NULL:
hi ${user.name}
будет возвращен результат hi user.name is undefined.
Параметр lineBreakStyle
Разработчики могут задать метод отрисовки разрывов строк в системе создания текста с помощью параметра lineBreakStyle. В настоящее время поддерживаются два метода:
default
— разрывы строк в многострочном тексте создают обычные разрывы строк;markdown
— разрывы строк в многострочном тексте будут автоматически преобразованы в две строки, чтобы создать новую строку.
В приведенном ниже примере показано, как задать параметр lineBreakStyle со значением markdown
.
> !# @lineBreakStyle = markdown
Параметр Namespace
Можно зарегистрировать пространство имен для шаблонов LG, которые необходимо экспортировать. Если пространство имен не указано, будет задано имя файла без расширения.
В приведенном ниже примере показано, как задать параметру пространства имен значение foo
.
> !# @Namespace = foo
Параметр Exports
Можно указать список шаблонов LG для экспорта. Экспортированные шаблоны вызываются так же, как готовые функции.
В приведенном ниже примере показано, как задать параметру экспорта значение 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 кэширует все результаты оценки, а если имя шаблона и параметры одинаковы, возвращает результат из кэша.
- Локальный кэш область используется по умолчанию. В том же слое, если предыдущий шаблон был вызван с тем же именем шаблона и теми же параметрами, кэшированный результат возвращается напрямую.
- Ни один кэш область отключает все область кэша, и каждый раз возвращает новый результат.
Примеры см. в примерах глобальных и локальных кэшей область.
> !# @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 Access .lg.
Предположим, у вас есть два файла: a.lg
и b.lg
показана ниже:
a.lg
> !# @cacheScope= global
[import](b.lg)
b.lg
> !# @cacheScope= none
# template1
- ${template2()} ${template2()}
# template2
- ${rand(1, 10000000)}
При выполнении следующего кода вы заметите, что template2
использует кэшированный результат первого вычисляемого результата из-за global
параметра кэша область в a.lg:
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!()
срабатывает и результат добавляется в кэш. template1()
Второй засоряет результат от первогоtemplate1()
. Последний вызов использует результаты, хранящиеся в кэше.
Пример область глобального кэша
Предположим, у вас есть следующие шаблоны:
# template1
- ${template2()} ${template3()}
# template2
- ${rand(1, 10)}
- abc
- hi
# template3
- ${template2()}
template2
будет оцениваться один раз, а второе выполнение template3
будет применять кэш первого.
Другой пример представлен в следующем фрагменте кода:
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
. Обратите внимание, что второй результат оценки удаляет все ранее кэшированные результаты 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)}
Дополнительные ресурсы
- Справочник по API C#
- Справочник по JavaScript API
- Чтение отладки с помощью адаптивных инструментов , чтобы узнать, как анализировать и отлаживать LG-файлы.