qnabot-on-aws
qnabot-on-aws copied to clipboard
Feature Request : Content Designer | ResponseCard titles optional rather than required?
Given that aws-lex-web-ui doesn't require responseCard titles, is there a reason they are required in the Content Designer? Reason I ask is being able to have a single message bubble with a list of button options is handy. (Appreciate that config.ui.shouldDisplayResponseCardTitle
could be set to false, but being a global setting doesn't give so much granular control). Thoughts?
The Lex runtime in past versions required title as property of a GenericAttachment. Returning a ResponseCard without title caused a runtime error. Hence the Content Designer required this attribute when defining a ResponseCard for an answer. Current Lex documentation indicates title is optional. It is worth a test changing title to be an optional field. The file templates/master/elasticsearch/schema/qna.js defines the values required when storing response cards as part of an answer. This also drives the validation performed by the content designer ui. Change the description field on line 67 so that 'Required - max length of 80...' becomes 'Optional - max length of 80 ...' and then remove title from the array of required fields on line 109. Rebuild deploying to a new QnABot stack. I've not found a way to change an existing index in elasticsearch to incorporate updates to the definition. If Lex Web Ui api now treats title as optional within a returned ResponseCard/GenericAttachment I think this might work.
Thanks @bobpskier After trying that, I've hit the following issues:
-
stack update
doesn't work, so currently have to make a new stack. Assume this is due to ElasticSearch Indexes/mappings not updated? (manageable but be good to find a solution) - cards with buttons only (no title/image), are not displayed due to
card.send = false
. I'm not sure where the 'send' prop is being set? However I've got it working by changinglambda/fulfillment/lib/middleware/lex.js assemble()
. Note the addition of _.pickBy() predicate function so that title with an empty strings don't get removed
(v, k) => {
if (k === "title") return true
return v != null && v !== ""
})
Also note the removal of the responseCard
check && (_.get(response.card,"imageUrl","").trim()
who's effect I'm not entirely sure about?
exports.assemble=function(request,response){
// Check standard buttons prop
var filteredButtons = _.get(response.card,"buttons",[])
// If card title is empty, check results object for buttons (as they are not passed up to card object)
if (filteredButtons.length === 0) {
filteredButtons = _.get(response, "result.r.buttons", [])
}
// Remove buttons that don't have text & value properties
for (var i = filteredButtons.length - 1; i >= 0; --i){
if (!(filteredButtons[i].text && filteredButtons[i].value)){
filteredButtons.splice(i,1)
}
}
// If card title is empty but buttons are available, card.send needs changing from false to true
if (filteredButtons.length > 0) {
response.card.send = true
}
var out={
sessionAttributes:_.get(response,'session',{}),
dialogAction:_.pickBy({
type:"Close",
fulfillmentState:"Fulfilled",
message:{
contentType:response.type,
content:response.message
},
responseCard:isCard(response.card) ? {
version:"1",
contentType:"application/vnd.amazonaws.card.generic",
genericAttachments:[_.pickBy({
title:_.get(response,"card.title","Image"),
subTitle:_.get(response.card,'subTitle'),
imageUrl:response.card.imageUrl,
buttons: _.has(filteredButtons, [0]) ? filteredButtons : null
}, (v, k) => {
if (k === "title") return true
return v != null && v !== ""
})]
} : null
})
}
...
So it now seems to be working but bit more complicated than would have liked. thoughts?
This has been simplified by amending lambda/proxy-es/lib/query.js get_answer(req, res)
from
var card=_.get(res,"result.r.title") ? res.result.r : null ...
to
var card = _.get(res,"result.r", {})
const cleanedCard = _.pickBy(card , (v, k) => { return v != null && v !== "" })
if(!_.isEmpty(cleanedCard)){
res.card.send=true
res.card.title=_.get(card,'title')
res.card.subTitle=_.get(card,'subTitle')
res.card.imageUrl=_.get(card,'imageUrl')
res.card.buttons=_.get(card,'buttons')
}
This should give a card if any property (title, subtitle, imageUrl, buttons) has a truthy value