QuBot: Справочник


Структура проекта

Проект с чат-ботом является объектом, свойствами которого являются другие объекты. Базовыми объектами (разделами проекта) являются:

bot:          
   # общие настройки бота

slots:        
   # перечень слотов (ячейк памяти)

nlu:          
   # работа в вводом на естественном языке
   
states:       
   # описание состояний (основной раздел)
   
default:       
   # поведение input и message по умолчанию (если их нет в состоянии)
Кроме этого, возможен раздел includes со списком подключаемых файлов:
includes:
  - "about_us.yml"
  - "test_ML.yml"
Один из файлов проекта является главным. Через includes он добавляет в себя другие файлы, те, в свою очередь, могут содержать свои includes и т.д. Корневые разделы (bot, slots, states) могут повторяться в файлах, но их содержание должно быть уникальным (например, данное состояние может быть описано в разделе states только одного yml-файла).


Структура состояния

Состояния описываются в разделе states. Каждое состояние имеет уникальное имя и содержит список объектов. У каждого объекта есть уникальное свойство (text, slots, ...), которое определят его тип. Часть объектов визуальные (text, button, image), другая часть - логические. Объекты одного и того же типа могут встречаться в списке несколько раз.

Списки визуальных объектов состояния могут быть разбиты на блоки. Начало следующего блока помечается объектом block. Каждый блок является отдельным сообщением. В web-chat это сообщение рисуется на подложке заданного (и при желании изменяемого) цвета. В месенджерах блоки могут оказаться разбитыми на отдельные сообщения.

В состояниях может не быть визуальных объектов. Такие состояния называются логическими. В них выполняются некоторые действия (action), устанавливаться слоты (slots) и т.п. В конце логического состояния ставится оператор перехода (goto) в новое состояние (визуальное или логическое).

Полный перечень объектов, которые могут встретиться в состоянии:

STATE:
  - block:   # начало новой плашки-сообщения
  - text:    # текст, возможно на нескольких языках
  - image:   # картинка
  - map:     # карта
  - random:  # случайный выбор контента
  - again:   # повторный запуск контента
  
  - run:     # запуск контента другого состояния и возврат обратно
  - state:   # состояние перехода по умолчанию (если нет в button, input, message)
  - goto:    # переход в другое состояние без возврата
  - time:    # время жизни состояния, после которого автоматически переходим на state
  
  - slots:   # изменение значений слотов
  - action:  # выполнение встроенных действий (операции со списками и т.п.)
  - if:      # условие
  - while:   # цикл
  
  - buttons: # раздел кнопок (не обязателен)
  - input:   # раздел ввода текста (должен быть один)
  - message: # раздел получения сообщения (должен быть один)
  
  - button:  # кнопка (может быть также в состоянии, вызываемом по run)
  - row:     # строка из кнопок (аналогично)
  
  - intent:  # обработка NLU-намерений последнего ввода INPUT_VALUE
  - extract: # извлечения слотов из последнего ввода INPUT_VALUE
  - value:   # анализ последнего INPUT_VALUE
  
  - show:    # показать список визуальных объектов (используется при обмене сообщениями)
  - print:   # вывести отладочный текст в окно debug


Визуальные объекты состояния

text - добавляет текст в сообщение. В web-chat этот текст окружается тегами абзаца <p> ... </p>. Если текст многострочный (внутри есть \n), то символы конца строк в web-chat заменяются на обрыв строки <br>.
Значение свойства text - это строка (единичная или многострочная):

STATE:
  - text: "Это текст в одну строчку"
  - text: |
      Это текст в несколько строк
      Так, это вторая строка
Можно также в text передавать объект с перечнем языков, значение каждого из которых это - однострочный или многострочный текст:
STATE:
  - text: 
      ru: "Мы писали, мы писали. Наши пальчики устали."
      en: |
        We wrote, we wrote... 
        Our fingers are tired.
Такой же формат имеют свойства других объектов, если их значением является текст (button, caption, и т.д.).

В месенджерах (например telegram) объект text отправляется отдельным сообщением (нарисованным на фоне своей подложки). Если состояние имеет визуальные объекты, то для месенджеров один из них обязательно должен быть текстом или картинкой. Если состояние имеет кнопки, то перед ним обязательно должен идти хотя бы один text или image (для месенджеров).

В строке текста могут помещаться значения слотов (перед их именем ставится знак доллара) и фигурные скобки {...}, содержащие выражение, которое необходимо вычислить (это выражение на Python). В результирующей строке произойдёт замена слотов на их значения и будут проведены соответствующие вычисления внутри {...}:

STATE:
  - text: "Отлично $NAME. Вы купили {$ITEM_NUM1+$ITEM_NUM2} товаров."
  - text: "Компания $INFO.COMAPNY благодарит Вас!"
К категориальным слотам можно в тексте обращаться через точку (выше второй текст). Если в разделе slots есть:
slots:
    INFO:
        type:   categorical
        value:  COMPANY
        values:
            COMPANY:
                ru: "Абсолютист"    
                en: "Absolutist"
            DESCR: "..."
Тогда вместо $INFO.COMAPNY будет подставлено название компании в текущем языке.

У объекта text может быть свойство p: false. Оно означает, что в web-chat текст тегами абзаца не нужно. Ещё одно свойство pre: true окружает текст тегами <pre> ... </pre> - моношириннный шрифт с сохранением всех пробелов.


image - выводимая в сообщении картинка. Она может содержать необязательное свойство caption. Это подпись под картинкой, которая "прижимается" к ней.

STATE:
  - image:   "im/squirrel.jpg"
    caption: "Это белочка"
Путь к картинке указывается относительно корневой директории, где находится главный yml-файл проекта.


map - вывод карты google. Ссылка соответствует полю src= в ссылке, которая генериться в www.google.com/maps. Для её получения, нажимаем на кнопку с полосочками в левом верхнем углу google map и выбираем "Ссылка/код", а там закладку "Встраивание карт".

STATE:
   - map: "https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!...."

random - выбрать случайный объект из списка. Ниже будет случайно выбран один из двух текстов:

STATE:
  - random:
    - text: "Я Вас не понял"
    - text: "Не понятно... Попробуйте сформулировать по другому."

Если случайно нужно выбрать не один объект, а группу, то используется блок actions:

STATE:
  - random:
    - text: "Я Вас не понял"
    - actions: 
        - text: "Не понятно... Попробуйте сформулировать по другому."
        - image: im/image.png


again - выбор и выполнение списка объектов, в зависимости от номера повтора вызова этого блока. Для его использования, необходимо создать слот типа int с нулевым начальным значением (это будет так, если value не указать). Ниже такой слот имеет имя SLOT_WAS_ARE_YOU_BOT. При заходе в again, стоящий в нём слот (без знака доллара!) увеличивается на единицу, а затем выполняется соответствующий его значению раздел (приведенные ниже числа) из ключа cases. Эти числа не обязательно идут подряд и в них могут быть пропуски:

STATE:
  - again: SLOT_WAS_ARE_YOU_BOT
    cases:
        1:  
          - text: "Да, я искусственный разум, созданный компанией QuData."
        3:  
          - text: "Да, да, это я."      
        more:  
          - text: "Да, кожаный мешок, набитый костями. Я не человек."

Если значение слота больше любого из чисел в списке, то выполняется болок more. В примере выше, при первом заходе будет выведен текст "Да, я искусственный разум...", при втором заходе ничего не будет выведено, при третьем - текст "Да, да, это я." Все последующие заходы будут порождать последний текст. В списке каждого блока могут быть любые объекты.

В again можно также передавать значение (доллар) слота (again: $SLOT), если в строковом слоте SLOT хранится имя слота, использующегося как счётчик.

В разделе more можно вызвать random, чтобы разнообразить контент при "переполнении" счётчика.


video - выводимое в сообщении видео.


audio - - выводимое в сообщении аудио.


Событийные объекты состояния

buttons - перечисляет список кнопок button (они будут идти в столбик) или строчек row, содержащих список кнопок button (они будут идти в строчку):

STATE:
  - text: "Нажми на кнопку"
  - buttons:
      - button: "Кнопка 1"
      - row:
          - button: "Кнопка 2.1"
          - button: "Кнопка 2.2"
      - button: "Кнопка 3"          
Для корректной работы месенджера раздел buttons должен быть последним визуальным объектом состояния и перед ним должен быть хотя бы один text или image.

В списке раздела buttons (и в row), кроме row и button, могут быть объекты if, while, action, run. Если результатом их работы будет объект button, он добавится в соответствующем месте (в строчке или колонке). Это позволяет создавать меню кнопок, зависящее от, например, текущего значения слотов. Других визуальных элементов if, while, action, run в разделе buttons порождать не должны:

STATE:
    - text: "Текст"
    - buttons:
        - button: "Кнопка 1"
        - if: $AMOUNT > 3
          then:
            - button: "Кнопка 2"
            
        - run: RUN_SHOW_BUTTONS_BACK # в этом состоянии есть button, row
        
Объект buttons не обязателен и служит для повышения структуризации. Кнопки button и строчки кнопок row можно перечислять непосредственно в состоянии.


button - одна кнопка. Кроме заголовка (возможно на разных языках) могут также находится следующие объекты, которые активируются при нажатии кнопку:

      - button: "Текст"                    # надпись на кнопке      
        answer: "Более полный текст"       # если нужно вывести "ответ", отличный от button
        slots:  { ITEM: $VAL1, ANOUNT: 5}  # установка слотов, при нажатии
        state:  STATE_NAME                 # состояние в которое переходим при нажатии
        run:    RUN_SOME_STATE             # сформировать контент перед переходом
        actions: []                        # список любых объектов (см. ниже)
Если при нажатии кнопки необходимо вызвать несколько объектов в контролируемом порядке, необходимо поставить блок actions и далее привести список этих объектов
      - button: "Текст"                    # надпись на кнопке      
        actions:                           # действия, выполняемые при на нажатии перед переходом
          - text:                          # визуальные элементы добавятся перед новым состоянием
          - image:
          #...
          
          - action: ...
          - if:     ...
          - run:    ...
          - slots:  ...          
          #...
Фактически в разделе actions могут быть все объекты, допустимые в состоянии.

Если под button есть state, то переход по нажатию на кнопку произойдёт в это состояние. Иначе будет выбрано состояние по умолчанию, указанное в state в корне данного состояния. Если state нет ни в кнопке, но в корне состояния, то будет повторно показано текущее состояние.

Если в кнопке (под actions) есть визуальные элементы ( text, image,...), они будут выведены в начале следующего состояния.

В кнопке может быть свойство url: "http://google.com". Если оно есть, при нажатии кнопки произойдёт переход по ссылке (в другом окне браузера).

По умолчанию текст на кнопке центрируется. Это поведение можно изменить свойством text_align: left (или right). Надпись на кнопке в этом случае будет прижата влево или вправо. Второе свойство text_margin: 10 определяет отступ в пикселях от левого или правого края кнопки соответственно. Эти свойства сработают только в web-чате.


input - строка ввода. В настоящее время она одна и её положение в списке объектов состояния роли не играет. Может содержать свойства, срабатывающие при вводе текста пользователем:

STATE:
  - input:
     - state: NEW_STATE                # куда перейдём при нажатии ввода
     - slots: { NAME: $INPUT_VALUE }   # какие слоты нужно изменить      
     - action: ...
     - if:     ...
     - run:    ...
     - slots:  ...
INPUT_VALUE - это встроенный строковый слот (его объявлять не нужно), содержащий введенный текст без пробелов в начале и конце. Доллар перед именем слота INPUT_VALUE означает взятие его значения (строку ввода).

Можно анализировать значение ввода в разделе value и выполнять те или иные действия:

STATE:
  - input:               
      - value:
            "1": # введен текст 1
               - slots:  {TEST_PYTHON: $TEST_PYTHON+1000  }
               - state: NEXT
            "2": # введен текст 2
               - slots: { WRONG: 1 }
               - state: GO
      - state: NEXT                    # переход по умолчанию, если нет в value
Возможны также разделы intents и extract (см. документ Естественный язык).

Если каждое действия данного типа в разделе input присутствует в единственном экземпляре и их порядок не важен, то input может быть объектом (аналогично button):

STATE:
  - input:
        extract: [ EMAIL ]
        value: ...
        state: NEW_STATE                # куда перейдём при нажатии ввода
        slots: { NAME: $INPUT_VALUE }   # какие слоты нужно изменить        
        run:    ...     
        actions: ...              
Однако лучше использовать "списочный синтаксис". В частности action в объектной форрме использовать нельзя (только под блоком actions).

Если в input и в корне состояния нет state, то будет повторно вызвано текущее состояние.


message - раздел активируется, если придёт сообщение от другого бота или от этого же бота, но от другого пользователя. Аналогично input может содержать список любых объектов, допустимых в состоянии. Если в нём и в корне состояния нет state, то будет повторно вызвано текущее состояние.


Управление сообщениями

Визуальные и событийные объекты состояния по умолчанию формируют одно сообщение. В web-chat оно рисуется на подложке заданного цвета (по умолчнию или из раздела bot), кроме кнопок buttons, которые идут ниже. В месенджерах такое сообщение, возможно будет разбито на несколько (будет несколько подложек).

В состоянии может быть несколько сообщений. Начало нового сообщения определяется объектом block:

STATE:
  - text:   "Будет на первой подложке"   
  - block: 
  - text:   "Будет на второй подложке"   
Свойства объекта block позволяют управлять цветом подложки, временем задержки вывода этого сообщения, эффектом, сопровождающим его появление:
STATE:
  - block: 
        background: "#09f"     # RGB - цвет подложки
        delay:      500        # пауза 500 ms
        effect:     TYPING     # перед появлением иммитация набора

Желательно раздел buttons (или список button, row) ставить последним визуальным компонентом в последнем блоке (сообщении). Для web-chat это не критично, но для работы бота в месенджерах важно придерживаться этого правила.

Объект block может стоять перед самым первым визуальным элементом для определения свойств первого сообщения. Например, в нём можно изменить цвет первой подложки и удалить предыдущее сообщение:
STATE:
  - block: 
        background: "#ааа"     # RGB - цвет подложки
        clear: 1               # удалить предыдущее сообщение 

По умолчанию кнопки предыдущего сообщения удаляются, а после него имитируется ответ пользователя в виде строки, содержащей текст на кнопке или ввод в поле редактирования. При помощи clear из раздела block можно удалять любое число предыдущих сообщений (все визуальные элементы):

clear:   1      # удалить предыдущее сообщение 
clear:  10      # удалить 10 предыдущих сообщений
clear:  -1      # удалить все предыдущие сообщения
clear:   0      # удалить себя, после перехода из состояния
Следует помнить, что в месенджере сообщение может быть разбито на несколько (в отличии от web-chat), поэтому свойство clear необходимо использовать с пониманием, что такое сообщение в месенджере.


Переходы между состояниями

goto - мгновенный переход на новое состояние. Игнорируются все остальные объекты ниже, поэтому обычно стоит последним в списке объектов состояния или под if. Всегда используется в стартовом состоянии для указания первого запускаемого состояния:

START_STATE:
  - slots: { LANGUAGE: ru }
  - goto:  GREET_STATE
Может также использоваться для переходов между логическими состояниями.

В качестве значения goto выступает имя состояния или имя слота строкового типа (с префиксом $). Это позволяет сохранять в слотах имена состояний:
slots:
    SAVE_STATE:
        type: str
states:
    ...
    STATE1:
      - slots { SAVE_STATE: STATE1}    # запомнили состояние (как строку STATE1)
    ...
    STATE2:
      ...
      - goto: $SAVE_STATE              # перейдём в STATE1, полуив значение ($) слота
Обратим внимание на знак $, который даёт значение слота SAVE_STATE. Если его не будет (goto: SAVE_STATE), то произойдёт попытка перехода в состояние с именем SAVE_STATE (которого скорее всего нет). Естественно, слотов со значениями запомненных состояний может быть любое количество и они могут использоваться как в goto, так и в state или run.

Переход goto не сбрасывает визуальные элементы состояния (стоящие выше него) и они выводятся в чат.


state - состояние для перехода при возникновении события (нажата кнопка, произведен ввод в строке редактирования). В списке объектов состояния state означает переход по умолчанию (значение state, если его не было в событийном объекте):

STATE:
  - text: "Привет. Как дела?"

  - button: "😆 Хорошо"      
    state:  SCR_OK                     # сюда попадут по нажатию этой кнопки
    
  - button: "😑 Так себе"
  - button: "😰 Ужасно"
      
  - state: SCR_WHAT_A_PITY             # сюда попадут по кнопкам "Так себе" и "Ужасно"
Объект state в списке объектов должен быть один (используется только последний). Выше при нажатии на "Так себе" и "Ужасно" произойдёт переход в состояние SCR_WHAT_A_PITY.


run - аналогично state или goto содержит имя состояния или строковый слот, хранящий это имя (со знаком $). При встречи этого объекта, происходит временное покидание текущего состояния. Выполнятся все действия в новом состоянии и происходит возврат обратно в ту точку откуда был вызван run. Вызываемое состояние может также формировать визуальные элементы, которые добавятся к элементам состояния откуда был вызван run.


Логические объекты состояния


slots - установка значения слотов:

STATE:
  - slots:
      SLOT3: 3.141592
  - slots: { SLOT1: "Привет", SLOT2: $SLOT3}
Выше, вторая запись является сокращением для:
STATE:
  - slots:     
        SLOT1: "Привет"
        SLOT2: $SLOT3

Напомним, что если значением слота является другой слот, то перед его именем необходимо поставить символ доллара, иначе он будет интерпретироваться как обычная строка, содержащая имя слота. В слотах можно использовать вычисляемые выражения:

STATE:
  - slots: 
        SLOT1: $NAME         # должны совпадать типы слотов SLOT1 и NAME
        SLOT2: $COUNT + 1    # запишется результат вычисления 
В последнем случае типы слотов SLOT2 и COUNT должны быть числовыми (int, float). Если COUNT имеет тип float, а SLOT2 тип int, после сложения, произойдёт округление. Фигурные скобки {$COUNT + 1} (как внутри текста) при задании значения слотов ставить не нужно.

Раздел slots может присутствовать в событийных объектах (button, input, message). Тогда он выполняется только при срабатывании этого объекта.


if - объект условия. Содержит строку с логическим выражением и раздел then, выполняемый, если выражение истинно и раздел else, если выражение ложно (один из этих разделов может отсутствовать).

В логическом выражении могут быть числа, слоты (начиняющиеся с $) и строки. Строки должны браться в одинарные кавычки 'Маша', '✅' и т.д.

Равенство двух величин это ==. Для сравнения чисел можно использовать >, <, ==, >=, <=, !=. Возможны логические связки and, or, not и скобки. Для чисел - арифметические выражения. Если переменная (слот) не определена у неё значение None. Вот несколько примеров:

if: ($NAME == 'Оля' or $NAME == 'Маша') and $AGE > 18
if: $X + $Y > $Z
if: $NAME == None

Полный пример раздела if:

STATE:
  - if: $AMOUNT > 5
    then:
      - slots: {}          # установить слоты
      - state: STATE1      # задать состояние перехода по умолчанию
      - text:  "AAA"       # вывести текст (всегда на первом уровне списка состояния)
      - buttons:           # если другого buttons в состоянии нет (и на первом уровне)
      - button:            # если if внутри buttons или row
    else:
      - goto: STATE2       # мгновенный переход  
Фигурные скобки: {$AMOUNT > 5} (как внутри текста) в if ставить не нужно.

Следующим образом можно проверить длину строки и добавить в сообщение текст:

  - if: len($NAME) > 3 and $AGE < 16
    then:
      - text: "Ты так молод $NAME!"


while - похож на if, но повторяет then пока условие истинно, но не более 1000 раз.

      - slots: {COUNTER: 0}
      - while: $COUNTER < 10               # повторяем then, пока выполняется условие
        then:
          - text: "$COUNTER, "
            p: false
          - slots: { COUNTER: $COUNTER+1}  # увеличиваем счётчик повторов
В теле цикла (под then) что-то должно изменяться (обычно в разделе slots), чтобы изменялось логическое условие в while.


action - встроенное или пользовательское действие, написанное на Python. Оно может содержать различные аргументы и возвращать различные значения:

STATE:
  - action: ACTION_LIST_EMPTY        # имя действия, проверяющего длину списка 
    value:  ORDER                    # аргумент действия (что проверяем)
    result:                          # возможные результаты работы
        true:  [ state: THANK_YOU ]  
        false: [ state: GET_EMAIL ]  
Некоторые действия не возвращают значения, а просто что-то делают (добавляют элемент в список и т.п.) Более подробно встроенные действия описаны в Справочник - Действия.


time - время жизни сообщения. После его истечения (если не было событий от button, input или message) происходит переход в следующее состояние (state). Полезно, например, при проведении тестирования клиента, когда на каждый вопрос отведено определенное время:

JOB_TEST_ML1:
  - text: "[1/4] Переобучение модели может возникать, когда:"
  
  - buttons:
      - button: "Модель очень хорошая"
      - button: "В модели слишком много параметров"
        slots:  { TEST_ML: $TEST_ML+1000 }
      - button: "Модель очень долго учится"
      
  - time:  60000                          # на ответ отведена минута
  - state: JOB_TEST_ML2                   # не нажмёт на кнопку, идём дальше

При помощи time и clear следующим образом можно реализовать таймер, выводящий на протяжении одной минуты в тексте сообщения секунды (перезаписывая предыдущий текст):

TIMER_STATE:
  - if: $COUNTER > 60
    then:
      - goto: PHONE_EXPLOSION_STATE        # закончить работу таймера.

  - block:         
        clear: 0                           # удаляем себя после time
        
  - text:  "Прошло $COUNTER секунд."       # визуальный контент сообщения
  - slots: { COUNTER: $COUNTER+1 }         # увеличиваем счётчик
  
  - time:  1000                            # живём 1000 ms
Естественно, где-то выше должно быть задано начальное значение слота {COUNTER: 0}. Так как state в состоянии не указано, через каждую секунду будет произведен повторный показ этого состояния, пока не сработает if и в нём goto.


intents: - обработка в произвольном месте последнего намерения человека (Работа с естественным языком):

#...
    RUN_CHITCHAT:                                # ответы на болтовню
    
      - intents:
            I_ARE_YOU_BOT:
              - text: "Да, я искусственный разум, созданный компанией QuData."
            I_WHAT_IS_YOUR_NAME:
              - text: "С утра меня звали Анна. Но для Вас - просто Нюшенька."

print: "строка" выводит на страницу в разделе Info строку. Можно использовать для отладочных целей.


Предопределённые состояния

Существуют три предопределённых состояния. Первое START_STATE описывает разработчик бота. Это состояние всегда должно быть в проекте. Оно запускается первым, делает необходимые настройки (например установку языка) и по goto переходит на первый экран.

Ещё два состояния PREV_STATE и PREV_STATE_2 могут использоваться в state и goto для перехода на одно или два состояния назад. Впрочем, для этих целей можно использовать и сохранённые в слотах имена состояний.


Слоты

Все данные хранятся в слотах, которые являются парами ключ-значение. Ключ - это имя слота. Его значение может иметь различные типы:

Слоты объявляются в разделе slots (он находится на корневом уровне файла проекта, там же, где и раздел states). У каждого слота обязательно надо указывать его тип (type) и можно, при необходимости, начальное значение (value):

slots:
    NAME: 
        type:  str                # тип слота строка
        
    COUNT:
        type:  int                # тип - целое число
        value: 5                  # начальное значение
Если value не указан, то для str это будет пустая строка "", для int, float - 0, в для list пустой список [].

В результате работы (например, при попытке вытащить из строки ввода информацию), значение слота может оказаться равным None (не определено). Это можно использовать в условных операторах (if: $NAME == None).

Значением категориального слота (categorical) является один из определённых в разделе values ключей:

slots:
    ITEM: 
        type:  categorical
        value: Milk               # начальное значение
        values:                   # возможнные значения:
            Milk: Молоко
            Wine:
                ru: Вино
                en: Wine
Такой слот внутри состояния задаётся обычным образом: slots: { ITEM: Milk }. Для получения значения в текстах можно использовать знак доллара: "Это $ITEM", где на место $ITEM будет подставлено текущее значение value. Можно также обратиться к конкретному значению (не зависимо от текущего value), используя точку между именем слота и именем его возможного значения: "Это $ITEM.Milk". Таким образом можно создавать строковые ресурсы для мультиязычных интерфейсов.

В слотах строкового типа также можно использовать несколько языков.

Предопределённые слоты:


Вычисления

Математические функции


Округление


Дата и время

В последних двух функциях можно передавать форматирование времени или даты, а также сдвиг от текщего дня:
      - text: "{time()}"                   # 09:02:12
      - text: "{time('%H:%M')}"            # 09:02
      - text: "{date()}"                   # 2021-09-23
      - text: "{date('%m/%d', days=5)}"    # 09/28
      - text: "{date('%b, %d')}"           # Sep, 23
      - text: "{date('%b, %d', weeks=1)}"  # Sep, 30
Список кракозябр для форматирования времени и даты можно найти здесь.

Случайные числа


Разное


Логические выражения

Значение ключа if - это строка, содержащая логическое выражение. Логическое выражение принимает два значения True и False. В выражении могут быть числа, переменные (имена слотов с $) и строки. Строки должны браться в одинарные кавычки 'Маша', '✅' и т.д.

Равенство двух величин это ==. Для сравнения чисел можно использовать >, <, ==, >=, <=, !=. Возможны логические связки and, or, not и скобки. Для чисел - арифметические выражения. Если переменная (слот) не определена у неё значение None. Вот несколько примеров:

if: ($NAME == 'Оля' or $NAME == 'Маша') and $AGE > 18
if: $X + $Y > $Z
if: $NAME == None
if: len($NAME) > 0
Если выражение не верное (не является логическим), слева появится ошибка.