How to make Alexa countdown in seconds - amazon-web-services

I want to be able to have alexa (audibly) countdown 15 seconds in my skill. I know I can just <break time="15s" /> in SSML. But that isn't audible. I also know I can just do:
15<break time="1s" />
14<break time="1s" />
or better yet (to account for the time it takes to say the number)
15<break time="0.85s" />
14<break time="0.85s" />
But that's going to be a ton of repeated code if I do this many times over. So I'm probably going to write a function that takes in a number and a number of seconds, and produces an SSML countdown in that interval.
Before I do that, however, I was wondering if there's a proper, built-in way of doing this? Or if someone has a function they've already built for this? Thanks!!!

function buildCountdown(seconds, break) {
var countdown = "";
for (var i = seconds; i > 0; i--) {
var count = i.toString + "<break time='" + break.toString() + "s' />\n";
countdown.concat(count);
}
return countdown;
}
And then just provide the outputSpeech property:
"outputSpeech": {
"type": "SSML",
"ssml": buildCountdown(15, 0.85)
}
I'm not sure about any ASK built-ins for building SSML, but writing functions that generate markup is pretty common when working with Javascript frameworks, so it seems appropriate here.

I ended up with the following function (with the help of someone on the Alexa slack):
function countDown(numSeconds, breakTime) {
return Array.apply(null, {length: numSeconds})
.map((n, i) => {return `<say-as interpret-as="cardinal">${numSeconds-i}</say-as>` })
.join(`<break time="${breakTime ? breakTime : 0.85}s" />`) + `<break time="${breakTime ? breakTime : 0.85}s" />`;
}

Related

ember-resources trackedTask with cached value

I've recently started looking into the nice ember-resources library because I came to the point my data fetching routine required some reactivity. Since we tend to use the ember-concurrency tasks in our project I wanted to follow the common pattern and I was happy to realise that ember-resources support ember-concurrency tasks out of the box.
Now i've got a dependant tracked property which is basically a timer and it's being updated every minute. What I want to do is to be able to run my task say every two minutes. The question is how to achieve this?
Here goes my pseudo-code:
// that's my component
#restartableTask
*fetchFeed() {
yield timeout(1);
return yield this.store.queryRecord('item', {...});
}
get currentTime() {
// this one returns a tracked variable which is updated every minute
}
feedResource = trackedTask(this, this.fetchFeed, () => [this.currentTime]);
// this is the corresponding hbs
{{#if this.feedResource.isRunning}}
<LoadingSpinner />
{{else}}
{{this.feedResource.value}}
{{/if}}
what I want to do is basically
get every2Minutes() {
return Math.trunc(this.currentTime.second() / 2)
}
feedResource = trackedTask(this, this.fetchFeed, () => [this.every2Minutes]);
but it's still run on every minute. I've tried using the #cached attribute and a custom cache solution but it didn't help - despite that the cache gave me the correct value, i.e. only even ones, the task was still fired every minute. Can I tell the trackedTask to not fire if the dependency wasn't changed?
👋 Hi, I'm the author of ember-resources! glad you're having fun with the library!
this one returns a tracked variable which is updated every minute
While this is clever, if the variable isn't used in the task, it "feels weird". I don't have better words for this. 🙃
But, to directly answer your question, I'd define currentTime like this:
const ClockEveryOtherMinute = resource(({ on }) => {
let time = cell(new Date());
let interval = setInterval(
() => time.current = new Date(),
2 * 60 * 1000, // 2 minutes
);
on.cleanup(() => clearInterval(interval));
return () => time.current;
});
class Foo {
// `#use` is required when a resource returns a single value
#use currentTime = ClockEveryOtherMinute;
feedResource = trackedTask(this, this.fetchFeed, () => [this.currentTime]);
// ...etc
}
Here is an interactive demo of something very similar
However, I think there may be a more ergonomic way --
In a scenario where you want recurring behavior, there are a couple approaches you could take:
invoke the task once and use a while loop to do something periodically
use a constructor/destructor combo with setInterval
These are somewhat separate from the trackedTask helper utility, as the trackedTask helper utility "only" does lazy invocation of the .perform method on a task when a property on the TaskInstance would be accessed. So... I'm not actually sure if your getter's return would be updated if the task is re-performed every couple minutes manually. I'm maybe.. 60% sure it would? (this is something I don't have tests for).
Anywho back to the options:
invoke the task once
class Foo extends Component {
#tracked items;
#task
*fetchFeed() {
yield timeout(1);
while(true) {
this.items = yield this.store.queryRecord('item', {...});
yield timeout(1000 * 60 * 2); // 2 minutes
}
}
get hasItems() {
return Boolean(this.items?.length);
}
}
// this is the corresponding hbs
{{#if this.hasItems}}
{{this.items}}
{{else}}
<LoadingSpinner />
{{/if}}
using setInterval
import { registerDestructor } from '#ember/destroyable';
class Foo extends Component {
#tracked items;
constructor(owner, args) {
super(owner, args);
let interval = setInterval(() => {
if (isDestroyed(this) || isDestroying(this)) return;
this.fetchFeed.perform();
}, 2 * 60 * 1000);
registerDestructor(this, () => {
clearTimeout(interval);
});
// initial perform
this.fetchFeed.perform();
}
#task
*fetchFeed() {
yield timeout(1);
return yield this.store.queryRecord('item', {...});
}
get hasItems() {
return Boolean(this.fetchFeed.lastSuccessful?.value?.length);
}
}
// this is the corresponding hbs
{{#if this.hasItems}}
{{this.fetchFeed.lastSuccessful.value}}
{{else}}
<LoadingSpinner />
{{/if}}
A "do something every 2 minutes API"
I'm 🤷‍♂️ on this approach, but for completeness, it's probably reasonable to know that it's possible (I'm going to hand-wave over the implementation, as that could be other stack-overflow questions):
const doEveryTwoMinutes = resourceFactory((callback) => {
// ...
return resource(({ on }) => {
// ...
});
});
class Foo extends Component {
#use feed = doEveryTwoMinutes(() => {
return this.fetchFeed.perform(); // returns a task
});
#task
*fetchFeed() {
yield timeout(1);
return yield this.store.queryRecord('item', {...});
}
get hasItems() {
return Boolean(this.feed.length);
}
}
// this is the corresponding hbs
{{#if this.hasItems}}
{{this.feed}}
{{else}}
<LoadingSpinner />
{{/if}}
(no trackedTask needed, we rely on the internal tracked-state of a TaskInstance)
Why do these approaches not need trackedTask?
because we have "events" that we know about that cause the task to be performed -- and ember-concurrency is really good at being "an event handler", of sorts -- whereas ember-resources is more about deriving data (maybe eventually), with cleanup.

SuiteScript 2.0 Map Reduce Script Complete Sample

I was hit SSS USAGE LIMIT EXCEEDED error in Netsuite.
I plan to change the search to use Map Reduce Script, however, I didn't found any complete example to call Map Reduce Script, like how to pass parameter to Map Reduce Script and get the resultset from it. Would you please show me how? Thanks in advance
the below show how to define the task to call Map Reduce Script
SuiteScript 2.0 UserEvent Script to Call Map Reduce
define(['N/record', 'N/log', 'N/Task'],
function (record, log, task) {
function setFieldInRecord (scriptContext) {
log.debug({
'title': 'TESTING',
'details': 'WE ARE IN THE FUNCTION!'
});
if (scriptContext.type === scriptContext.UserEventType.EDIT) {
var scriptTask = task.create({
taskType: task.TaskType.MAP_REDUCE
});
scriptTask.scriptId = 'customscript_id';
scriptTask.deploymentId = 'customdeploy_id';
var scriptTaskId = scriptTask.submit();
//How to pass parameter to getInputData?
//How to get the result?
}
}
return {
beforeSubmit: setFieldInRecord
};
}
);
Map/Reduce script type provides you with 4 entry point functions to load/process your data:
getInputData(inputContext)
map(mapContext)
reduce(reduceContext)
summarize(summaryContext)
Example:
function summarize(context) {
context.output.iterator().each(function(key, value) {
// your logic here
return true;
});
}
Take a look at this help center section, there are examples (only available with NetSuite account):
https://system.netsuite.com/app/help/helpcenter.nl?fid=section_4387799161.html

Koa middleware - generator concurrency testing

I've hit a bit of an interesting road block in my attempt at writing unit tests for some middleware as I can't seem to come up with a feasible means to fake two concurrent connections for a generator function which is a piece of koa middleware.
I have a constructor function that takes some setup options and returns a generator. This generator has access to some variables via closure which increment per request and decrement when the complete. Here is a subset of the code to give you an idea of what i'm trying to accomplish.
module.exports = function (options = {}) {
let connections = 0;
let {
max = 100
...
} = options;
return function *() {
connections++
...
if (connections > max) {
connections--;
// callback here
}
...
}
}
In simple terms I want to be able to keep track of multiple simultaneous "connections" in which I fire a callback when a max number of requests have been met. However, in my test i get back a single instance of this generator and can only call it once mimicking a single request, thus i can never meet the connections > max conditional
it("Should trigger callback when max connections reached", () => {
const gen = middleware({
max: 1,
onMax: function (current, max) {
this.maxReached = true;
}
}).call(context);
gen.next();
expect(context.maxReached).to.be.true;
});
Sometimes you just need a good night sleep to dream your answer. This was simply a matter of calling the same generator with two different contexts that represented two different requests and store a value to tests against on the latter. The counter would still increment because I never returned up the middleware chain (response) in order to decrement. It's more of a fake concurrency.
const middleware = limiter({
max: 1,
onMax: function (current, max) {
this.maxReached = true;
}
});
middleware.call(reqContext).next();
middleware.call(secondReqContext).next();
expect(secondReqContext.maxReached).to.be.true;

Map/reduce to get the count and latest date for each document grouped by key

A simple version of my document document is the following structure:
doc:
{
"date": "2014-04-16T17:13:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
}
I would like to group my document by key, to get the latest date and the number of documents for each key, something like
{ "Last": "2014-04-16T16:00:00", "Count": 10 }
My idea is to to do a map/reduce view and query setting group to true.
This is what I have so far tried. I get the exact count, but not the correct dates.
map
function (doc, meta) {
if(doc.type =="doc")
emit(doc.key, doc.date);
}
reduce
function(key, values, rereduce) {
var result = {
Last: 0,
Count: 0
};
if (rereduce) {
for (var i = 0; i < values.length; i++) {
result.Count += values[i].Count;
result.Last = values[i].Last;
}
} else {
result.Count = values.length;
result.Last = values[0]
}
return result;
}
You're not comparing dates... Couchbase sorts values by key. In your situation it will not sort it by date, so you should do it manually in your reduce function. Probably it will look like:
result.Last = values[i].Last > result.Last ? values[i].Last : result.Last;
and in reduce function it also can be an array, so I don't think that your reduce function always be correct.
Here is an example of my reduce function that filter documents and leave just one that have the newest date. May be it will be helpful or you can try to use it (seems it looks like reduce function that you want, you just need to add count somewhere).
function(k,v,r){
if (r){
if (v.length > 1){
var m = v[0].Date;
var mid = 0;
for (var i=1;i<v.length;i++){
if (v[i].Date > m){
m = v[i].Date;
mid = i;
}
}
return v[mid];
}
else {
return v[0] || v;
}
}
if (v.length > 1){
var m = v[0].Date;
var mid = 0;
for (var i=1;i<v.length;i++){
if (v[i].Date > m){
m = v[i].Date;
mid = i;
}
}
return v[mid];
}
else {
return v[0] || v;
}
}
UPD: Here is an example of what that reduce do:
Input date (values) for that function will look like (I've used just numbers instead of text date to make it shorter):
[{Date:1},{Date:3},{Date:8},{Date:2},{Date:4},{Date:7},{Date:5}]
On the first step rereduce will be false, so we need to find the biggest date in array, and it will return
Object {Date: 8}.
Note, that this function can be called one time, but it can be called on several servers in cluster or on several branches of b-tree inside one couchbase instance.
Then on next step (if there were several machines in cluster or "branches") rereduce will be called and rereduce var will be set to true
Incoming data will be:
[{Date:8},{Date:10},{Date:3}], where {Date:8} came from reduce from one server(or branch), and other dates came from another server(or branch).
So we need to do exactly the same on that new values to find the biggest one.
Answering your question from comments: I don't remember why I used same code for reduce and rereduce, because it was long time ago (when couchbase 2.0 was in dev preview). May be couchbase had some bugs or I just tried to understand how rereduce works. But I remember that without that if (r) {..} it not worked at that time.
You can try to place return v; code in different parts of my or your reduce function to see what it returns on each reduce phase. It's better to try once by yourself to understand what actually happens there.
I forget to mention that I have many documents for the same key. In fact for each key I can have many documents( message here):
{
"date": "2014-04-16T17:13:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
"message": "message1",
}
{
"date": "2014-04-16T15:22:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
"message": "message2",
}
Another way to deal with the problem is to do it in the map function:
function (doc, meta) {
var count = 0;
var last =''
if(doc.type =="doc"){
for (k in doc.message){
count += 1;
last = doc.date> last?doc.date:last;
}
emit(doc.key,{'Count':count,'Last': last});
}
}
I found this simpler and it do the job in my case.

Sahi: _include in if statements

I'm trying to run the following code as a sahi script:
_include("initialScript.sah");
_include("secondScript.sah");
function currentTime(){
var $current = new Date();
var $hours = $current.getHours();
var $minutes = $current.getMinutes();
if ($minutes < 10){
$minutes = "0" + minutes;
}
if($hours > 11){
_log("It is " + $hours + ":" + $minutes + " PM");
}
else {
_log("It is " + $hours + ":" + $minutes + " AM");
}
if($hours >= 8 || $hours =< 20) {
_include("aScript.sah");
_include("anotherScript.sah");
...
}
else {
//do nothing and continue below
}
}
_include("yetMoreScripts.sah");
...
Simply put, I have a block of various scripts, followed by a check of the current time.
If it isn't between 8am and 8pm, the included block of scripts is skipped and the others below are executed. The _logs tell me that getting the time appears to work as intended.
Yet whenever I attempt to run the script as is, I get an immediate failure and completely unrelated Syntax Errors (such as on an _include way further down that is not faulty at all). Taking the _includes out of the if Statement seems to make the errors stop. For all I know this should work but just doesn't. Does anybody have experience with something similar and could give me a hint as to where I made a mistake?
as far as I can tell, this should work. A simple test:
test1.sah:
_log("ok");
test2.sah:
if (true) {
_include("test1.sah");
}
When I run this from the Sahi Controller, I get an "ok" logged. Maybe recreate this test and check if you get the same results.
Maybe it's the ";" missing after your includes?
Are you passing dynamic values to include? like _include($path)?