3

Currenty, I am trying to develop a Chatbot using the SDK v4 of the Bot framework and I have the following problem: Based on the BasicBot template from Microsoft I tried to build my own waterfall dialogue. Within the function promptUserForAttachmentStep of the waterfalldialog the user should be asked to upload an image with the AttachmentPrompt. Due to this prompt, it is no longer possible to access the UserProfile object within the following steps from the memory using the state accessor. All I got is an empty object.

It does not matter what kind of prompt it is. Within the prompt step, the object can still be called. But not after that. However, as soon as I remove the prompt, it can be called in the next step.

Unfortunately, I don't quite understand why this is so. This is not a problem within the template.

I would be glad about help

Many greetings

import { StatePropertyAccessor } from 'botbuilder';
import { ComponentDialog, PromptValidatorContext, WaterfallDialog, WaterfallStepContext, AttachmentPrompt, TextPrompt } from 'botbuilder-dialogs';
import { FaceAPI } from './API_Files/faceAPI_conn';
import { SQLConntector } from './API_Files/mysql_conn';
import { UserProfile } from './userProfile';

const FACE_DIALOG = 'faceDialog';
const LOGIN_DIALOG = 'loginDialog'
const ATTACH_PROMPT = 'attachPrompt';
const SECRET_PROMPT = 'secretPrompt;'

export class authentDialog extends ComponentDialog {
    private userProfileAccessor: StatePropertyAccessor<UserProfile>;
    private faceAPI;
    private sqlConnector: SQLConntector;

    constructor (dialogId: string, userStateAccessor: StatePropertyAccessor<UserProfile>) {
        super(dialogId);

        // TODO: Daten auslagern
        this.faceAPI =  new FaceAPI (
            "https://northeurope.api.cognitive.microsoft.com/face/v1.0/",
            ""
        );
        this.sqlConnector = new SQLConntector (
            "",
            "",
            "",
            ""
        );

        this.addDialog(new WaterfallDialog<UserProfile>(FACE_DIALOG, [
            this.initializeUserStateStep.bind(this),
            this.promptUserForAttachmentStep.bind(this),
            this.identificateFaceId.bind(this),
            this.detectPersonId.bind(this)
        ]));

        this.addDialog(new AttachmentPrompt(ATTACH_PROMPT));
        this.addDialog(new TextPrompt(SECRET_PROMPT));

        this.addDialog(new WaterfallDialog<UserProfile> (LOGIN_DIALOG, [
            this.getEmployeeName.bind(this)
        ]));


        this.userProfileAccessor = userStateAccessor;
    }

    private async initializeUserStateStep (step: WaterfallStepContext<UserProfile>) {
        const userProfile = await this.userProfileAccessor.get(step.context);
        if (userProfile === undefined) {
            await this.userProfileAccessor.set(step.context, new UserProfile());
        }
        return await step.next();
    }

    private async promptUserForAttachmentStep (step: WaterfallStepContext<UserProfile>) {
        // This writes the userProfile object
        console.log(await this.userProfileAccessor.get(step.context));
        return await step.prompt(ATTACH_PROMPT,'Bitte lade zur Autorisierung ein Foto deines Gesichts hoch.');
    }

    private async identificateFaceId (step: WaterfallStepContext<UserProfile>) {
        // This is now an empty object
        console.log(await this.userProfileAccessor.get(step.context));
        if (!step.result[0].contentUrl) {
            await step.context.sendActivities([
                {type: 'typing'},
                {type: 'delay', value: 2000},
                {type: 'message', text: 'Ich benötige ein Foto :)' }
            ])
            return await step.replaceDialog(FACE_DIALOG);
        } else {
            const faceID = await this.faceAPI.getDetectedFaceId(step.result[0].contentUrl);
            if (!faceID) {
                await step.context.sendActivities([
                    {type: 'typing'},
                    {type: 'delay', value: 2000},
                    {type: 'message', text: 'Ich konnte kein Gesicht erkennen :(.' },
                    {type: 'typing'},
                    {type: 'delay', value: 2000},
                    {type: 'message', text: 'Bitte versuche es nochmal.' }
                ]);
                return await step.replaceDialog(FACE_DIALOG);
            } else {
                return await step.next(faceID);
            }
        }
    }
}
Tobias C.
  • 61
  • 1
  • 8
  • I'm a little confused. Is this based off the typescript Basic Bot (bot.ts) sample from the BotBuilder-Samples? Also, where is the onTurn method? Is there code of yours missing? – Steven Kanberg Jan 28 '19 at 20:13
  • Hey Steven, yes, this is based off the typescript Basic Bot. I'm outsourcing the dialogue just like in the sample. There it was the Greeting Dialog. If you also need the Bot.ts script, I'm happy to hand it in. I have currently solved it in such a way that I first create an object within the constructor and only store it in memory within the last dialog. The part of the code is not visible in the example above. – Tobias C. Jan 28 '19 at 20:46
  • I would recommend posting your solution as an answer so others can benefit from it. – Steven Kanberg Jan 28 '19 at 22:20
  • As Steven asked, where is the onTurn() method for your code? Are you saving your conversation state after each turn? –  Jan 29 '19 at 12:59
  • Hello Michael, the code shown above is an outsourced dialog. The module inherits from the ComponentDialog. Therefore there is no onTurn method here. However, the error was still on my part. I had a thinking error :D and already understood it. I thank you both anyway for the help. – Tobias C. Jan 31 '19 at 14:39

0 Answers0