Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #54 from alexa/feature/catalog-explorer/selection-…
Browse files Browse the repository at this point in the history
…by-name

Feature/catalog explorer/selection by name
  • Loading branch information
karanggg authored Mar 15, 2023
2 parents ef2e68f + 62b8698 commit 4a3dbff
Show file tree
Hide file tree
Showing 20 changed files with 624 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ exports.handler = SkillBuilders.custom()
// are required to be defined by skills using catalog explorer
...CatalogExplorer.createHandlers(
`${skillDomain}.getPage`,
`${skillDomain}.indexOfItemByNameApi`,
`${skillDomain}.selectItemApi`,
`${skillDomain}.search_`,
`${skillDomain}.getProperty_`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import prompts.*
import displays.*
import slotTypes.*

/************************
* CREATE CATALOG ITEM
************************/
multiModalWelcome = MultiModalResponse {
apl = WelcomeAPL,
apla = AlexaConversationsWelcome
Expand All @@ -29,10 +32,6 @@ import slotTypes.*
}
)

/************************
* CREATE CATALOG ITEM
************************/

type BookItem {
String title
String genre
Expand Down Expand Up @@ -161,9 +160,17 @@ selectByIndexEvent = utterances<IndexSlotWrapper>([
"{index}"
])

action RecommendationResult<SearchConditions, BookItem> getPage(SearchConditions searchConditions, Optional<String> pageToken, optional CatalogReference catalogRef)
action RecommendationResult<SearchConditions, BookItem> selectItemApi(SearchConditions searchConditions, Page<BookItem> page, Number index, optional CatalogReference catalogRef)
selectByNameEvent = utterances<ItemNameSlotWrapper<TITLE>>([
"{name}",
"{name} would be good",
"I like {name}",
"{name} sounds interesting",
"show me {name}"
])

action RecommendationResult<SearchConditions, BookItem> getPage(SearchConditions searchConditions, Optional<String> pageToken, optional CatalogReference catalogRef)
action RecommendationResult<SearchConditions, BookItem> selectItemApi(Page<BookItem> page, Number index, optional SearchConditions searchConditions, optional CatalogReference catalogRef)
action NUMBER indexOfItemByNameApi(Page<BookItem> page, TITLE name)

/************************
* OFFERS
Expand Down Expand Up @@ -241,25 +248,25 @@ action CatalogActionResult performAction_SendToPhone(List<BookItem> items, optio
* Anonymous Dialogs
************************/

dialog RecommendationResult<SearchConditions, BookItem> allSearchPathsAdaptor(PropertyConfig<SearchConditions, BookItem> config, optional CatalogReference catalogRef) {
dialog RecommendationResult<SearchConditions, BookItem> allSearchPathsAdaptor(PropertyConfig<SearchConditions, BookItem, TITLE> config, optional CatalogReference catalogRef) {
sample {
allSearchPaths_2(config)
}
}

dialog RecommendationResult<SearchConditions, BookItem> baseSearchPathsAdaptor(PropertyConfig<SearchConditions, BookItem> config, optional CatalogReference catalogRef) {
dialog RecommendationResult<SearchConditions, BookItem> baseSearchPathsAdaptor(PropertyConfig<SearchConditions, BookItem, TITLE> config, optional CatalogReference catalogRef) {
sample {
baseSearchPaths_2(config)
}
}

dialog RecommendationResult<SearchConditions, BookItem> allFollowUpPathsAdaptor(PropertyConfig<SearchConditions, BookItem> config, RecommendationResult<SearchConditions, BookItem> priorResult, optional CatalogReference catalogRef) {
dialog RecommendationResult<SearchConditions, BookItem> allFollowUpPathsAdaptor(PropertyConfig<SearchConditions, BookItem, TITLE> config, RecommendationResult<SearchConditions, BookItem> priorResult, optional CatalogReference catalogRef) {
sample {
allFollowUpPaths_5(config, priorResult, catalogRef)
}
}

dialog CatalogActionResult allCatalogActionPathsAdaptor(PropertyConfig<SearchConditions, BookItem> config, List<BookItem> items, optional CatalogReference catalogRef) {
dialog CatalogActionResult allCatalogActionPathsAdaptor(PropertyConfig<SearchConditions, BookItem, TITLE> config, List<BookItem> items, optional CatalogReference catalogRef) {
sample {
allCatalogActionPaths_3(config, items, catalogRef)
}
Expand Down Expand Up @@ -305,14 +312,16 @@ dialog MainDialog{
]

//Buidling the navigation configuration
navigationConfig = buildNavigationConfig<SearchConditions, BookItem>(
navigationConfig = buildNavigationConfig<SearchConditions, BookItem, TITLE>(
nextEvent = nextEvent,
prevEvent = prevEvent,
getPageApi = getPage,
selectByOrdinalEvent = selectByOrdinalEvent,
selectByRelativePositionEvent = selectByRelativePositionEvent,
selectByNameEvent = selectByNameEvent,
selectByIndexEvent = selectByIndexEvent,
selectItemApi = selectItemApi
indexOfItemByNameApi = indexOfItemByNameApi,
selectItemApi = selectItemApi,
)

//Buidling the Offers configuration
Expand Down Expand Up @@ -375,7 +384,7 @@ dialog MainDialog{
]

//Building the main catalog explorer configuration object
config = buildCatalogConfig<SearchConditions, BookItem>(
config = buildCatalogConfig<SearchConditions, BookItem, TITLE>(
searchPatterns,
navigationConfig,
catalogProperties,
Expand All @@ -388,7 +397,7 @@ dialog MainDialog{
)

//calling the the catalog explorer component with the configuration object
result = exploreCatalog<SearchConditions, BookItem>(config)
result = exploreCatalog<SearchConditions, BookItem, TITLE>(config)

//Below part is just for a workaround that the main deployable dialog cannont
//return CatalogExplorationResult which is the return type of the component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,96 @@
}
}
]
},
{
"name": "TITLE",
"values": [
{
"name": {
"value": "The Shining"
}
},
{
"name": {
"value": "It"
}
},
{
"name": {
"value": "Pet Sematary"
}
},
{
"name": {
"value": "The Green Mile"
}
},
{
"name": {
"value": "Under the Dome"
}
},
{
"name": {
"value": "Doctor Sleep"
}
},
{
"name": {
"value": "Four Past Midnight"
}
},
{
"name": {
"value": "Do androids dream of robotic sheep"
}
},
{
"name": {
"value": "Dune"
}
},
{
"name": {
"value": "A Game of Thrones"
}
},
{
"name": {
"value": "Pride and Prejudice"
}
},
{
"name": {
"value": "Hyperion"
}
},
{
"name": {
"value": "Ready Player One"
}
},
{
"name": {
"value": "Harry Potter: Deathly Hallows"
}
},
{
"name": {
"value": "The Fault in Our Stars"
}
},
{
"name": {
"value": "The Notebook"
}
},
{
"name": {
"value": "The Hobbit"
}
}
]
}
]
}
Expand Down
85 changes: 85 additions & 0 deletions catalog-explorer/lambda/handlers/index-of-by-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0
// Licensed under the Amazon Software License http://aws.amazon.com/asl/

import { HandlerInput } from 'ask-sdk-core';
import { Response } from "ask-sdk-model";

import { apiNamespace } from '../config';
import { CatalogExplorer } from '../interface';
import { Page } from "../catalog-provider";
import { CatalogExplorerSessionState } from '../state';
import * as util from '../util';
import { BaseApiHandler } from './base-api-handler';

interface Arguments{
// the page to retrieve an item from
page: Page<any>;

// the name of the item
name: string;
}

export type ItemNameMatcher = (items: any[], name: string) => number | undefined;

// called when a user tries to select a item on the current page by name,
// utilizes a matcher callback to determine how to match an item to name;
// assuming each item simply has a "name" field by default
export class IndexOfItemByNameHandler extends BaseApiHandler {
static defaultApiName = `${apiNamespace}.indexOfItemByNameApi`;

// default matcher just assumes each item has a 'name' field that can be matched against
static defaultItemNameMatcher: ItemNameMatcher = (items, name) => {
return items.findIndex((item) => {
return item?.name?.toLowerCase() == name;
});
}

private itemNameMatcher: ItemNameMatcher;

constructor(
apiName: string = IndexOfItemByNameHandler.defaultApiName,
itemNameMatcher: ItemNameMatcher = IndexOfItemByNameHandler.defaultItemNameMatcher,
) {
super(apiName);
this.itemNameMatcher = itemNameMatcher;
}

handle(handlerInput : HandlerInput): Response {
const args = util.getApiArguments(handlerInput) as Arguments;

let currentRecommendationsPage: Page<any>

if(CatalogExplorer.useSessionArgs){
currentRecommendationsPage = this.getRecommendationPageFromSession(handlerInput);
}
else{
currentRecommendationsPage = args.page;
}

const index = this.itemNameMatcher(currentRecommendationsPage.items, args.name);
if (index == undefined || index < 0) {
throw new Error("indexOfItemByName: API called with name matching no displayed element");
} else if (index >= currentRecommendationsPage.items.length) {
throw new Error("indexOfItemByName: item matcher returned index out of bounds of current page");
}else{
console.log("indexOfItemByName: ",index);
}

return handlerInput.responseBuilder
.withApiResponse(index+1) // index in ACDL currently starts at 1 to match ordinal
.withShouldEndSession(false)
.getResponse();
}

getRecommendationPageFromSession(handlerInput: HandlerInput): Page<any>{
const sessionState = CatalogExplorerSessionState.load(handlerInput);

const recommendationResultFromSession = sessionState.argsState?.recommendationResult;
if (recommendationResultFromSession === undefined){
throw new Error("Recommendation Result from session state in undefined");
}

return recommendationResultFromSession.recommendations;
}
}
1 change: 1 addition & 0 deletions catalog-explorer/lambda/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./base-api-handler";
export * from "./convert-ordinal-to-index";
export * from "./convert-relative-position-to-index";
export * from "./index-of-by-name";
export * from "./accept-offer-handler";
export * from "./get-page-handler";
export * from "./get-property-handler";
Expand Down
3 changes: 3 additions & 0 deletions catalog-explorer/lambda/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ConvertOrdinalToIndexHandler,
ConvertRelativePositionToIndexHandler,
GetPageHandler,
IndexOfItemByNameHandler,
GetPropertyHandler,
PerformActionHandler,
SearchHandler,
Expand Down Expand Up @@ -146,6 +147,7 @@ export class CatalogExplorer {
// Returns: array of constructed handlers
static createHandlers(
getPageApiName: string,
indexOfItemByNameApiName: string,
selectItemApiName: string,
searchApiName: string,
getPropertyApiName: string,
Expand All @@ -164,6 +166,7 @@ export class CatalogExplorer {

// APIs that have to be defined by skill dev (as they use generics)
new SearchHandler(searchApiName),
new IndexOfItemByNameHandler(indexOfItemByNameApiName),
new GetPageHandler(getPageApiName),
new SelectItemHandler(selectItemApiName),
new AcceptOfferHandler(acceptOfferApiName),
Expand Down
9 changes: 1 addition & 8 deletions catalog-explorer/lambda/providers/ddb-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class DDBListProvider<SearchConditions, Item> implements CatalogProvider
}
}
count = seenListEntries.size;
console.log("Count", count);
console.log("Seen item Count", count);
console.log("Items in table:", results.Table?.ItemCount)
if(count === results.Table?.ItemCount)
{
Expand Down Expand Up @@ -222,8 +222,6 @@ export class DDBListProvider<SearchConditions, Item> implements CatalogProvider
excludeList.push(temp[y]);
}
}
console.log("Exclude List:", excludeList);
console.log("DDB key:", key);
const filterExpression= "NOT #pk IN (" + excludeList.map((_: any, index: string) => ":pk" + index).join(", ") + ")";
const expressionAttributeNames = { "#pk": key };
let expressionAttributeValue : any = {};
Expand All @@ -232,12 +230,8 @@ export class DDBListProvider<SearchConditions, Item> implements CatalogProvider
});
let unseenList: any[] = [];
let scanResults: any ;
console.log("filterExpression:",filterExpression);
console.log("expressionAttributeNames:",expressionAttributeNames);
console.log("ExpressionAttributeValues:",expressionAttributeValue);
do
{
console.log("INSIDE LOOP");
let scanCommand: ScanCommandInput = {
Limit : pageSize,
TableName : this.tableName,
Expand Down Expand Up @@ -322,7 +316,6 @@ export class DDBListProvider<SearchConditions, Item> implements CatalogProvider
try {
const results = await this.client.send(new QueryCommand(params));
this.lek = results.LastEvaluatedKey;
console.log("LEKKKK:",this.lek);
(results.Items || []).forEach(function (element: any, index: any, array: any) {
matchingData.push(unmarshall(element));
});
Expand Down
2 changes: 1 addition & 1 deletion catalog-explorer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alexa-skill-components/catalog-explorer",
"version": "0.0.2",
"version": "0.0.3",
"publisher": "Amazon",
"description": "Alexa skill component for searching, refining and navigating through a catalog",
"license": "AmznSL-1.0",
Expand Down
4 changes: 2 additions & 2 deletions catalog-explorer/src/actionAdapters.acdl
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import com.amazon.alexa.schema.*
import com.amazon.alexa.skill.components.catalog_explorer.types.*
import com.amazon.alexa.skill.components.catalog_explorer.action.*

dialog CatalogActionResult allCatalogActionPaths_1<SearchConditions, Item> (
PropertyConfig<SearchConditions, Item> config,
dialog CatalogActionResult allCatalogActionPaths_1<SearchConditions, Item, ItemName> (
PropertyConfig<SearchConditions, Item, ItemName> config,
List<Item> items,
optional CatalogReference catalogRef
) {
Expand Down
Loading

0 comments on commit 4a3dbff

Please sign in to comment.