aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

I have just updated amplify packages and interactions throws "not implemented" error #10974

Closed charithreddyv closed 1 year ago

charithreddyv commented 1 year ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Interactions

Amplify Categories

interactions

Environment information

``` # Put output below this line ```

Describe the bug

I have recently updated few of my amplify packages . @aws-amplify/pushnotification: from ^3.2.20 to ^5.0.14 aws-amplify: from ^3.3.17 to ^5.0.14 aws-amplify-react-native: from 4.3.0 to 7.0.2 react-native-audio-recorder-player: from 3.1.2 to 3.5.3 react-native-sound from 0.11.0 to 0.11.2 .

Everything seems to be working fine with minimal changes, like auth push notifications ...

when i do PostTextCommand i get not implemented error . There is similar issue but couldn't find how to resolve it.

from the latest docs , Amplify configure takes Interactions with bots but in my aws-exports.js i only have an array of aws_bots_config. i do also use addPluggable .

Expected behavior

should be able to send chat messages to lex like earlier.

Reproduction steps

upgrade the packages and try sending message with lex.

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line ```

aws-exports.js


const awsmobile = {
    "aws_project_region": "XXXXXX",
    "aws_cognito_identity_pool_id": "XXXXXX:YYY",
    "aws_cognito_region": "XXXXXX",
    "aws_user_pools_id": "XXXXXX_ZZZ",
    "aws_user_pools_web_client_id": "ZZZZ",
    "oauth": {},
    "aws_cognito_username_attributes": [
        "EMAIL"
    ],
    "aws_cognito_social_providers": [],
    "aws_cognito_signup_attributes": [
        "EMAIL"
    ],
    "aws_cognito_mfa_configuration": "OFF",
    "aws_cognito_mfa_types": [
        "SMS"
    ],
    "aws_cognito_password_protection_settings": {
        "passwordPolicyMinLength": "6",
        "passwordPolicyCharacters": []
    },
    "aws_cognito_verification_mechanisms": [
        "EMAIL"
    ],
    "aws_mobile_analytics_app_id": "TTTTT",
    "aws_mobile_analytics_app_region": "XXXXXX",
    "aws_bots": "enable",
    "aws_bots_config": [
        {
            "name": "TTTT",
            "alias": "$LATEST",
            "region": "XXXXXX"
        },
        {
            "name": "CCCC",
            "alias": "$LATEST",
            "region": "XXXXXX"
        },
        {
            "name": "ZZZZZ",
            "alias": "$LATEST",
            "region": "XXXXXX"
        }
    ],
    "aws_appsync_graphqlEndpoint": "https://GGGGGGGGG.appsync-api.XXXXXX.amazonaws.com/graphql",
    "aws_appsync_region": "XXXXXX",
    "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
    "aws_appsync_apiKey": "PPPPPP",
    "aws_cloud_logic_custom": [
        {
            "name": "avosApiRest",
            "endpoint": "https://NNNNN.execute-api.XXXXXX.amazonaws.com/dev",
            "region": "XXXXXX"
        }
    ],
    "aws_user_files_s3_bucket": "DJFHFBDK-dev",
    "aws_user_files_s3_bucket_region": "XXXXXX"
};

export default awsmobile;

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

tannerabread commented 1 year ago

Hi @charithreddyv have you seen the migration guide for upgrading to v4.x and also upgrading to v5.x?

Notable changes include named exports for Amplify packages and new necessary community dependencies for react native. How are you importing the Interactions package into your project?

Your aws-exports shouldn't be an issue, that is the default for Lex v1

How are you using that PostTextCommand? I do not believe we export that directly but rather import it into the AWSLexProvider.ts class from the @aws-sdk/client-lex-runtime-service for use in the Interactions.send method.

charithreddyv commented 1 year ago

Hai,

I have adjusted all the imports from amplify and push notification . example i import interactions and api like this import {Interactions, API} from "aws-amplify"; then Interactions.send(....

Yes i am getting PostTextCommand from @aws-sdk/client-lex-runtime-service which works with Interactions.send. i did not upgrade the net-info, amplify-cli , async-storage which i will do now . will get back to you shortly.

Thanks for the prompt response.

UPDATE: no joy, have update other packages but same error persists. no idea what is causing this issue .

tannerabread commented 1 year ago

Could you share how you are importing the PostTextCommand and using it? And also your package.json

charithreddyv commented 1 year ago

Importing PostTextCommand like so in my custom lex Provider tried using the one provided by interactions no difference .

import {
    LexRuntimeServiceClient,
    PostTextCommand,
    PostContentCommand,
} from '@aws-sdk/client-lex-runtime-service';

and following is how my package.json currently looks like

{
  "scripts": {
    "start": "react-native start",
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "openDebugger": "open 'rndebugger://set-debugger-loc?host=localhost&port=19001'",
    "prettier:write": "npx prettier --write **/*.{js,jsx,ts,tsx,json} && npx prettier --write *.{js,jsx,ts,tsx,json}",
    "lint": "tsc --noEmit && eslint --ext .js,.jsx,.ts,.tsx ./"
  },
  "dependencies": {
    "@aws-amplify/cli": "^4.48.0",
    "@aws-amplify/pushnotification": "^5.0.14",
    "@react-native-async-storage/async-storage": "^1.14.1",
    "@react-native-community/cli-platform-android": "^4.13.0",
    "@react-native-community/masked-view": "0.1.10",
    "@react-native-community/netinfo": "^5.9.10",
    "@react-native-community/push-notification-ios": "^1.8.0",
    "@react-navigation/bottom-tabs": "^5.11.3",
    "@react-navigation/drawer": "^5.11.4",
    "@react-navigation/native": "^5.8.10",
    "@react-navigation/stack": "^5.12.8",
    "@types/lodash": "^4.14.168",
    "@types/react-native-svg-charts": "^5.0.7",
    "@types/react-native-table-component": "^1.2.0",
    "@types/react-native-vector-icons": "^6.4.6",
    "@types/validator": "^13.1.3",
    "amazon-cognito-identity-js": "^4.5.7",
    "aws-amplify": "^5.0.14",
    "aws-amplify-react-native": "^7.0.2",
    "axios": "^0.21.1",
    "expo": "~40.0.0",
    "expo-app-loading": "^1.0.1",
    "expo-barcode-scanner": "^9.1.0",
    "expo-location": "~10.0.0",
    "expo-status-bar": "~1.0.3",
    "expo-task-manager": "~8.6.0",
    "expo-updates": "~0.4.0",
    "intl": "^1.2.5",
    "lodash": "^4.17.21",
    "moment": "^2.29.1",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-intl": "^5.10.16",
    "react-native": "0.63.5",
    "react-native-animatable": "^1.3.3",
    "react-native-app-intro-slider": "^4.0.4",
    "react-native-audio-recorder-player": "^3.5.3",
    "react-native-camera": "^3.43.6",
    "react-native-date-picker": "^4.2.0",
    "react-native-dropdown-picker": "^5.4.0",
    "react-native-elements": "^3.1.0",
    "react-native-fix-image": "^2.1.0",
    "react-native-flash-message": "^0.1.21",
    "react-native-fs": "^2.16.6",
    "react-native-gesture-handler": "~1.8.0",
    "react-native-get-random-values": "^1.6.0",
    "react-native-gifted-chat": "^0.16.3",
    "react-native-google-fit": "^0.18.2",
    "react-native-health": "^1.6.0",
    "react-native-image-picker": "^4.10.0",
    "react-native-loading-dots": "^1.3.2",
    "react-native-localize": "^2.0.1",
    "react-native-maps": "^1.3.2",
    "react-native-permissions": "^3.0.2",
    "react-native-progress": "^5.0.0",
    "react-native-purchases": "^5.0.2",
    "react-native-qrcode-scanner": "^1.5.4",
    "react-native-qrcode-svg": "^6.1.1",
    "react-native-raw-bottom-sheet": "^2.2.0",
    "react-native-reanimated": "~1.13.0",
    "react-native-safe-area-context": "3.1.9",
    "react-native-screens": "^2.15.2",
    "react-native-search-bar": "^3.5.1",
    "react-native-sound": "^0.11.2",
    "react-native-splash-screen": "^3.3.0",
    "react-native-svg": "^12.1.0",
    "react-native-svg-charts": "^5.4.0",
    "react-native-svg-transformer": "^0.14.3",
    "react-native-swipe-list-view": "^3.2.9",
    "react-native-table-component": "^1.2.1",
    "react-native-unimodules": "~0.12.0",
    "react-native-vector-icons": "^7.1.0",
    "react-native-voice": "^0.3.0",
    "react-native-web": "~0.13.12",
    "react-native-wheel-scrollview-picker": "^2.0.0",
    "react-redux": "^7.2.2",
    "redux-actions": "^2.6.5",
    "redux-devtools-extension": "^2.13.8",
    "redux-persist": "^6.0.0",
    "redux-saga": "^1.1.3",
    "reselect": "^4.0.0",
    "uuid": "^8.3.2",
    "validator": "^13.5.2"
  },
  "devDependencies": {
    "@babel/core": "~7.9.0",
    "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0",
    "@types/react": "~16.9.35",
    "@types/react-dom": "~16.9.8",
    "@types/react-native": "~0.63.2",
    "@types/react-redux": "^7.1.14",
    "@types/redux-actions": "^2.6.1",
    "@types/uuid": "^8.3.0",
    "@typescript-eslint/eslint-plugin": "^4.14.0",
    "babel-jest": "~25.2.6",
    "eslint": "^7.18.0",
    "eslint-config-airbnb-typescript": "^12.0.0",
    "eslint-config-prettier": "^7.2.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-jsx-a11y": "^6.4.1",
    "eslint-plugin-react": "^7.22.0",
    "jest": "~25.2.6",
    "prettier": "^2.2.1",
    "react-test-renderer": "~16.13.1",
    "typescript": "~4.0.0"
  },
  "private": true,
  "name": "XX-master",
  "version": "1.0.3"
}
tannerabread commented 1 year ago

tried using the one provided by interactions no difference

Just want to verify that you were saying you get the same result when you use Interactions.send?

Also I'm trying to figure out how you are using both @aws-sdk/client-lex-runtime-service and the Interactions package

Are you using the normal flow for the runtime client like shown here:

import { LexRuntimeServiceClient, PostTextCommand } from "@aws-sdk/client-lex-runtime-service"; // ES Modules import

const client = new LexRuntimeServiceClient(config);
const command = new PostTextCommand(input);
const response = await client.send(command);

Or are you using some combination of the above with the Interactions.send method?

Are you creating the client through the SDK as indicated by your importing of LexRuntimeServiceClient? Or are you setting up the bot through Interactions and then trying to use PostTextCommand?

If you could provide some implementation details on how you are using the 2 packages I can try to reproduce, but I am getting different errors trying to set up both at the same time

charithreddyv commented 1 year ago

Hai There , Apologies for the delay.

Below is my lex provider .


import { AbstractInteractionsProvider } from '@aws-amplify/interactions/src/Providers';
import { 
    InteractionsOptions,
    InteractionsResponse,
    InteractionsMessage
} from '@aws-amplify/interactions/src/types';
import {
    LexRuntimeServiceClient,
    PostTextCommand,
    PostContentCommand,
} from '@aws-sdk/client-lex-runtime-service';
import {
    ConsoleLogger as Logger,
    Credentials,
    getAmplifyUserAgent,
} from '@aws-amplify/core';
import { Auth } from '@aws-amplify/auth';
import { convert } from '@aws-amplify/interactions/src/Providers/AWSLexProviderHelper/convert';

const logger = new Logger('myLexProvider');

export class myLexProvider extends AbstractInteractionsProvider {
    private lexRuntimeServiceClient: LexRuntimeServiceClient;
    private _botsCompleteCallback: object;

    constructor(options: InteractionsOptions = {}) {
        super(options);
        this._botsCompleteCallback = {};
    }

    getProviderName() {
        return 'myLexProvider';
    }

    reportBotStatus(data, botname) {
        // Check if state is fulfilled to resolve onFullfilment promise
        logger.debug('postContent state', data.dialogState);
        if (
            data.dialogState === 'ReadyForFulfillment' ||
            data.dialogState === 'Fulfilled'
        ) {
            if (typeof this._botsCompleteCallback[botname] === 'function') {
                setTimeout(
                    () =>
                        this._botsCompleteCallback[botname](null, { slots: data.slots }),
                    0
                );
            }

            if (
                this._config &&
                typeof this._config[botname].onComplete === 'function'
            ) {
                setTimeout(
                    () => this._config[botname].onComplete(null, { slots: data.slots }),
                    0
                );
            }
        }

        if (data.dialogState === 'Failed') {
            if (typeof this._botsCompleteCallback[botname] === 'function') {
                setTimeout(
                    () => this._botsCompleteCallback[botname]('Bot conversation failed'),
                    0
                );
            }

            if (
                this._config &&
                typeof this._config[botname].onComplete === 'function'
            ) {
                setTimeout(
                    () => this._config[botname].onComplete('Bot conversation failed'),
                    0
                );
            }
        }
    }

    async sendMessage(
        botname: string,
        message: string | InteractionsMessage | object
    ): Promise<InteractionsResponse> {
        if (!this._config[botname]) {
            return Promise.reject('Bot ' + botname + ' does not exist');
        }
        const credentials = await Credentials.get();
        if (!credentials) {
            return Promise.reject('No credentials');
        }

        this.lexRuntimeServiceClient = new LexRuntimeServiceClient({
            region: this._config[botname].region,
            credentials,
            customUserAgent: getAmplifyUserAgent(),
        });

        let params;
        if (typeof message === 'string') {
            const userInfo = await Auth.currentUserInfo();
            params = {
                botAlias: this._config[botname].alias,
                botName: botname,
                inputText: message,
                userId: userInfo.username,
            };

            logger.debug('postText to LEX', message);

            try {
                const postTextCommand = new PostTextCommand(params);
                const data = await this.lexRuntimeServiceClient.send(postTextCommand);
                logger.debug('RESPONSE: ', data);
                this.reportBotStatus(data, botname);
                return data;
            } catch (err) {
                return Promise.reject(err);
            }
        } else if (typeof  message === 'object' && message.hasOwnProperty('sessionAttributes')) {
            const {inputText, sessionAttributes} = message as any || {};
            const userInfo = await Auth.currentUserInfo();
            params = {
                botAlias: this._config[botname].alias,
                botName: botname,
                inputText,
                userId: userInfo.username,
                sessionAttributes
            };

            logger.debug('postText to LEX', message);

            try {
                const postTextCommand = new PostTextCommand(params);
                const data = await this.lexRuntimeServiceClient.send(postTextCommand);
                logger.debug('RESPONSE: ', data);
                this.reportBotStatus(data, botname);
                return data;
            } catch (err) {
                return Promise.reject(err);
            }
        } else {
            const {
                content,
                options: { messageType },
            } = message as InteractionsMessage;
            if (messageType === 'voice') {
                params = {
                    botAlias: this._config[botname].alias,
                    botName: botname,
                    contentType: 'audio/x-l16; sample-rate=16000',
                    inputStream: content,
                    userId: credentials.identityId,
                    accept: 'audio/mpeg',
                };
            } else {
                params = {
                    botAlias: this._config[botname].alias,
                    botName: botname,
                    contentType: 'text/plain; charset=utf-8',
                    inputStream: content,
                    userId: credentials.identityId,
                    accept: 'audio/mpeg',
                };
            }
            logger.debug('postContent to lex', message);
            try {
                const postContentCommand = new PostContentCommand(params);
                const data = await this.lexRuntimeServiceClient.send(
                    postContentCommand
                );
                const audioArray = await convert(data.audioStream);
                this.reportBotStatus(data, botname);
                return { ...data, ...{ audioStream: audioArray } };
            } catch (err) {
                return Promise.reject(err);
            }
        }
    }

    onComplete(botname: string, callback) {
        if (!this._config[botname]) {
            throw new ErrorEvent('Bot ' + botname + ' does not exist');
        }
        this._botsCompleteCallback[botname] = callback;
    }
}

plug it like this in app.tsx and set the provider name for each bot before amplify.configure


import  { Interactions } from "aws-amplify";

Interactions.addPluggable(new myLexProvider());
awsconfig.aws_bots_config.forEach(function (bot: any) {
  bot.providerName = "myLexProvider";
  bot.alias = "BotAlias";
});

in my chatbot screen i send the text like so

import {Interactions, API} from "aws-amplify";
return Interactions.send(
        botName,
        inputText
    );

Hope this helps, thanks.

tannerabread commented 1 year ago

Hi @charithreddyv. Sorry for the late response, I have been trying to reproduce your error with what you provided and do not see the same. I copy/pasted your code into mine and everything seems to be working as expected, the only thing I've noticed so far was line 18 in the lex provider convert is now exported from a utils file and not a convert file:

- import { convert } from '@aws-amplify/interactions/src/Providers/AWSLexProviderHelper/convert';
+ import { convert } from '@aws-amplify/interactions/src/Providers/AWSLexProviderHelper/utils';

In case it helps, I uploaded my sample app that was as minimal changes as I could make to a react-native starter app. Note the only other difference I am aware of from what you told me is that I used the new UI package for React Native's withAuthenticator rather than the legacy package you were using from aws-amplify-react-native. I wouldn't think that would effect what is happening here but it was worth pointing out.

Here is what my config for bots looked like: image

Please let me know if you see anything I'm doing differently from you so that I can try to reproduce your error. For a sanity check I looked through node_modules/@aws-sdk/client-lex-runtime-service and found that PostTextCommand should still be exported

tannerabread commented 1 year ago

@charithreddyv were you able to look at my sample repo or implement the suggestion about the import?

tannerabread commented 1 year ago

Hi 👋 Closing this as we have not heard back from you. If you are still experiencing this issue and are in need of assistance, please feel free to comment and provide us with any information previously requested by our team members so we can re-open this issue and be better able to assist you.

Thank you!