@ibgib/helper-gib
Version:
common helper/utils/etc used in ibgib libs. Node v19+ needed for heavily-used isomorphic webcrypto hashing consumed in both node and browsers.
1,050 lines (1,049 loc) • 32.1 kB
JavaScript
import { HELPER_LOG_A_LOT } from "../constants.mjs";
const logalot = HELPER_LOG_A_LOT || true;
/**
* Values that indicate how Alexa should speak text.
* To be used with Ssml.sayAs({text, interpret: As.characters})
*/
export const As = {
/**
* Spell out each letter.
*/
characters: "characters",
/**
* Spell out each letter.
*/
spell_out: "spell-out",
/**
* Interpret the value as a cardinal number.
*
* @example "12" is pronounced as "twelve" and not "1-2".
*/
cardinal: "cardinal",
/**
* Interpret the value as a cardinal number.
*
* @example "12" is pronounced as "twelve" and not "1-2".
*/
number: "number",
/**
* Interpret the value as an ordinal number.
*
* @example "12" is pronounced as "twelfth"
*/
ordinal: "ordinal",
/**
* Spell each digit separately.
*/
digits: "digits",
/**
* Interpret the value as a fraction. This works for both common
* fractions (such as 3/20) and mixed fractions (such as 1+1/2).
*/
fraction: "fraction",
/**
* Interpret a value as a measurement. The value should be either a
* number or fraction followed by a unit (with no space in between)
* or just a unit.
*/
unit: "unit",
/**
* Interpret the value as a date. Specify the format with the
* format attribute.
*/
date: "date",
/**
* Interpret a value such as 1'21" as duration in minutes and
* seconds.
*/
time: "time",
/**
* Interpret a value as a 7-digit or 10-digit telephone number.
* This can also handle extensions (for example, 2025551212x345).
*/
telephone: "telephone",
/**
* Interpret a value as part of street address.
*/
address: "address",
/**
* askGib NOTE: SpeechCons are already implemented directly: e.g. `Ssml.speech(Con.abracadabra)`
*
* Interpret the value as an interjection. Alexa speaks the text in
* a more expressive voice. For optimal results, only use the
* supported interjections and surround each one with a pause. For
*
* @example
* <say-as interpret-as="interjection">Wow.</say-as>.
*
* Speechcons are supported for English (US), English (UK), and
* German.
*/
interjection: "interjection",
/**
* “Bleep” out the content inside the tag.
*/
expletive: "expletive",
};
/**
* Date formats, used with @see {sayAs} function when
* @see {InterpretAs} is "date".
*
* Alternatively, if you provide the date in YYYYMMDD format, the
* format attribute is ignored. You can include question marks (?) for
* portions of the date to leave out. For instance, Alexa would speak
* <say-as interpret-as="date">????0922</say-as> as “September 22nd”.
*/
export const SayAsDate = {
mdy: "mdy",
dmy: "dmy",
ymd: "ymd",
md: "md",
dm: "dm",
ym: "ym",
my: "my",
d: "d",
m: "m",
y: "y",
};
/**
* Special interjections that Alexa can say.
* I have this called only "Con" for readability of calling code.
*
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speechcon-reference
*
* All spaces in keys are replaced with underscores.
*/
export const Con = {
abracadabra: "abracadabra",
achoo: "achoo",
aha: "aha",
ahem: "ahem",
ahoy: "ahoy",
all_righty: "all righty",
aloha: "aloha",
aooga: "aooga",
argh: "argh",
arrivederci: "arrivederci",
as_you_wish: "as you wish",
attagirl: "attagirl",
au_revoir: "au revoir",
avast_ye: "avast ye",
aw_man: "aw man",
baa: "baa",
bada_bing_bada_boom: "bada bing bada boom",
bah_humbug: "bah humbug",
bam: "bam",
bang: "bang",
batter_up: "batter up",
bazinga: "bazinga",
beep_beep: "beep beep",
bingo: "bingo",
blah: "blah",
blarg: "blarg",
blast: "blast",
boing: "boing",
bon_appetit: "bon appetit",
bonjour: "bonjour",
bon_voyage: "bon voyage",
boo: "boo",
boo_hoo: "boo hoo",
boom: "boom",
booya: "booya",
bravo: "bravo",
bummer: "bummer",
caw: "caw",
cha_ching: "cha ching",
checkmate: "checkmate",
cheerio: "cheerio",
cheers: "cheers",
cheer_up: "cheer up",
chirp: "chirp",
choo_choo: "choo choo",
clank: "clank",
click_clack: "click clack",
cock_a_doodle_doo: "cock a doodle doo",
coo: "coo",
cowabunga: "cowabunga",
darn: "darn",
ding_dong: "ding dong",
ditto: "ditto",
doh: "doh",
dot_dot_dot: "dot dot dot",
duh: "duh",
dum: "dum",
dun_dun_dun: "dun dun dun",
dynomite: "dynomite",
eek: "eek",
eep: "eep",
encore: "encore",
en_gard: "en gard",
eureka: "eureka",
fancy_that: "fancy that",
geronimo: "geronimo",
giddy_up: "giddy up",
good_grief: "good grief",
good_luck: "good luck",
good_riddance: "good riddance",
gotcha: "gotcha",
great_scott: "great scott",
heads_up: "heads up",
hear_hear: "hear hear",
hip_hip_hooray: "hip hip hooray",
hiss: "hiss",
honk: "honk",
howdy: "howdy",
hurrah: "hurrah",
hurray: "hurray",
huzzah: "huzzah",
jeepers_creepers: "jeepers creepers",
jiminy_cricket: "jiminy cricket",
jinx: "jinx",
just_kidding: "just kidding",
kaboom: "kaboom",
kablam: "kablam",
kaching: "kaching",
kapow: "kapow",
katchow: "katchow",
kazaam: "kazaam",
kerbam: "kerbam",
kerboom: "kerboom",
kerching: "kerching",
kerchoo: "kerchoo",
kerflop: "kerflop",
kerplop: "kerplop",
kerplunk: "kerplunk",
kerpow: "kerpow",
kersplat: "kersplat",
kerthump: "kerthump",
knock_knock: "knock knock",
le_sigh: "le sigh",
look_out: "look out",
mamma_mia: "mamma mia",
man_overboard: "man overboard",
mazel_tov: "mazel tov",
meow: "meow",
merci: "merci",
moo: "moo",
nanu_nanu: "nanu nanu",
neener_neener: "neener neener",
no_way: "no way",
now_now: "now now",
oh_boy: "oh boy",
oh_brother: "oh brother",
oh_dear: "oh dear",
oh_my: "oh my",
oh_snap: "oh snap",
oink: "oink",
okey_dokey: "okey dokey",
oof: "oof",
ooh_la_la: "ooh la la",
open_sesame: "open sesame",
ouch: "ouch",
oy: "oy",
phew: "phew",
phooey: "phooey",
ping: "ping",
plop: "plop",
poof: "poof",
pop: "pop",
pow: "pow",
quack: "quack",
read_em_and_weep: "read em and weep",
ribbit: "ribbit",
righto: "righto",
roger: "roger",
ruh_roh: "ruh roh",
shucks: "shucks",
splash: "splash",
spoiler_alert: "spoiler alert",
squee: "squee",
swish: "swish",
swoosh: "swoosh",
ta_da: "ta da",
ta_ta: "ta ta",
tee_hee: "tee hee",
there_there: "there there",
thump: "thump",
tick_tick_tick: "tick tick tick",
tick_tock: "tick tock",
touche: "touche",
tsk_tsk: "tsk tsk",
tweet: "tweet",
uh_huh: "uh huh",
uh_oh: "uh oh",
um: "um",
voila: "voila",
vroom: "vroom",
wahoo: "wahoo",
wah_wah: "wah wah",
watch_out: "watch out",
way_to_go: "way to go",
well_done: "well done",
well_well: "well well",
wham: "wham",
whammo: "whammo",
whee: "whee",
whew: "whew",
woof: "woof",
whoops_a_daisy: "whoops a daisy",
whoosh: "whoosh",
woo_hoo: "woo hoo",
wow: "wow",
wowza: "wowza",
wowzer: "wowzer",
yadda_yadda_yadda: "yadda yadda yadda",
yay: "yay",
yikes: "yikes",
yippee: "yippee",
yoink: "yoink",
yoo_hoo: "yoo hoo",
you_bet: "you bet",
yowza: "yowza",
yowzer: "yowzer",
yuck: "yuck",
yum: "yum",
zap: "zap",
zing: "zing",
zoinks: "zoinks",
};
export const ConUK = {
abracadabra: "abracadabra",
ace: "ace",
achoo: "achoo",
ahoy: "ahoy",
all: "all",
aloha: "aloha",
aooga: "aooga",
arrivederci: "arrivederci",
as_if: "as if",
as_you_wish: "as you wish",
au_revoir: "au revoir",
aw: "aw",
aw_man: "aw man",
awesome: "awesome",
baa: "baa",
bah_humbug: "bah humbug",
bam: "bam",
bang: "bang",
bazinga: "bazinga",
beep_beep: "beep beep",
bingo: "bingo",
blah: "blah",
blarg: "blarg",
blast: "blast",
blimey: "blimey",
bobs_your_uncle: "bobs your uncle",
boing: "boing",
bon_appetit: "bon appetit",
bon_voyage: "bon voyage",
bonjour: "bonjour",
boo: "boo",
boo_hoo: "boo hoo",
booya: "booya",
bother: "bother",
bravo: "bravo",
caw: "caw",
cha_ching: "cha ching",
checkmate: "checkmate",
cheer_up: "cheer up",
cheerio: "cheerio",
cheers: "cheers",
chirp: "chirp",
choo_choo: "choo choo",
clank: "clank",
clickety_clack: "clickety clack",
cock_a_doodle_doo: "cock a doodle doo",
codswallop: "codswallop",
coo: "coo",
cowabunga: "cowabunga",
crikey: "crikey",
doh: "doh",
darn: "darn",
ditto: "ditto",
dot_dot_dot: "dot dot dot",
duh: "duh",
dun_dun_dun: "dun dun dun",
eek: "eek",
eep: "eep",
en_garde: "en garde",
encore: "encore",
eureka: "eureka",
ew: "ew",
fancy_that: "fancy that",
geronimo: "geronimo",
giddy_up: "giddy up",
good_golly: "good golly",
good_grief: "good grief",
good_luck: "good luck",
good_riddance: "good riddance",
gosh: "gosh",
gotcha: "gotcha",
great_scott: "great scott",
ha: "ha",
ha_ha: "ha ha",
heads_up: "heads up",
hear_hear: "hear hear",
hip_hip_hooray: "hip hip hooray",
hiss: "hiss",
honk: "honk",
howdy: "howdy",
howzat: "howzat",
hurrah: "hurrah",
hurray: "hurray",
huzzah: "huzzah",
jeepers_creepers: "jeepers creepers",
jiminy_cricket: "jiminy cricket",
jinx: "jinx",
just_kidding: "just kidding",
kablam: "kablam",
kaboom: "kaboom",
kaching: "kaching",
kapow: "kapow",
knock_knock: "knock knock",
le_sigh: "le sigh",
look_out: "look out",
mamma_mia: "mamma mia",
man_overboard: "man overboard",
mazel_tov: "mazel tov",
meow: "meow",
merci: "merci",
moo: "moo",
no_way: "no way",
nom_nom: "nom nom",
now_now: "now now",
oh_boy: "oh boy",
oh_dear: "oh dear",
oh_my: "oh my",
oh_my_giddy_aunt: "oh my giddy aunt",
oh_snap: "oh snap",
okey_dokey: "okey dokey",
oof: "oof",
ooh_la_la: "ooh la la",
open_sesame: "open sesame",
ouch: "ouch",
ow: "ow",
oy: "oy",
pardon: "pardon",
phew: "phew",
phooey: "phooey",
ping: "ping",
plop: "plop",
pop: "pop",
pow: "pow",
quack: "quack",
read_em_and_weep: "read em and weep",
ribbit: "ribbit",
righto: "righto",
roger: "roger",
sigh: "sigh",
simples: "simples",
splash: "splash",
spoiler_alert: "spoiler alert",
squee: "squee",
swish: "swish",
swoosh: "swoosh",
ta_da: "ta da",
tallyho: "tallyho",
tee_hee: "tee hee",
there_there: "there there",
thump: "thump",
tick_tick_tick: "tick tick tick",
tick_tock: "tick tock",
tosh: "tosh",
touche: "touche",
tsk_tsk: "tsk tsk",
tut_tut: "tut tut",
tweet: "tweet",
uh_huh: "uh huh",
uh_oh: "uh oh",
voila: "voila",
vroom: "vroom",
wahoo: "wahoo",
watch_out: "watch out",
way_to_go: "way to go",
well_done: "well done",
well_well: "well well",
wham: "wham",
whammo: "whammo",
whee: "whee",
whoop: "whoop",
whoops: "whoops",
whoops_a_daisy: "whoops a daisy",
whoosh: "whoosh",
woo_hoo: "woo hoo",
wow: "wow",
wowza: "wowza",
yadda_yadda_yadda: "yadda yadda yadda",
yippee: "yippee",
yoink: "yoink",
you_bet: "you bet",
yowza: "yowza",
yum: "yum",
zap: "zap",
zing: "zing",
zoinks: "zoinks",
};
export const ConDE = {
aber_hallo: "aber hallo",
aber_sicher: "aber sicher",
abrakadabra: "abrakadabra",
ach: "ach",
ach_du_grüne_neune: "ach du grüne neune",
ach_du_liebe_zeit: "ach du liebe zeit",
ach_du_meine_güte: "ach du meine güte",
ach_ja: "ach ja",
ach_so: "ach so",
achje: "achje",
achtung: "achtung",
ade: "ade",
ah: "ah",
aha: "aha",
ähm: "ähm",
ahoi: "ahoi",
alles_klar: "alles klar",
aloha: "aloha",
als_ob: "als ob",
argh: "argh",
arrivederci: "arrivederci",
aso: "aso",
au: "au",
au_weia: "au weia",
aua: "aua",
autsch: "autsch",
bazinga: "bazinga",
bingo: "bingo",
bis_bald: "bis bald",
bis_dann: "bis dann",
bla: "bla",
boing: "boing",
bon_appetit: "bon appetit",
bon_voyage: "bon voyage",
bonjour: "bonjour",
bravo: "bravo",
brumm: "brumm",
buh: "buh",
buhu: "buhu",
bumm: "bumm",
bzz: "bzz",
da_lachen_ja_die_hühner: "da lachen ja die hühner",
ding_dong: "ding dong",
dito: "dito",
donner_und_doria: "donner und doria",
donnerwetter: "donnerwetter",
ebenso: "ebenso",
en_garde: "en garde",
ey: "ey",
geh_nur: "geh nur",
gemach: "gemach",
genug: "genug",
gesundheit: "gesundheit",
gott_im_himmel: "gott im himmel",
grüß_gott: "grüß gott",
gute_reise: "gute reise",
guten_appetit: "guten appetit",
hach_ja: "hach ja",
halleluja: "halleluja",
hals_und_beinbruch: "hals und beinbruch",
halt: "halt",
hände_hoch: "hände hoch",
heiliger_strohsack: "heiliger strohsack",
heisa: "heisa",
hey: "hey",
hihi: "hihi",
hipp_hipp_hurra: "hipp hipp hurra",
hört_hört: "hört hört",
hü: "hü",
hüa: "hüa",
huch: "huch",
huhu: "huhu",
hui: "hui",
hurra: "hurra",
ich_glaub_ich_bin_im_kino: "ich glaub ich bin im kino",
ich_glaub_mein_schwein_pfeift: "ich glaub mein schwein pfeift",
ich_glaub_mich_knutscht_ein_elch: "ich glaub mich knutscht ein elch",
ich_glaub_mich_laust_der_affe: "ich glaub mich laust der affe",
ich_glaub_mich_tritt_ein_pferd: "ich glaub mich tritt ein pferd",
igitt: "igitt",
iiieh: "iiieh",
ist_nicht_dein_ernst: "ist nicht dein ernst",
japp: "japp",
jawohl: "jawohl",
jo: "jo",
juhu: "juhu",
kein_kommentar: "kein kommentar",
keine_ursache: "keine ursache",
kikeriki: "kikeriki",
klar: "klar",
klick_klack: "klick klack",
kopf_hoch: "kopf hoch",
kuckuck: "kuckuck",
lass_es_dir_schmecken: "lass es dir schmecken",
lecker: "lecker",
los: "los",
mach: "mach's gut",
mahlzeit: "mahlzeit",
mamma_mia: "mamma mia",
mann_über_bord: "mann über bord",
manometer: "manometer",
mazel_tov: "mazel tov",
mein_gott: "mein gott",
merci: "merci",
miau: "miau",
mist: "mist",
moin: "moin",
muh: "muh",
na_klar: "na klar",
na_sieh_mal_einer_an: "na sieh mal einer an",
na_und_: "na und?",
na_: "na?",
naja: "naja",
nanu: "nanu",
ne: "ne",
nee: "nee",
nichts_da: "nichts da",
nix_da: "nix da",
nö: "nö",
null_problemo: "null problemo",
obacht: "obacht",
och: "och",
oh_mann: "oh mann",
oh_mein_gott: "oh mein gott",
oh_my_god: "oh my god",
oh_nein: "oh nein",
oh_oh: "oh oh",
ohne_scheiß: "ohne scheiß",
oink: "oink",
oje: "oje",
okey_dokey: "okey dokey",
ooh_la_la: "ooh la la",
pfui: "pfui",
piep: "piep",
plop: "plop",
plumps: "plumps",
prima: "prima",
prosit: "prosit",
prost: "prost",
puff: "puff",
puh: "puh",
pustekuchen: "pustekuchen",
schachmatt: "schachmatt",
schade: "schade",
schau_an: "schau an",
sesam_öffne_dich: "sesam öffne dich",
seufz: "seufz",
sieh_an: "sieh an",
siehe_da: "siehe da",
siehste: "siehste",
spoileralarm: "spoileralarm",
stimmt: "stimmt",
super: "super",
supi: "supi",
süßes_oder_saures: "süßes oder saures",
tada: "tada",
tatsächlich: "tatsächlich",
tick_tack: "tick tack",
tja: "tja",
touche: "touche",
tschö: "tschö",
türlich: "türlich",
tut: "tut",
uff: "uff",
verdammt: "verdammt",
verflixt: "verflixt",
viel_glück: "viel glück",
voila: "voila",
von_wegen: "von wegen",
vorsicht: "vorsicht",
war_nur_ein_scherz: "war nur ein scherz",
was_zur_hölle: "was zur hölle",
weh_mir: "weh mir",
wehe: "wehe",
wie_du_meinst: "wie du meinst",
willkommen: "willkommen",
wow: "wow",
wuff: "wuff",
yay: "yay",
zugabe: "zugabe",
zum_wohl: "zum wohl",
};
export const Effect = {
whispered: "whispered",
};
export const PartOfSpeech = {
/**
* Interpret the word as a verb (present simple).
*/
verb: "amazon:VB",
/**
* Interpret the word as a past participle.
*/
past_participle: "amazon:VBD",
/**
* Interpret the word as a noun.
*/
noun: "amazon:NN",
/**
* Use the non-default sense of the word. For example,
* the noun “bass” is pronounced differently depending on meaning.
* The “default” meaning is the lowest part of the musical range.
* The alternate sense (which is still a noun) is a freshwater
* fish. Specifying
* <speak><w role="amazon:SENSE_1">bass</w>"</speak>
* renders the non-default pronunciation (freshwater fish).
*/
sense1: "amazon:SENSE_1",
};
export class Ssml {
/**
* Wraps a given list of paragraph strings in `<speak>` tags, with
* optional paragraph `<p>` tags.
*
* @param paras individual paragraphs to be wrapped in <p></p> tags.
* @param addParaTags If true, wraps individual strings in paras with `<p>` tags. Otherwise just concats.
*/
static wrapSsmlSpeak(paras, addParaTags = true) {
let result = "<speak>" +
paras.reduce((agg, p) => {
return addParaTags ? agg + "<p>" + p + "</p>" : agg + p;
}, "") +
"</speak>";
return result;
}
/**
* This simply replaces <speak> and </speak> tags with an empty
* string.
*
* Use this when you want to add some text to existing ssml and
* then re-wrap the ssml.
*
* @see {Helper.stripSsml} function.
*
* @param ssml with <speak> tag around the whole thing.
*/
static unwrapSsmlSpeak(ssml) {
return ssml.replace(/\<speak\>/g, "").replace(/\<\/speak\>/g, "");
}
/**
* Simply wraps with <p> tag.
*
* Represents a paragraph. This tag provides extra-strong breaks
* before and after the tag. This is equivalent to specifying a
* pause with <break strength="x-strong"/>.
*
* @param text to wrap
*/
static p(text) {
return '<p>' + text + '</p>';
}
/**
* Simply wraps with <s> tag.
*
* Represents a sentence. This tag provides strong breaks before
* and after the tag.
*
* This is equivalent to:
* Ending a sentence with a period (.).
* Specifying a pause with <break strength="strong"/>.
* @param text to wrap
*/
static s(text) {
return '<s>' + text + '</s>';
}
/**
* Strips all tags within ssml to produce plain text.
*
* @see {Helper.unwrapSsmlSpeak} function.
*
* @param ssml to strip
*/
static stripSsml(ssml) {
const stripped = ssml
// Combines </p> <p> to not double para breaks
.replace(/\<\/p\>[ ]*\<p\>/g, "<p>")
// remove spaces after <p>,</p> tags
.replace(/\<p\>(?=[ ])/g, "<p>")
.replace(/\<\/p\>(?=[ ])/g, "</p>")
// convert <p> and </p> to two new lines
.replace(/\<[\/]*p\>/g, "\n\n")
// Strip all remaining tags
.replace(/(<([^>]*)>)/ig, "")
// Replace multiple spaces with a single space
.replace(/ +/g, ' ')
.replace(/\\n\\n\\n/g, "\n\n")
// .replace(/^\\n+/, "")
.replace(/^\n+/, "")
.replace(/\n+$/, "");
return stripped;
}
/**
* Wraps a given text in an ssml phoneme tag with the given
* pronunciation and alphabet.
*
* @param text Literal text that we're wrapping the phoneme tag around, e.g. "sewing".
* @param pronunciation the phoneme itself, e.g. "soʊɪŋ"
* @param alphabet phoneme alphabet, either "ipa" or "x-sampe" (ATOW)
*
* @see {@link https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#prosody|SsmlReference}
*/
static phoneme(text, pronunciation, alphabet = "ipa") {
return `<phoneme alphabet="${alphabet}" ph="${pronunciation}">${text}</phoneme>`;
}
/**
* Wraps a given text in an ssml emphasis tag.
*
* e.g. <emphasis level="${level}">${text}</emphasis>`
*
* @param text to wrap with the emphasis tag
* @param level attribute in emphasis tag. Valid values "strong" | "moderate" | "reduced" = "moderate"
*
* @see {@link https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#prosody|SsmlReference}
*/
static emphasis(text, level = "moderate") {
return `<emphasis level="${level}">${text}</emphasis>`;
}
/**
* Wraps a given text in an ssml prosody tag with the given
* options of rate, pitch, and/or volume.
*
* @param rate valid values ATOW "x-slow" | "slow" | "medium" | "fast" | "x-fast" | number,
* @param pitch valid values ATOW "x-low" | "low" | "medium" | "high" | "x-high" | number,
* @param volume valid values ATOW "silent" | "x-soft" | "soft" | "medium" | "loud" | "x-loud" | number
*
* @see {@link https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#prosody|SsmlReference}
*/
// static prosody(text, { rate, pitch, volume }) {
static prosody(text, { rate, pitch, volume }) {
const lc = `${Ssml.lc}${Ssml.prosody.name}`;
let attrs = "";
// adds the + to positive numbers
if (rate || rate === 0) {
const rateText = typeof rate === 'number' ?
rate + "%" :
rate;
attrs += `rate="${rateText}"`;
}
if (pitch || pitch === 0) {
let pitchText;
if (typeof pitch === 'number') {
const pitchNum = pitch;
if (pitch >= 0) {
const max = 50;
if (pitchNum > max) {
console.warn(`${lc} max: ${max}, actual: ${pitchNum} (W: 7fd9706e59f24dba896e2de149904677)`);
}
pitchText = "+" + pitchNum + "%";
}
else {
const min = -33.3;
if (pitchNum < min) {
console.warn(`${lc} min: ${min}, actual: ${pitchNum} (W: 90f4c21672034c51a8a95dcfcd281f98)`);
}
pitchText = "-" + pitchNum + "%";
}
}
else {
pitchText = pitch;
}
attrs = attrs ? attrs + " " : attrs;
attrs += `pitch="${pitchText}"`;
}
if (volume || volume === 0) {
let volumeText;
if (typeof volume === 'number') {
let volumeNum = volume;
if (volumeNum >= 0) {
const max = 4.08;
if (volumeNum > max) {
console.warn(`${lc} max: ${max}, actual: ${volumeNum} (W: 7db9521e6b3e418faca89d2f5cfa4f2c)`);
}
volumeText = "+" + volumeNum + "%";
}
else {
const min = -12;
if (volumeNum < min) {
console.warn(`${lc} min: ${min}, actual: ${volumeNum} (W: 49210d930272498e828d2c9a815ceea0)`);
}
}
volumeText = volumeNum + "%";
}
else {
volumeText = volume;
}
attrs = attrs ? attrs + " " : attrs;
attrs += (volume ? `volume="${volumeText}"` : "");
}
return "<prosody " + attrs + ">" + text + "</prosody>";
}
/**
* Generates SpeechCon SSML.
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speechcon-reference
*/
static speech(speechCon) {
return `<say-as interpret-as="interjection">${speechCon}</say-as>`;
}
/**
* Applies Amazon-specific effects to the speech.
*
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#amazon-effect
*
* The name of the effect to apply to the speech. Available effects:
* whispered: Applies a whispering effect to the speech.
* @param effect Which amazon:effect. ATOW only whispered implemented.
* @param s text to wrap in the effect.
*/
static amazon(effect, s) {
return `<amazon:effect name="${effect}">${s}</amazon:effect>`;
}
/**
* The audio tag lets you provide the URL for an MP3 file that the
* Alexa service can play while rendering a response. You can use
* this to embed short, pre-recorded audio within your service’s
* response. For example, you could include sound effects alongside
* your text-to-speech responses, or provide responses using a
* voice associated with your brand. For more information, see
* Including Short Pre-Recorded Audio in your Response at
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/handling-requests-sent-by-alexa#audio.
*
* Note the following requirements and limitations:
*
* * The MP3 must be hosted at an Internet-accessible HTTPS
* endpoint. HTTPS is required, and the domain hosting the MP3
* file must present a valid, trusted SSL certificate.
* Self-signed certificates cannot be used.
* * The MP3 must not contain any customer-specific or other
* sensitive information.
* * The MP3 must be a valid MP3 file (MPEG version 2).
* * The audio file cannot be longer than ninety (90) seconds.
* * The bit rate must be 48 kbps. Note that this bit rate gives a
* good result when used with spoken content, but is generally
* not a high enough quality for music.
* * The sample rate must be 16000 Hz.
*
* You may need to use converter software to convert your MP3 files
* to the required codec version (MPEG version 2) and bit rate (48
* kbps).
*
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#audio
*
* @param srcUrl Specifies the URL for the MP3 file.
*/
static audio(srcUrl) {
return `<audio src="${srcUrl}" />`;
}
/**
* Represents a pause in the speech. Set the length of the pause
* with the strength or time attributes.
*
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#break
*
* @param param0
*/
static break({ strength, s, ms }) {
const lc = `${Ssml.lc}${Ssml.break.name}`;
if (strength) {
return `<break strength="${strength}"/>`;
}
else if (s || s === 0) {
const min = 0;
const max = 10;
if (s < min) {
console.warn(`${lc} min: ${min}, actual: ${s} (W: 6ff97060a6734f20b16a81a20d06630e)`);
s = min;
}
else if (s > max) {
console.warn(`${lc} max: ${max}, actual: ${s} (W: d57ed120e09c4fcaa19b864bdf9f1fc7)`);
s = max;
}
return `<break time="${s}s"/>`;
}
else if (ms || ms === 0) {
const min = 0;
const max = 10000;
if (ms < min) {
console.warn(`min: ${min}, actual: ${ms} (W: 0addf6dbab1844a9906bd18a859be3d7)`);
ms = 0;
}
else if (ms > max) {
console.warn(`max: ${max}, actual: ${ms} (W: f46b9868ec6d4ef2abd4f2aefe879427)`);
ms = max;
}
return `<break time="${ms}ms"/>`;
}
else {
throw new Error('Unknown break parameters (E: 1ae569301a354c28a54cc06b58c93b87)');
}
}
/**
* Takes a given text that will be written and provides an alias
* for it when it's actually spoken.
*
* For example, if the written text is the element symbol "Mg", then
* you probably want to verbally say the entire word: "Magnesium".
* In this case, the "text" is "Mg" and the "alias" is "Magnesium".
*
* @see (@link https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#sub)
*
* @param text Written text that will be substituted when spoken, e.g. "Mg"
* @param alias Spoken alias that will be spoken, e.g. "Magnesium"
*/
static sub(text, alias) {
return `<sub alias="${alias}">${text}</sub>`;
}
/**
* Similar to <say-as>, this tag customizes the pronunciation of
* words by specifying the word’s part of speech.
*
* @param text Text that requires clarity.
* @param partOfSpeech Context provided for the given text.
*/
static w(text, partOfSpeech) {
return `<w role="${partOfSpeech}">${text}</w>`;
}
/**
* Describes how the text should be interpreted. This lets you
* provide additional context to the text and eliminate any
* ambiguity on how Alexa should render the text. Indicate how
* Alexa should interpret the text with the interpret-as attribute.
*
* Note that the Alexa service attempts to interpret the provided
* text correctly based on the text’s formatting even without this
* tag. For example, if your output speech includes “202-555-1212”,
* Alexa speaks each individual digit, with a brief pause for each
* dash. You don’t need to use <say-as interpret-as="telephone"> in
* this case. However, if you provided the text “2025551212”, but
* you wanted Alexa to speak it as a phone number, you would need
* to use <say-as interpret-as="telephone">.
*
* @example
* <speak>
* Here is a number spoken as a cardinal number:
* <say-as interpret-as="cardinal">12345</say-as>.
* Here is the same number with each digit spoken separately:
* <say-as interpret-as="digits">12345</say-as>.
* Here is a word spelled out: <say-as interpret-as="spell-out">hello</say-as>
* </speak>
*
* @see
* https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference#say-as
*/
static sayAs({ text, interpret, format }) {
const lc = `${Ssml.lc}[${Ssml.sayAs.name}]`;
try {
if (format) {
if (interpret !== As.date) {
throw new Error(`\`format\` arg requires (implies) \`interpret\` === "date" (E: 2a470b25ac284ec4bec9eb3e6a704b6b)`);
}
return `<say-as interpret-as="${interpret}" format="${format}">${text}</say-as>`;
}
else {
return `<say-as interpret-as="${interpret}">${text}</say-as>`;
}
}
catch (error) {
console.error(`${lc} ${error.message}`);
throw error;
}
}
}
Ssml.lc = `[${Ssml.name}]`;
//# sourceMappingURL=ssml-helper.mjs.map