По какой-то причине BotFramework плохо работает с обратными вызовами, поэтому вы получаете сообщение об ошибке «Невозможно выполнить get для прокси-сервера, который был отозван». Решение, хотя и сложное, состоит в том, чтобы создать упреждающую конечную точку API сообщения, вызвать к ней запрос из обратного вызова тайм-аута, а затем выполнить остальные вызовы бота из упреждающего сообщения. Я бы рекомендовал взглянуть на образец Proactive Messaging , прежде чем приступить к работе с кодом ниже.
index.js file
Мы собираемся добавить конечную точку / api / notify на наш сервер обновлений, которая будет задействована по истечении времени ожидания. Я бы порекомендовал добавить к вашему боту метод для обработки проактивных сообщений, чтобы вы могли сохранить все элементы состояния и диалога, содержащиеся в вашем боте, вместо того, чтобы поднимать их в индексный файл. Обратите внимание, вы должны будете передать адаптер в качестве параметра для вашего бота.
let bot = new Bot(adapter, conversationState, userState);
...
server.get('/api/notify/:conversationId', (req, res) => {
bot.sendProactiveMessages(req.params.conversationId);
res.send(204);
});
Диалог
На этом шаге диалога мы добавляем ответный атрибут в профиль пользователя - вы также можете добавить его в состояние разговора - и устанавливаете для значения по умолчанию значение false. Затем вместо настройки обратного вызова для доступа к состоянию и сообщения пользователю, просто используйте HTTP-клиент, такой как Axios или Request, чтобы сделать запрос get с идентификатором диалога в качестве параметра URL для конечной точки, которую мы только что создали на шаге выше.
Когда пользователь отвечает на следующее приглашение, измените ответное значение на true, чтобы мы могли определить, ответил ли пользователь на проактивное сообщение.
async captureName(step) {
const profile = await this.profileAccessor.get(step.context);
profile.name = step.result;
profile.responded = false;
this.profileAccessor.set(step.context, profile);
const { conversation: { id }} = TurnContext.getConversationReference(step.context.activity);
setTimeout(() => {
axios.get(`http://localhost:3978/api/notify/${id}`)
.then(() => {})
.catch(error => console.log(error));
}, 60000);
return await step.next();
}
async promptForCity(step) {
return await step.prompt(CITY_PROMPT, "What city are your from?");
}
async captureCity(step) {
const profile = await this.profileAccessor.get(step.context);
profile.city = step.result;
profile.responded = true;
this.profileAccessor.set(step.context, profile);
return await step.next();
}
Bot
В примере проактивного обмена сообщениями все ссылки на диалоги хранятся в объекте. Мы можем использовать идентификатор разговора из запроса get в качестве значения ключа для получения ссылки на разговор и использовать эту ссылку для продолжения диалога. Из активного сообщения вы можете отправлять действия, доступ и состояние обновления, отменять диалоги и все другие обычные функции, которые вы можете выполнять с ботом.
class Bot extends ActivityHandler{
constructor(adapter, conversationState, userState) {
super();
this.adapter = adapter;
this.conversationReferences = {};
this.conversationState = conversationState;
this.userState = userState;
// Configure properties
this.profileAccessor = this.userState.createProperty(USER_PROFILE);
this.dialogState = this.conversationState.createProperty(DIALOG_STATE);
}
async sendProactiveMessages(conversationId) {
const conversationReference = this.conversationReferences[conversationId];
conversationReference && await this.adapter.continueConversation(conversationReference, async context => {
const { responded } = await this.profileAccessor.get(context);
if (!responded) {
const dc = await this.dialogs.createContext(context);
await dc.cancelAllDialogs();
await context.sendActivity('Sorry you took too long to respond..');
await this.conversationState.saveChanges(context);
}
});
}
}
Я знаю, что это немного сложно для простого действия, но я надеюсь, что это поможет!