Change color of individual list items in AlexaTextList? - alexa

Is there a way to specify a color for the text in specific items in an AlexaTextList? In my example, I'd like to, based on a dynamic value in my lambda_handler, specific whether each text list item is red, yellow, or green. This is the template for the display:
{
"type": "APL",
"version": "1.8",
"license": "Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0\nLicensed under the Amazon Software License http://aws.amazon.com/asl/",
"theme": "dark",
"import": [
{
"name": "alexa-layouts",
"version": "1.5.0"
}
],
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "AlexaTextList",
"headerTitle": "${payload.textListData.title}",
"listItems": "${payload.textListData.listItems}",
"secondaryText": "${payload.headlineTemplateData.properties.textContent.secondaryText.text}",
"backgroundColor": "teal",
"id": "covidList"
}
]
}
}

You can't with AlexaTextList.
On APL, all component have the same base properties
One of the property is called style, and you can apply a style with a color but AlexaTextLists doesn't acknowledge it.
{
"redColor": {
"values": [
{
"color": "red"
}
]
},
}
// in your components:
{ ... "style": "redColor", ... }
AlexaTextLists contains a list of AlexaTextListItem and doesn't acknowledge it as well.
As of today, I recommend you to rely on Container and Text when you need more flexibility.
{
"type": "APL",
"version": "1.8",
"license": "Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0\nLicensed under the Amazon Software License http://aws.amazon.com/asl/",
"theme": "dark",
"import": [
{
"name": "alexa-layouts",
"version": "1.5.0"
}
],
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"height": "100vh",
"width": "100vw",
"direction": "column",
"alignItems": "center",
"items": [
{
"type": "Text",
"color": "red",
"text": "Text in red"
},
{
"type": "Text",
"color": "blue",
"text": "Text in blue"
}
]
}
]
},
"styles": {}
}

Related

Vega Chloropleth Map Visualisation

For some reason vega is reading my data as 0 when the numbers range from 1-234.
I am attempting to show a visualisation of a chloropleth map of crypto-ownership by country.
The countries have been ranked 1-234 and that is meant to show on the tooltip however, this is being shown as 0 on the tooltip. How do I fix this.
Here is my code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title":{
"text": "Crypto Ownership Worldwide",
"subtitle": "Source: FILL",
"anchor": "start"
},
"width":500,
"height":400,
"data": {
"url": "https://raw.githubusercontent.com/tomiwav/tomiwav.github.io/main/custom.geo%20(3).json",
"format":{"property": "features"}
},
"projection":{"type": "mercator"},
"transform": [
{
"lookup":"properties.name",
"from":{
"key": "Country",
"fields": ["Rank"],
"data":{
"url": "https://raw.githubusercontent.com/tomiwav/tomiwav.github.io/main/datarank.csv",
"format":{"type":"csv"}
}
}
}
],
"mark":{
"type": "geoshape",
"fill":"lightgray",
"stroke":"black",
"strokeWidth":0.5
},
"encoding": {
"color": {
"field": "Rank",
"type": "quantitative",
"scale": {
"domain":[234,1],
"scheme": "oranges"
}
},
"tooltip":[
{"field":"properties.name", "title":"Country"},
{"field":"Rank","type":"quantitative","title":"Number of Crypto Owners","format":".2f"}
]
},
"config": {"mark": {"invalid": null}
}
}
Your lookup was failing. You need a lower case "c" on country.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title": {
"text": "Crypto Ownership Worldwide",
"subtitle": "Source: FILL",
"anchor": "start"
},
"width": 500,
"height": 400,
"data": {
"url": "https://raw.githubusercontent.com/tomiwav/tomiwav.github.io/main/custom.geo%20(3).json",
"format": {"property": "features"}
},
"projection": {"type": "mercator"},
"transform": [
{
"lookup": "properties.name",
"from": {
"key": "country",
"fields": ["Rank"],
"data": {
"url": "https://raw.githubusercontent.com/tomiwav/tomiwav.github.io/main/datarank.csv",
"format": {"type": "csv"}
} }
}
],
"mark": {
"type": "geoshape",
"fill": "lightgray",
"stroke": "black",
"strokeWidth": 0.5
},
"encoding": {
"color": {
"field": "Rank",
"type": "quantitative",
"scale": {"domain": [234, 1], "scheme": "oranges"}
},
"tooltip": [
{"field": "properties.name", "title": "Country"},
{
"field": "Rank",
"type": "quantitative",
"title": "Number of Crypto Owners",
"format": ".2f"
}
]
},
"config": {"mark": {"invalid": null}}
}

What is the correct way to integrate audio & visual response using Alexa APL?

I have an Alexa audio and visual response that is returned on the first launch of an Alexa App. I use a transformer to embed the APLA document. Up until recently this was working.
This is the APL document:
{
"type": "APL",
"version": "2022.1",
"license": "Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0\nLicensed under the Amazon Software License http://aws.amazon.com/asl/",
"theme": "dark",
"import": [
{
"name": "alexa-layouts",
"version": "1.5.0"
}
],
"onMount": [
{
"type": "SpeakItem",
"componentId": "initialAPLAcomponent"
}
],
"resources": [
{
"description": "Default resource definitions for Video template",
"dimensions": {
"videoHeight": "55%",
"videoPaddingTop": "80dp",
"videoWidth": "70vw",
"videoControlPaddingBottom": "0dp",
"videoSliderPaddingBottom": "80dp"
}
},
{
"when": "${#viewportProfile == #hubLandscapeLarge}",
"dimensions": {
"videoHeight": "60%",
"videoPaddingTop": "110dp",
"videoControlPaddingBottom": "10dp",
"videoSliderPaddingBottom": "90dp"
}
},
{
"when": "${#viewportProfile == #hubLandscapeSmall || #viewportProfile == #hubRoundSmall}",
"dimensions": {
"videoHeight": "50%",
"videoPaddingTop": "70dp",
"videoControlPaddingBottom": "15dp"
}
}
],
"commands": {
"ToggleVideoOverlay": {
"parameters": [
"componentId",
"show"
],
"commands": [
{
"type": "Sequential",
"commands": [
{
"when": "${show}",
"type": "SetValue",
"componentId": "${componentId}",
"property": "display",
"value": "normal"
},
{
"type": "AnimateItem",
"easing": "ease-in-out",
"duration": 1000,
"componentId": "${componentId}",
"value": [
{
"property": "opacity",
"from": "${show ? 0 : 0.5}",
"to": "${show ? 0.5 : 0}"
}
]
},
{
"when": "${!show}",
"type": "SetValue",
"componentId": "${componentId}",
"property": "display",
"value": "none"
}
]
}
]
},
"ToggleVideoControls": {
"parameters": [
"componentId",
"direction",
"show"
],
"commands": [
{
"type": "Sequential",
"commands": [
{
"type": "AnimateItem",
"easing": "ease-in-out",
"duration": 1000,
"componentId": "${componentId}",
"value": [
{
"property": "opacity",
"from": "${show ? 0 : 1}",
"to": "${show ? 1 : 0}"
},
{
"property": "transform",
"from": [
{
"translateY": "${!show ? 0 : (direction == 'down' ? -50 : 50)}"
}
],
"to": [
{
"translateY": "${show ? 0 : (direction == 'down' ? 50 : -50)}"
}
]
}
]
},
{
"type": "SetValue",
"property": "videoControlsDisplay",
"value": "${show ? true : false}"
}
]
}
]
}
},
"layouts": {
"VideoPlayer": {
"parameters": [
{
"name": "backgroundImageSource",
"description": "URL for the background image source in fullscreen.",
"type": "string"
},
{
"name": "displayFullscreen",
"description": "Select to display video in fullscreen. Video controls will be displayed on tap.",
"type": "boolean",
"default": false
},
{
"name": "headerTitle",
"description": "Title text to render in the header.",
"type": "string"
},
{
"name": "headerSubtitle",
"description": "Subtitle Text to render in the header.",
"type": "string"
},
{
"name": "headerAttributionImage",
"description": "URL for attribution image or logo source (PNG/vector).",
"type": "string"
},
{
"name": "videoControlType",
"description": "The type of video control to use. Default is skip (foward and backwards).",
"type": "string",
"default": "skip"
},
{
"name": "videoSources",
"description": "Video single source or an array of sources. Videos will be in a playlist if multiple sources are provided.",
"type": "any"
},
{
"name": "sliderType",
"description": "Determinate for full control of the slider with transport control. Indeterminate is an ambient progress bar with animation.",
"type": "string",
"default": "determinate"
},
{
"name": "autoplay",
"type": "boolean",
"default": true,
"description": "Determines the starting state of the play/pause icon. This should match the autoplay state of the media playing component. Defaults to false. "
}
],
"item": {
"type": "Container",
"height": "100vh",
"width": "100vw",
"bind": [
{
"name": "sliderThumbPosition",
"type": "number",
"value": 0
},
{
"name": "sliderActive",
"type": "boolean",
"value": false
},
{
"name": "videoProgressValue",
"type": "number",
"value": 0
},
{
"name": "videoTotalValue",
"type": "number",
"value": 0
},
{
"name": "videoControlsDisplay",
"type": "boolean",
"value": false
}
],
"handleTick": [
{
"when": "${!sliderActive && displayFullscreen && videoControlsDisplay}",
"minimumDelay": 5000,
"description": "For video fullscreen view, hide video controls after 5 seconds of inactivity",
"commands": [
{
"type": "Parallel",
"sequencer": "ToggleVideoControlsSequencer",
"commands": [
{
"type": "ToggleVideoOverlay",
"componentId": "videoOverlay",
"show": false
},
{
"type": "ToggleVideoControls",
"componentId": "videoHeader",
"direction": "up",
"show": false
},
{
"type": "ToggleVideoControls",
"componentId": "videoControls",
"direction": "down",
"show": false
}
]
}
]
}
],
"items": [
{
"type": "AlexaBackground",
"id": "AlexaBackground",
"backgroundColor": "${backgroundColor}",
"backgroundImageSource": "${backgroundImageSource}"
},
{
"description": "Video container",
"type": "Container",
"height": "100%",
"width": "100%",
"position": "absolute",
"item": {
"type": "TouchWrapper",
"height": "100%",
"width": "100%",
"description": "Outer touch wrapper that brings up the controls",
"onPress": [
{
"when": "${displayFullscreen}",
"type": "Parallel",
"sequencer": "ToggleVideoControlsSequencer",
"commands": [
{
"type": "ToggleVideoOverlay",
"componentId": "videoOverlay",
"show": true
},
{
"type": "ToggleVideoControls",
"componentId": "videoHeader",
"direction": "down",
"show": true
},
{
"type": "ToggleVideoControls",
"componentId": "videoControls",
"direction": "up",
"show": true
}
]
}
],
"item": {
"type": "Container",
"height": "100%",
"width": "100%",
"alignItems": "center",
"item": {
"type": "Video",
"height": "${displayFullscreen ? '100%' : #videoHeight}",
"width": "${displayFullscreen ? '100%' : #videoWidth}",
"scale": "best-fill",
"autoplay": true,
"audioTrack": "foreground",
"id": "videoPlayerId",
"source": "${videoSources}",
"position": "absolute",
"top": "${displayFullscreen ? '0' : #videoPaddingTop}",
"onPlay": [
{
"type": "SetValue",
"property": "videoTotalValue",
"value": "${event.duration}"
},
{
"type": "SpeakItem",
"componentId": "initialAPLAcomponent"
}
],
"onTrackUpdate": [
{
"type": "SetValue",
"property": "videoTotalValue",
"value": "${event.duration}"
}
],
"onTimeUpdate": [
{
"type": "SetValue",
"property": "videoProgressValue",
"value": "${event.currentTime}"
},
{
"type": "SetValue",
"componentId": "slider",
"property": "progressValue",
"value": "${videoProgressValue}"
},
{
"type": "SetValue",
"property": "videoTotalValue",
"value": "${event.duration}"
}
],
"onTrackReady": [
{
"type": "SetValue",
"property": "videoTotalValue",
"value": "${event.duration}"
}
],
"onTrackFail": [
{
"type": "SetValue",
"property": "videoTotalValue",
"value": "0"
}
]
}
}
}
},
{
"description": "Header, slider, and controls container",
"type": "Container",
"height": "100%",
"width": "100%",
"items": [
{
"description": "Oveylay background for Video Controls",
"when": "${displayFullscreen}",
"type": "Frame",
"id": "videoOverlay",
"height": "100%",
"width": "100%",
"backgroundColor": "${viewport.theme == 'light' ? '#colorWhite' : '#colorBlack'}",
"position": "absolute",
"display": "none",
"opacity": 0
},
{
"when": "${#viewportProfileCategory != #hubRound}",
"type": "AlexaHeader",
"id": "videoHeader",
"opacity": "${displayFullscreen ? 0 : 1}",
"layoutDirection": "${environment.layoutDirection}",
"headerAttributionImage": "${headerAttributionImage}",
"headerTitle": "${headerTitle} ",
"headerSubtitle": "${headerSubtitle} ",
"headerAttributionPrimacy": true,
"width": "100%",
"theme": "${viewport.theme}"
},
{
"description": "Slider and controls",
"type": "Container",
"id": "videoControls",
"opacity": "${displayFullscreen ? 0 : 1}",
"width": "100%",
"position": "absolute",
"bottom": 0,
"items": [
{
"when": "${sliderType != 'indeterminate'}",
"type": "Container",
"alignItems": "center",
"item": [
{
"type": "AlexaSlider",
"id": "slider",
"progressValue": "${videoProgressValue}",
"totalValue": "${videoTotalValue}",
"positionPropertyName": "sliderThumbPosition",
"metadataDisplayed": true,
"metadataPosition": "above_right",
"width": "${#videoWidth + 5vw}",
"paddingBottom": "#videoSliderPaddingBottom",
"theme": "${viewport.theme}",
"onUpCommand": [
{
"type": "ControlMedia",
"componentId": "videoPlayerId",
"command": "seek",
"value": "${sliderThumbPosition - videoProgressValue}"
},
{
"delay": "1000",
"type": "SetValue",
"sequencer": "ToggleVideoControlsSequencer",
"property": "sliderActive",
"value": false
}
],
"onMoveCommand": [
{
"type": "SetValue",
"property": "sliderActive",
"value": true
}
],
"onDownCommand": [
{
"type": "SetValue",
"property": "sliderActive",
"value": true
}
]
},
{
"type": "AlexaTransportControls",
"mediaComponentId": "videoPlayerId",
"playPauseToggleButtonId": "playPauseToggleButtonId",
"primaryControlSize": "70dp",
"secondaryControls": "${videoControlType}",
"secondaryControlSize": "60dp",
"autoplay": true,
"position": "absolute",
"bottom": "#videoControlPaddingBottom",
"theme": "${viewport.theme}"
}
]
},
{
"when": "${sliderType == 'indeterminate'}",
"type": "Container",
"alignItems": "center",
"item": [
{
"type": "AlexaProgressBar",
"progressBarType": "indeterminate",
"width": "#videoWidth",
"paddingBottom": "#videoSliderPaddingBottom",
"theme": "${viewport.theme}"
}
]
}
]
}
]
}
]
}
},
"AudioTransform": {
"parameters": [
{
"name": "audioSource",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"id": "initialAPLAcomponent",
"speech": "${audioSource}"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "VideoPlayer",
"backgroundImageSource": "${payload.videoPlayerTemplateData.properties.backgroundImage}",
"displayFullscreen": "${payload.videoPlayerTemplateData.properties.displayFullscreen}",
"headerAttributionImage": "${payload.videoPlayerTemplateData.properties.logoUrl}",
"headerTitle": "${payload.videoPlayerTemplateData.properties.headerTitle}",
"headerSubtitle": "${payload.videoPlayerTemplateData.properties.headerSubtitle}",
"videoControlType": "${payload.videoPlayerTemplateData.properties.videoControlType}",
"videoSources": "${payload.videoPlayerTemplateData.properties.videoSources}",
"sliderType": "${payload.videoPlayerTemplateData.properties.sliderType}"
},
{
"type": "AudioTransform",
"audioSource": "${payload.videoPlayerTemplateData.properties.outputAPLA.url}"
}
]
}
}
This is the datasource:
{
"videoPlayerTemplateData": {
"type": "object",
"properties": {
"backgroundImage": "",
"displayFullscreen": true,
"headerTitle": "",
"headerSubtitle": "",
"logoUrl": "https://my.png",
"videoControlType": "jump10",
"videoSources": [
"https://my.mp4"
],
"sliderType": "determinate"
},
"transformers": [
{
"template": "intialAPLA",
"outputName": "outputAPLA",
"transformer": "aplAudioToSpeech"
}
]
}
}
and this is the APLA source:
{
"intialAPLA": {
"type": "APLA",
"version": "0.91",
"mainTemplate": {
"parameters": [
"payload"
],
"item": [
{
"type": "Mixer",
"items": [
{
"type": "Sequencer",
"items": [
{
"type": "Audio",
"description": "sound from bank",
"source": "my.sound"
},
{
"type": "Speech",
"content": "myspeech "
}
]
},
{
"type": "Audio",
"source": "https://my.mp3",
"duration": "trimToParent",
"filter": [
{
"type": "Volume",
"amount": "50%"
},
{
"type": "FadeOut",
"duration": 2000
}
]
}
]
}
]
}
}
}
If I remove the video item from the main template the audio plays, so I know this is not an issue with the transformer. I've tried setting the speech attrbute of the video, in layouts, to be the transformer binding, and playing that onMount, but that doesn't work either.
It seems I can only play video or the audio, not both. This worked previously so I'm not sure what's changed.
Are you able to see why I can't return the video with the audio embedded?

Alexa custom skill: getting FallbackIntent instead of validation prompt

I have an interaction model with a GetMenuIntent which I can invoke with "what's for {meal}". meal is a MealType custom slot with allowed values of "breakfast" and "lunch". I added validation on the meal slot in my GetMenuIntent to only allow those values defined in the slot type and it works great for those configured values.
However, after saving and building my model, when I put "what's for dinner" into the Utterance Profiler or the interactive tester, It ended up calling my FallbackIntent instead of reprompting for a correct value.
I feel like what I'm trying to do isn't really much different than Amazon's own example here.
Here's "whats for lunch" working correctly:
And here's "whats for dinner" ignoring my GetMenuIntent and calling FallbackIntent instead:
Here's my interaction model:
{
"interactionModel": {
"languageModel": {
"invocationName": "school menus",
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
},
{
"name": "GetMenuIntent",
"slots": [
{
"name": "meal",
"type": "Meal"
},
{
"name": "date",
"type": "AMAZON.DATE"
}
],
"samples": [
"whats for {meal} {date}",
"what will you have for {meal} {date}",
"what is on the menu for {meal} {date}",
"what are we having for {meal} {date}",
"what we're having for {meal} {date}"
]
},
{
"name": "AMAZON.FallbackIntent",
"samples": []
}
],
"types": [
{
"values": [
{
"name": {
"value": "lunch"
}
},
{
"name": {
"value": "breakfast"
}
}
],
"name": "Meal"
}
]
},
"dialog": {
"intents": [
{
"name": "GetMenuIntent",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "meal",
"type": "Meal",
"elicitationRequired": false,
"confirmationRequired": false,
"prompts": {},
"validations": [
{
"type": "hasEntityResolutionMatch",
"prompt": "Slot.Validation.806855880612.19281662909.602239253259"
}
]
},
{
"name": "date",
"type": "AMAZON.DATE",
"elicitationRequired": false,
"confirmationRequired": false,
"prompts": {}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Slot.Validation.806855880612.19281662909.602239253259",
"variations": [
{
"type": "PlainText",
"value": "Hmm, I don't know about that menu type. Please try again."
}
]
}
]
},
"version": "48"
}
Since this is 6 months old I assume you figured out by now that your interaction model only includes Lunch and Breakfast.

APL skill without lambda functions

I am creating Alexa echo show skill, I have created one sample Alexa skill without lambda function that hits myserver api and I return response in Alexa accepted format like below:
{
"version": "1.0",
"sessionAttributes": {},
"response": {
"outputSpeech": {
"type": "PlainText",
"text": "My output speech"
},
"card": {
"type": "Simple",
"title": "hELLO",
"content": "Meetings"
},
"reprompt": {
"outputSpeech": {
"type": "PlainText",
"text": "Can I help you with anything else?"
}
},
"shouldEndSession": false
}
}
Till now my skill working fine, But now I want to show a template over the echo show that is possible with APL(Alexa Programming Language).
I am not getting APL examples without lambda function, I have tried to add some APL response json from the example that i got and put into above response json that is not working.
I am confused with APL, Should i just need to add some attribute only in the above response or need to use sdk at my server that is running with PHP whose sdk i did not find at the portal.
Please help me
If you want to send an APL document, you have to send a directive to the JSON
{
"body": {
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Hello world, change me</speak>"
},
"directives": [
{
"type": "Alexa.Presentation.APL.RenderDocument",
"token": "TemplateTypescript",
"document": {
"type": "APL",
"version": "1.7",
"license": "Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0\nLicensed under the Amazon Software License http://aws.amazon.com/asl/",
"theme": "dark",
"import": [
{
"name": "alexa-layouts",
"version": "1.4.0"
}
],
"resources": [
{
"description": "Default dimensions, numbers and strings for the AlexaHeadline.",
"dimensions": {
"primaryTextMaxWidth": "100%",
"secondaryTextMaxWidth": "100%",
"secondaryTextTopPadding": "#spacingXSmall",
"contentPaddingLeft": "#marginHorizontal"
},
"numbers": {
"headlinePrimaryTextMaxLines": 2
},
"strings": {
"textComponentAlign": "center"
}
},
{
"description": "Dimensions for the AlexaHeadline - hubLandscapeLarge.",
"when": "${#viewportProfile == #hubLandscapeLarge}",
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions for the AlexaHeadline - hubRound.",
"when": "${#viewportProfileCategory == #hubRound}",
"dimensions": {
"secondaryTextTopPadding": "#spacing3XSmall"
}
},
{
"description": "Dimensions for the AlexaHeadline - tvLandscapeOverlay/tvLandscapeXLarge.",
"when": "${#viewportProfile == #tvLandscapeXLarge || #viewportProfile == #tvLandscapeOverlay}",
"dimensions": {
"primaryTextMaxWidth": "560dp",
"secondaryTextMaxWidth": "560dp",
"secondaryTextTopPadding": "#spacing3XSmall"
}
},
{
"description": "Dimensions for the AlexaHeadline - tvLandscapeXLarge.",
"when": "${#viewportProfile == #tvLandscapeXLarge}",
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - tvPortraitOverlay.",
"when": "${#viewportProfile == #tvPortraitOverlay}",
"dimensions": {
"primaryTextMaxWidth": "220dp",
"secondaryTextMaxWidth": "220dp",
"contentPaddingLeft": "#spacing2XLarge"
},
"strings": {
"textComponentAlign": "left"
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - mobileSmall portrait.",
"when": "${#viewportProfile == #mobileSmall && #viewportOrientation == #viewportOrientationPortrait}",
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - mobileMedium.",
"when": "${#viewportProfile == #mobileMedium}",
"dimensions": {
"primaryTextMaxWidth": "758dp"
},
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - mobileLarge.",
"when": "${#viewportProfile == #mobileLarge}",
"dimensions": {
"primaryTextMaxWidth": "1025dp"
},
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - hubPortraitMedium.",
"when": "${#viewportProfile == #hubPortraitMedium}",
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
},
{
"description": "Dimensions, numbers and strings for the AlexaHeadline - hubLandscapeXLarge.",
"when": "${#viewportProfile == #hubLandscapeXLarge}",
"dimensions": {
"primaryTextMaxWidth": "1440dp"
},
"numbers": {
"headlinePrimaryTextMaxLines": 4
}
}
],
"styles": {
"primaryTextLight": {
"extends": "textStyleDisplay4",
"values": [
{
"color": "#colorTextReversed"
}
]
},
"secondaryTextLight": {
"extends": "textStyleCallout",
"values": [
{
"color": "#colorTextReversed"
}
]
}
},
"layouts": {
"AlexaHeadline": {
"parameters": [
{
"name": "theme",
"description": "Colors will be switched depending on the specified theme (light/dark). Default to dark theme",
"type": "string",
"default": "dark"
},
{
"name": "primaryText",
"description": "Primary message",
"type": "string"
},
{
"name": "secondaryText",
"description": "secondary message",
"type": "string"
},
{
"name": "headerAttributionOpacity",
"type": "number",
"default": "${#viewportProfileCategory == #hubRound ? 1 : #opacitySecondary}"
},
{
"name": "headerTitle",
"description": "Primary text to render in header.",
"type": "string"
},
{
"name": "headerSubtitle",
"description": "Secondary text to render in header.",
"type": "string"
},
{
"name": "headerAttributionText",
"description": "Attribution text to render in header. Only shown when no headerAttributionImage is provided, and when headerAttributionPrimacy is true, or on a device that shows Title/Subtitle and Attribution.",
"type": "string"
},
{
"name": "headerAttributionImage",
"description": "URL for attribution image source. Only shown when headerAttributionPrimacy is true, or on a device that shows Title/Subtitle and Attribution.",
"type": "string"
},
{
"name": "headerAttributionPrimacy",
"description": "On devices that can only display one element due to screen size, Attribution is prioritized. Setting False displays Title/Subtitle. Defaults to true.",
"type": "boolean",
"default": true
},
{
"name": "headerDivider",
"description": "Toggle to display the divider that appears at the bottom of header to help separate it from the content below. Default to false",
"type": "boolean",
"default": false
},
{
"name": "headerBackButton",
"description": "Toggle to display back button in header. Defaults to false.",
"type": "boolean",
"default": false
},
{
"name": "headerBackButtonAccessibilityLabel",
"description": "An accessibility label to describe the back button to customers who use a screen reader.",
"type": "string"
},
{
"name": "headerBackButtonCommand",
"description": "Command that is issued when back button is pressed.",
"type": "any",
"default": {
"type": "SendEvent",
"arguments": ["goBack"]
}
},
{
"name": "headerBackgroundColor",
"description": "Optional color value to use as background color for Header. Defaults to transparent.",
"type": "color",
"default": "transparent"
},
{
"name": "backgroundColor",
"description": "Color value to use as background color for layout.",
"type": "color"
},
{
"name": "backgroundImageSource",
"description": "URL for background image source.",
"type": "string"
},
{
"name": "backgroundVideoSource",
"description": "URL for background video source.",
"type": "any"
},
{
"name": "backgroundScale",
"description": "Image/video scale to apply to background image/video. Defaults to best-fill.",
"type": "string",
"default": "best-fill"
},
{
"name": "backgroundAlign",
"description": "Image/video alignment to apply to background image/video. Defaults to center.",
"type": "string",
"align": "center"
},
{
"name": "backgroundBlur",
"description": "Toggle to apply background blur. Defaults to false.",
"type": "boolean",
"default": false
},
{
"name": "backgroundColorOverlay",
"description": "Toggle to apply overlay scrim to background image/video. Defaults to false.",
"type": "boolean",
"default": false
},
{
"name": "backgroundOverlayGradient",
"description": "Toggle to apply gradient to background image/video. Defaults to false.",
"type": "boolean",
"default": false
},
{
"name": "backgroundVideoAutoPlay",
"description": "Toggle to autoplay background video(s). Defaults to false.",
"type": "boolean",
"default": false
},
{
"name": "backgroundVideoAudioTrack",
"description": "Audio track to play on. Defaults to foreground. EM can select foreground | background | none.",
"type": "string",
"default": "foreground"
},
{
"name": "footerHintText",
"type": "string",
"description": "Hint text to display in Footer."
},
{
"name": "entities",
"description": "Array of entity data bind to this layout",
"type": "any"
},
{
"name": "layoutDirection",
"description": "The layoutDirection of AlexaHeadline. It can be LTR or RTL. By default, it uses environment layoutDirection.",
"type": "string",
"default": "${environment.layoutDirection}"
},
{
"name": "lang",
"description": "The lang property of AlexaHeadline. Set the lang property to a BCP-47 string (e.g., en-US). By default, it uses environment lang.",
"type": "string",
"default": "${environment.lang}"
}
],
"items": [
{
"type": "Container",
"layoutDirection": "${layoutDirection}",
"height": "100vh",
"entities": "${entities}",
"items": [
{
"type": "AlexaBackground",
"backgroundColor": "${backgroundColor}",
"backgroundImageSource": "${backgroundImageSource}",
"backgroundVideoSource": "${backgroundVideoSource}",
"backgroundScale": "${backgroundScale}",
"backgroundAlign": "${backgroundAlign}",
"backgroundBlur": "${backgroundBlur}",
"colorOverlay": "${backgroundColorOverlay}",
"overlayGradient": "${backgroundOverlayGradient}",
"videoAutoPlay": "${backgroundVideoAutoPlay}",
"videoAudioTrack": "${backgroundVideoAudioTrack}"
},
{
"type": "Container",
"height": "100vh",
"width": "100vw",
"position": "absolute",
"items": [
{
"type": "Container",
"grow": 1,
"justifyContent": "center",
"paddingLeft": "#contentPaddingLeft",
"paddingRight": "#marginHorizontal",
"alignItems": "center",
"items": [
{
"when": "${primaryText && primaryText != ''}",
"type": "Text",
"style": "${theme == 'light' ? 'primaryTextLight' : 'textStyleDisplay4'}",
"text": "${primaryText}",
"opacity": 1,
"textAlign": "#textComponentAlign",
"maxWidth": "#primaryTextMaxWidth",
"maxLines": "#headlinePrimaryTextMaxLines"
},
{
"when": "${secondaryText && secondaryText != ''}",
"type": "Text",
"style": "${theme == 'light' ? 'secondaryTextLight' : 'textStyleCallout'}",
"text": "${secondaryText}",
"maxLines": 1,
"opacity": "#opacitySecondary",
"textAlign": "#textComponentAlign",
"maxWidth": "#secondaryTextMaxWidth",
"paddingTop": "#secondaryTextTopPadding"
}
]
},
{
"type": "AlexaHeader",
"theme": "${theme}",
"headerTitle": "${headerTitle}",
"layoutDirection": "${layoutDirection}",
"headerSubtitle": "${#viewportProfile != #tvLandscapeOverlay ? headerSubtitle : ''}",
"headerAttributionText": "${headerAttributionText}",
"headerAttributionImage": "${headerAttributionImage}",
"headerAttributionPrimacy": "${headerAttributionPrimacy}",
"headerDivider": "${headerDivider}",
"headerBackButton": "${headerBackButton}",
"headerBackButtonAccessibilityLabel": "${headerBackButtonAccessibilityLabel}",
"headerBackButtonCommand": "${headerBackButtonCommand}",
"headerBackgroundColor": "${headerBackgroundColor}",
"headerAttributionOpacity": "${headerAttributionOpacity}",
"position": "absolute",
"width": "100%",
"top": "0"
},
{
"when": "${#viewportProfileCategory != #hubRound && #viewportProfile != #tvLandscapeOverlay && footerHintText}",
"type": "AlexaFooter",
"hintText": "${footerHintText}",
"theme": "${theme}",
"lang": "${lang}",
"position": "absolute",
"width": "100%",
"bottom": "0"
}
]
}
]
}
]
}
},
"mainTemplate": {
"parameters": ["payload"],
"item": [
{
"type": "AlexaHeadline",
"id": "PlantHeadline",
"primaryText": "${payload.headlineTemplateData.properties.textContent.primaryText.text}",
"headerBackButton": false,
"headerAttributionImage": "${payload.headlineTemplateData.properties.logoUrl}",
"headerAttributionPrimacy": true,
"footerHintText": "${payload.headlineTemplateData.properties.hintText}",
"backgroundImageSource": "${payload.headlineTemplateData.properties.backgroundImage.sources[0].url}",
"backgroundColorOverlay": false,
"speech": "${payload.headlineTemplateData.properties.welcomeSpeech}",
"theme": "light"
}
]
},
"onMount": [
{
"type": "SpeakItem",
"componentId": "PlantHeadline"
}
]
},
"datasources": {
"headlineTemplateData": {
"type": "object",
"objectId": "headlineSample",
"properties": {
"backgroundImage": {
"sources": [
{
"url": "https://d2o906d8ln7ui1.cloudfront.net/images/templates_v3/headline/HeadlineBackground_Light.png",
"size": "large"
}
]
},
"textContent": {
"primaryText": {
"type": "PlainText",
"text": "Welcome to Template Typescript"
}
},
"logoUrl": "",
"hintText": ""
}
}
},
"timeoutType": "SHORT"
}
],
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Hello world, change me</speak>"
}
},
"shouldEndSession": false,
"type": "_DEFAULT_RESPONSE"
},
"sessionAttributes": {},
"userAgent": "ask-node/2.11.0 Node/v12.22.4"
}
}
You can use https://apl.ninja/ or within the developer console to help you get started quickly.

An error occurred while requesting the visualisation's config resource

I got an error "An error occurred while requesting the visualisation's config resource" while trying to request my custom visualisation. All files have been made public.
manifest.json
{
"name": "Custom Vis",
"description": "By Sorrow",
"devMode": true,
"components": [{
"id": "Custom Vis",
"name": "Custom Vis",
"iconUrl": "https://raw.githubusercontent.com/googledatastudio/community-visualizations/master/docs/codelab/img/bar_chart.png",
"description": "Custom Vis",
"resource": {
"js": "custom-vis/final.js",
"config": "custom-vis/config.json",
"css": "custom-vis/style.css"
}
}]
}
config.json
{
"data": [
{
"id": "concepts",
"label": "Concepts",
"elements": [
{
"id": "barDimension",
"label": "Dimension",
"type": "DIMENSION",
"options": {
"min": 1,
"max": 1
}
},
{
"id": "barMetric",
"label": "Metric",
"type": "METRIC",
"options": {
"min": 1,
"max": 1
}
}
]
}
],
"style": [
{
"id": "color",
"label": "Colors",
"elements": [
{
"type": "FONT_COLOR",
"id": "barColor",
"label": "Bar Color",
"defaultValue": "black"
}
]
}
]
}
Can someone tell me why it doesn't work?
You need to create a folder on the Google Cloud where your files will go:
Then add it like here:
"resource": {
"js": "gs://yourname/index.js",
"config": "gs://yourname/index.json",
"css": "gs://yourname/index.css"
}
PS: watch a video here https://developers.google.com/datastudio/visualization/local-dev
That will save you a lot of time on development.
I stumbled upon the same issue.
Resources were provided in the default tutorial in a form of
"resource": {
"js": "MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.js",
"config": "MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.json",
"css": "MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.css"
}
What was not clear is that they actually need to include gs:// in the path. Would be clearer if they explicitly mentioned it like so:
"resource": {
"js": "gs://MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.js",
"config": "gs://MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.json",
"css": "gs://MY_GOOGLE_CLOUD_STORAGE_BUCKET/myViz.css"
}
It must work this way.

Resources