[Help] I cannot connect my Alexa Skill to a DB

0

Hello! I have been trying for weeks to connect a MySQL-based RDS database to an Alexa Skill, this skill is a test, using the data provided through the "Build your first alexa skill" course. The problem is that when I go to the "Test" section and make queries it returns cached data from the previous queries. But it does not return the value that is in the database. Checking RDS tells me that there are two connections, one I assume is MySQL Workbench, which is the one I use to manage the tables, and the other is Alexa Skill.

Another issue I ran into is that when I want to see the CloudWatch Logs it is not loading, I get an error saying "not available in this account or region".

index.js code:

/* *
 * This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2).
 * Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
 * session persistence, api calls, and more.
 * */
const Alexa = require('ask-sdk-core');
const helper = require('./helper');
const mysql = require('mysql');
require('mysql/database');

async function getServicePriceSync(serviceType, serviceDetail) {
  try {
    const connection = await mysql.createConnection({
      host: 'database-1.czmoiem282w5.us-east-1.rds.amazonaws.com',
      user: '...',
      password: '...',
      database: 'houndhubDB',
      port: 3306
    });

    const [rows] = await connection.execute(
      'SELECT price FROM services WHERE service = ? AND serviceDetail = ?',
      [serviceType, serviceDetail]
    );

    connection.end();

    if (!rows.length) {
      return null; // Indicates price not found
    }

    return rows[0].price;
  } catch (error) {
    console.error('Error fetching service price:', error);
    throw new Error('An error occurred while retrieving the service price.');
  }
}

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
    },
    handle(handlerInput) {
        const speakOutput = 'Hello! Welcome to Hound Hub. We offer dog training, dog walking, and veterinary services. Which would you like to try?';

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    }
};

const HelpIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
    },
    handle(handlerInput) {
        const speakOutput = 'Hound Hub lets you request selected services for your dog. Try asking for dog training, dog walking, or veterinary services.';

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    }
};

const CancelAndStopIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'
                || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');
    },
    handle(handlerInput) {
        const speakOutput = 'Goodbye!';

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .getResponse();
    }
};
/* *
 * FallbackIntent triggers when a customer says something that doesn’t map to any intents in your skill
 * It must also be defined in the language model (if the locale supports it)
 * This handler can be safely added but will be ingnored in locales that do not support it yet 
 * */
const FallbackIntentHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.FallbackIntent';
    },
    handle(handlerInput) {
        const speakOutput = 'Sorry, I don\'t know about that. Please try again.';

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    }
};
/* *
 * SessionEndedRequest notifies that a session was ended. This handler will be triggered when a currently open 
 * session is closed for one of the following reasons: 1) The user says "exit" or "quit". 2) The user does not 
 * respond or says something that does not match an intent defined in your voice model. 3) An error occurs 
 * */
const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';
    },
    handle(handlerInput) {
        console.log(`~~~~ Session ended: ${JSON.stringify(handlerInput.requestEnvelope)}`);
        // Any cleanup logic goes here.
        return handlerInput.responseBuilder.getResponse(); // notice we send an empty response
    }
};

const GetServiceIntentHandler = {
    canHandle(handlerInput) {
         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' 
          && Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetServiceIntent';
    },
    handle(handlerInput) {
        
        var service;
        var resolvedService;
        var serviceSlot;
    
        const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
        
        serviceSlot = Alexa.getSlot(handlerInput.requestEnvelope, "service");
        service = serviceSlot.value;

        //service = helper.getSpokenWords(handlerInput, "service");
        resolvedService = helper.getResolvedWords(handlerInput, "service");

        var speakOutput = "";

        if (resolvedService) {
        
        var selectedService = resolvedService[0].value.name
        
        speakOutput = `I heard you say that you want a dog ${selectedService}. `
        if (selectedService === "walker") {
         speakOutput += `We offer daily, weekly, or twice-a-week dog walking packages. `;
         }
        if (selectedService === "vet") {
         speakOutput += `We offer vaccinations and checkups. `;
         }
        if (selectedService === "trainer") {
         speakOutput += `We offer beginner, intermediate, and advanced obedience training. `;
         }
         speakOutput += "Which service are you interested in?";
         
         const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
         
         sessionAttributes.selectedService = selectedService;
         
         handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
        }

         else {
             speakOutput = `I heard you say ${service}. I don't offer that service. Choose from dog training, dog walking, or veterinary care.`;
         }
        
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    }
};

const GetPriceIntentHandler = {
  canHandle(handlerInput) {
    return (
      Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
      Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetPriceIntent'
    );
  },
  async handle(handlerInput) {
    try {
      const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
      const selectedService = sessionAttributes.selectedService;
      const serviceDetailSlot = Alexa.getSlot(handlerInput.requestEnvelope, 'serviceDetail');
      const serviceDetail = serviceDetailSlot.value;

      console.log('Selected Service:', selectedService);
      console.log('Service Detail:', serviceDetail);

      if (!selectedService) {
        return handlerInput.responseBuilder
          .speak('What service would you like?')
          .reprompt('What service would you like?')
          .getResponse();
      }

      const price = await getServicePriceSync(selectedService, serviceDetail);

      console.log('Price from Database:', price);

      if (!price) {
        const speakOutput = `Sorry, I couldn't find the price for the "${selectedService}" service at the "${serviceDetail}" level.`;
        return handlerInput.responseBuilder
          .speak(speakOutput)
          .reprompt(speakOutput)
          .getResponse();
      }

      const speakOutput = `The price for the "${selectedService}" service at the "${serviceDetail}" level is ${price} dollars.`;

      return handlerInput.responseBuilder
        .speak(speakOutput)
        .reprompt(speakOutput)
        .getResponse();
    } catch (error) {
      console.error('Error handling GetPriceIntent:', error);
      const speakOutput = 'Sorry, I had trouble getting the price. Please try again.';
      return handlerInput.responseBuilder
        .speak(speakOutput)
        .reprompt(speakOutput)
        .getResponse();
    }
  }
};

/* *
 * The intent reflector is used for interaction model testing and debugging.
 * It will simply repeat the intent the user said. You can create custom handlers for your intents 
 * by defining them above, then also adding them to the request handler chain below 
 * */
const IntentReflectorHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest';
    },
    handle(handlerInput) {
        const intentName = Alexa.getIntentName(handlerInput.requestEnvelope);
        const speakOutput = `You just triggered ${intentName}`;

        return handlerInput.responseBuilder
            .speak(speakOutput)
            //.reprompt('add a reprompt if you want to keep the session open for the user to respond')
            .getResponse();
    }
};
/**
 * Generic error handling to capture any syntax or routing errors. If you receive an error
 * stating the request handler chain is not found, you have not implemented a handler for
 * the intent being invoked or included it in the skill builder below 
 * */
const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        const speakOutput = 'Sorry, I had trouble doing what you asked. Please try again.';
        console.log(`~~~~ Error handled: ${JSON.stringify(error)}`);

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    }
};

/**
 * This handler acts as the entry point for your skill, routing all request and response
 * payloads to the handlers above. Make sure any new handlers or interceptors you've
 * defined are included below. The order matters - they're processed top to bottom 
 * */
exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(
        LaunchRequestHandler,
        HelpIntentHandler,
        CancelAndStopIntentHandler,
        FallbackIntentHandler,
        SessionEndedRequestHandler,
        GetServiceIntentHandler,
        GetPriceIntentHandler,
        IntentReflectorHandler)
    .addErrorHandlers(
        ErrorHandler)
    .withCustomUserAgent('sample/hello-world/v1.2')
    .lambda();

package.json

{
  "name": "hello-world",
  "version": "1.2.0",
  "description": "alexa utility for quickly building skills",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Amazon Alexa",
  "license": "Apache License",
  "dependencies": {
    "ask-sdk-core": "^2.7.0",
    "ask-sdk-model": "^1.19.0",
    "aws-sdk": "^2.326.0",
    "ejs": "latest",
    "express": "latest",
    "body-parser": "latest",
    "mysql": "latest"
  }
}

Database script:

-- MySQL Script generated by MySQL Workbench
-- Thu Feb 15 11:44:29 2024
-- Model: New Model    Version: 1.0
-- MySQL Workbench Forward Engineering

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema houdhubDB
-- -----------------------------------------------------

-- -----------------------------------------------------
-- Schema houdhubDB
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `houdhubDB` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ;
USE `houdhubDB` ;

-- -----------------------------------------------------
-- Table `houdhubDB`.`services`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `houdhubDB`.`services` (
  `service` VARCHAR(50) NOT NULL,
  `serviceDetail` VARCHAR(50) NULL,
  `price` INT NULL,
  INDEX `idx_services_price` (`price` ASC) VISIBLE,
  PRIMARY KEY (`service`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
CesarV
asked 2 months ago138 views
No Answers

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions