Формат файлов .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)}

Дополнительные ресурсы