Botframework-solutions: [TypeScript] Класс SkillMiddleware должен принимать три параметра вместо двух.

Созданный на 17 окт. 2019  ·  13Комментарии  ·  Источник: microsoft/botframework-solutions

Какой проект затронут?

Microsoft botframework V4, Custom Skill.

На каком это языке?

Машинопись

Что происходит?

Навык не может получить информацию, переданную от виртуального помощника через SkillContext.

Что нужно сделать, чтобы воспроизвести эту проблему?

Шаг 1. Создайте виртуальное устройство с помощью https://botbuilder.myget.org/feed/aitemplates/package/npm/botbuilder-solutions.
Шаг 2. Создайте навык с помощью команды генератора навыков.
" https://botbuilder.myget.org/feed/aitemplates/package/npm/botbuilder-skills "
Шаг 3. Добавлен файл манифеста навыка с параметром слота.
Шаг 4: Установите SkillContext со значением параметра слота.
Шаг 5: попробуйте получить доступ к значению SkillContext в Skill.

Чего вы ожидали?

Объект, установленный в SkillContext, должен быть доступен для навыка, если совпал атрибут «слот».
Но навык не может получить SkillContext.
"SkillMiddleware" должен поддерживать skillContextAccessor и заполнять SkillContext параметрами слота.

Можете ли вы поделиться журналами, выводом ошибок и т. Д.?

После некоторой работы выяснилось, что CustomSkillAdapter заполняется значением «skillContextAccessor».

Текущий код:
класс экспорта CustomSkillAdapter расширяет SkillHttpBotAdapter {
конструктор(
telemetryClient: TelemetryClient,
talkState: ConversationState,
skillContextAccessor: StatePropertyAccessor,
dialogStateAccessor: StatePropertyAccessor,
...
) {
супер (телеметрияКлиент);
[...]
this.use (новый SkillMiddleware (talkState, dialogStateAccessor));
[...]
}
}

Ожидаемый код в соответствии с этим " https://microsoft.github.io/botframework-solutions/howto/skills/skillenablesav4bot/ "

класс экспорта CustomSkillAdapter расширяет SkillHttpBotAdapter {
конструктор(
telemetryClient: TelemetryClient,
talkState: ConversationState,
skillContextAccessor: StatePropertyAccessor,
dialogStateAccessor: StatePropertyAccessor,
...
) {
супер (телеметрияКлиент);
[...]
this.use (новый SkillMiddleware (talkState, skillContextAccessor, dialogStateAccessor));
[...]
}
}

Спасибо,
Эдвард

Самый полезный комментарий

Приятно это слышать! Рад, что смог помочь тебе с этим 😊

Все 13 Комментарий

Привет @ Edwardfelix08 , извиняюсь за задержку с ответом.
Мы рассмотрели документацию по включению бота V4 в качестве навыка (структура документа изменилась, предыдущая ссылка вернула 404) и поняли, что она не обновлялась правильно после некоторых изменений в коде, поэтому мы обновим эту документацию.

Следуя инструкциям по воспроизведению, мы понимаем, что у вас есть некоторая информация о вашем виртуальном помощнике, и вы сохраняете эту информацию в SkillContext виртуального помощника, и когда навык получит сообщение, вы хотите получить эту информацию из SkillContext . Это верно?

Привет @dfavretto.
Да, это правильно.

Привет, @ Edwardfelix08 , мы тестировали этот сценарий и создали руководство о том, как заставить его работать. Примите во внимание , что образец-помощник не готов вне коробки для использования в этом сценарии, поэтому мы даем три шага в некоторых незначительных изменений , необходимых для достижения этой цели :

  1. [Виртуальный помощник] Сохранение информации в SkillContext
  2. [botbuilder-skills] Информация SkillContext фильтруется и сохраняется в SemanticAction действия.
  3. [Skill] Заполнение SkillState информацией о SemanticAction действия

[Виртуальный помощник] Сохранение информации в SkillContext

Прежде всего, вы должны сохранить желаемую информацию в контексте навыков , чтобы получить ее позже. Это необходимо сделать до того,

  1. Внутри mainDialog вы должны использовать skillContextAccessor для получения SkillContext, соответствующего вашему контексту. Это можно сделать с помощью следующих строк:

    const sc: SkillContext = await this.skillContextAccessor.get(dc.context, new SkillContext());
    const skillContext: SkillContext = Object.assign(new SkillContext(), sc);
    
  2. Теперь, когда ваш SkillContext сохранен в переменной, вы можете получить или установить любое значение. Не забывайте, что значения внутри SkillContext представляют собой пару «ключ-значение», поэтому убедитесь, что ваши ключи уникальны, если вы не хотите перезаписывать свои значения. Теперь вы можете сохранить что угодно, например значение местоположения:

    skillContext.setObj('location', locationObj);
    
  3. Наконец, установите свой SkillContext с помощью skillContextAccessor, чтобы эта информация сохранялась в вашем userState :

    await this.skillContextAccessor.set(dc.context, skillContext);
    

[botbuilder-skills] Информация SkillContext фильтруется и сохраняется в SemanticAction действия.

После сохранения информации в SkillContext можно перенаправить сообщение в Skill, но до того, как сообщение достигнет Skill, SkillDialog внутри botbuilder-skills обработает SkillContext во время метода onBeginDialog , который выполняется только один раз, когда Навык вызывается впервые.

Этот метод автоматически выполнит следующие шаги:

  1. Получает SkillContext так же, как мы это делали на первом шаге.
  2. SkillManifest используется для получения слотов , а затем эта информация отправляется методу matchSkillContextToSlots .
  3. Внутри метода matchSkillContextToSlots, то SkillContext оценивается , чтобы найти какой - либо ключ , соответствующий ключ шлицев. Каждый сопоставленный ключ используется для сохранения этой пары ключ-значение SemanticAction .
  4. Деятельность с SemanticAction (информация извлекается из SkillContext , который соответствует шлицы) направляется в соответствующий навык.

[Skill] Заполнение SkillState информацией о SemanticAction действия

Третий и последний шаг - заполнить SkillState информацией, отправленной из виртуального помощника, с помощью следующих шагов:

  1. В Skill, внутри mainDialog , есть метод , называемый populateStateFromSemanticAction . Этот метод прокомментирован и немного устарел. Мы создали [PR # 2669] (уже объединены), чтобы обновить этот метод.
  2. Обязательно обновите свой SkillState , добавив необходимые свойства.
  3. Изменение populateStateFromSemanticAction по мере необходимости принять все свойства из SemanticAction и сохранить их в SkillState. Прямо сейчас метод ищет в качестве примера свойство «Местоположение», его можно изменить на любое свойство, к которому вы хотите получить доступ:
    typescript if (semanticAction !== undefined && Object.keys(semanticAction.entities) .find((key: string) => key === "location"))
  4. Теперь вы можете получить доступ к своему SkillState внутри своего навыка из любого места.

Надеюсь, эти шаги будут полезны 😊

Привет, @ lauren-mills, не могли бы вы проверить, верен ли этот подход? 😁

Спасибо, @dfavretto попробует посмотреть, работает ли это.

Привет @dfavretto. Я пробовал вышеуказанное решение, но оно не сработало. Я все еще вижу, что в классе CustomSkillAdapter нет обновлений или изменений кода.

@ Edwardfelix08 Не могли бы вы рассказать нам , в чем

  1. Удалось ли вам сохранить информацию в SkillContext вашего виртуального помощника ?
  2. Обновлен ли ваш SkillManifest необходимыми слотами ?
  3. Соответствует ли ключ слота ключу, используемому для сохранения информации в SkillContext ?
  4. Является ли метод populateStateFromSemanticAction в вашей Skill раскомментирована?

Кроме того, что касается CustomSkillAdapter , не было необходимости изменять этот класс для этого сценария.

Привет @dfavretto!
Ниже приведен используемый код

  1. Удалось ли вам сохранить информацию в SkillContext в вашем виртуальном помощнике?

    В.А. MainDialog.
    const sk: SkillContext = await this.skillContextAccessor.get (dc.context, new SkillContext ());
    const skillContext: SkillContext = Object.assign (новый SkillContext (), sk);
    skillContext.setObj ('userState', userProfile);
    ждать this.skillContextAccessor.set (dc.context, skillContext);

  2. Обновлен ли ваш SkillManifest необходимыми слотами?
    skill.json в VA
    "слоты": [{
    "name": "userState",
    "тип": ["IUserState"]
    }],

    SkillManifest
    "слоты": [{
    "name": "userState",
    "тип": ["IUserState"]
    }],

  3. Соответствует ли ключ слота ключу, используемому для сохранения информации в SkillContext?
    код внутри populateStateFromSemanticAction
    if (skillContext.ContainsKey ('userState')) {
    ......
    ......
    }

  4. Раскомментирован ли метод populateStateFromSemanticAction в вашем навыке?
    да, я раскомментировал код метода populateStateFromSemanticAction внутри botSkill.

Какую версию фрейма бота мы должны использовать?
Мы используем следующие пакеты.

    "botbuilder": "^4.5.3",
    "botbuilder-ai": "^4.5.3",
    "botbuilder-applicationinsights": "^4.5.3",
    "botbuilder-azure": "^4.5.3",
    "botbuilder-core": "^4.5.3",
    "botbuilder-dialogs": "^4.5.3",
    "botbuilder-skills": "^4.4.6",
    "botbuilder-solutions": "^4.4.6",
    "botframework-config": "^4.5.3",
    "botframework-connector": "^4.5.3",
    "botframework-schema": "^4.5.3",

@ Edwardfelix08 , я вижу, вы пытаетесь получить значение userState из skillContext в методе populateStateFromSemanticAction . Я хотел бы отметить, что skillContext вы заполнили в виртуальном помощнике , больше не те, что у вас есть в вашем навыке .

Для использования этой ситуации данные из skillContext виртуального помощника копируются в semanticAction . Действие - единственный элемент, отправленный виртуальным помощником навыку , и затем его можно оценить для получения этой информации.

Вот пример populateStateFromSemanticAction , который получит ваше значение userState из semanticAction действия Activity:

protected async populateStateFromSemanticAction(context: TurnContext): Promise<void> {
        // Example of populating local state with data passed through semanticAction out of Activity
        const activity: Activity = context.activity;
        const semanticAction: SemanticAction | undefined = activity.semanticAction;
        if (semanticAction !== undefined && Object.keys(semanticAction.entities).find((key: string) => key === "userState")) {

            const userState: any = semanticAction.entities["userState"];
            const userStateObj = userState.properties["userState"];
            const state: SkillState = await this.stateAccessor.get(context, new SkillState());
            state.userState = userStateObj !== undefined ? userStateObj : userState;
            await this.stateAccessor.set(context, state);
        }
    }

@dfavretto извините за поздний ответ.
Я пробовал то же самое, но до сих пор не могу понять значение.
Значение для activity.semanticAction не определено.

Привет, @ Edwardfelix08 , мы провели несколько SemanticAction всегда имеет какое-то значение по умолчанию, поэтому оно не должно быть неопределенным.

image

Просто чтобы подтвердить, в вашем виртуальном помощнике вы вызываете свой навык следующим образом?

image

@darrenj - стоит ли добавить команду поддержки, чтобы они могли подойти к этой проблеме с другой точки зрения? Поскольку похоже, что это не имеет ничего общего с самой реализацией TypeScript, а с конкретным сценарием, который здесь реализуется.

Привет @dfavretto!
Извините за поздний ответ. Нам удалось заставить это работать, благодаря вам. Мы имели в виду старую версию фреймворка после обновления и перекрестной проверки с вашим кодом, и было различие в "populateStateFromSemanticAction", обновили код до предложенного, и он начал работать как шарм.

Спасибо, что помогли нам в этом.

Приятно это слышать! Рад, что смог помочь тебе с этим 😊

Была ли эта страница полезной?
0 / 5 - 0 рейтинги