Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@seanmtracey
Last active April 21, 2020 13:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanmtracey/f820a0df2400a965dfe72d8b2f833919 to your computer and use it in GitHub Desktop.
Save seanmtracey/f820a0df2400a965dfe72d8b2f833919 to your computer and use it in GitHub Desktop.
The code for the IBM Developer UK word counter tutorial
[{"id":"b76061c1.f23da","type":"inject","z":"92d160d6.54f31","name":"Blue","topic":"","payload":"#000099","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":435,"wires":[["e6cb0afc.efffd8"]]},{"id":"756acaa2.4247b4","type":"inject","z":"92d160d6.54f31","name":"Orange","topic":"","payload":"#ffff00","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":495,"wires":[["e6cb0afc.efffd8"]]},{"id":"72dd9b62.3bc494","type":"inject","z":"92d160d6.54f31","name":"Green","topic":"","payload":"#00ff00","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":555,"wires":[["e6cb0afc.efffd8"]]},{"id":"7e5328f4.4aa2b8","type":"function","z":"92d160d6.54f31","name":"Word Counter","func":"const MAX_WORDS_ALLOWED = 185;\nconst ALLOWANCE = 40;\nconst WINDOW_TRANSCRIPTS = context.get('audio') || [];\n\nconst data = {\n time : Date.now() | 0,\n words : msg.transcription.split(' ')\n};\n\nWINDOW_TRANSCRIPTS.push(data);\n\nconst MINUTE_TRANSCRIPT_WINDOW = WINDOW_TRANSCRIPTS.filter(datum => {return (Date.now() | 0) - datum.time < 60000 });\n\ncontext.set('audio', MINUTE_TRANSCRIPT_WINDOW);\n\nconst WORDS_COUNTED = MINUTE_TRANSCRIPT_WINDOW.reduce( (acc, data) => {\n \n console.log('COUNT!:', acc, data);\n return acc + data.words.length\n \n}, 0 );\n\n\nconst TIME_ELAPSED = (MINUTE_TRANSCRIPT_WINDOW[MINUTE_TRANSCRIPT_WINDOW.length - 1].time) - MINUTE_TRANSCRIPT_WINDOW[0].time;\nconst MULT_FACTOR = (60000 / TIME_ELAPSED);\nconst WORDS_SPOKEN = WORDS_COUNTED * MULT_FACTOR;\n\nconst NB = `EST: ${WORDS_SPOKEN} COUNTED: ${WORDS_COUNTED} TIME ELAPSED: ${TIME_ELAPSED}`;\nconsole.log(NB);\n\nmsg.NB = NB;\n\n\nif(WORDS_SPOKEN > MAX_WORDS_ALLOWED){\n msg.payload = '#0000ff';\n} else if(WORDS_SPOKEN > MAX_WORDS_ALLOWED - ALLOWANCE){\n msg.payload = '#ffff00';\n} else {\n msg.payload = '#00ff00';\n}\n\nmsg.words_spoken = WORDS_SPOKEN === Infinity ? 0 : WORDS_SPOKEN;\n\nreturn msg;","outputs":1,"noerr":0,"x":590,"y":285,"wires":[["c5494993.caaf68","eac868c.c377c98","ff0f84e9.6e58c8","e6cb0afc.efffd8"]]},{"id":"c5494993.caaf68","type":"debug","z":"92d160d6.54f31","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":785,"y":225,"wires":[]},{"id":"9bb56441.c2fbc8","type":"websocket in","z":"92d160d6.54f31","name":"","server":"acd8ae06.c9bf5","client":"","x":145,"y":225,"wires":[["c5494993.caaf68","e747537e.709ac"]]},{"id":"7a64e849.b77098","type":"http in","z":"92d160d6.54f31","name":"","url":"/word-count","method":"get","upload":false,"swaggerDoc":"","x":155,"y":150,"wires":[["ac02e244.643f5"]]},{"id":"f46e6c2b.8ab33","type":"http response","z":"92d160d6.54f31","name":"","statusCode":"","headers":{},"x":815,"y":150,"wires":[]},{"id":"ac02e244.643f5","type":"template","z":"92d160d6.54f31","name":"CSS","field":"payload.styles","fieldType":"msg","format":"css","syntax":"mustache","template":"/*\n* {\n background: blue;\n}*/\n\nbody{\n display: flex;\n flex-direction: column;\n align-items: center;\n font-family: sans-serif;\n}\n\n\n#toggle{\n width: 200px;\n padding: 1em;\n border: 1px solid black;\n border-radius: 10px;\n cursor: pointer;\n font-weight: 800;\n font-size: 1em;\n outline: 0 solid transparent;\n}\n\n#toggle[data-state=\"started\"]{\n color: white;\n border-color: red;\n background: #ff7878;\n animation: pulse 2.5s infinite;\n\t-moz-animation: pulse 2.5s infinite;\n\t-webkit-animation: pulse 2.5s infinite;\n\t-o-animation: pulse 2.5s infinite;\n}\n\n@keyframes pulse{\n\t0% {opacity:1; }\n\t50% {opacity: 0.5; }\n 100% {opacity: 1; }\n}\n\n@-moz-keyframes pulse{\n\t0% {opacity:1; }\n\t50% {opacity: 0.5; }\n 100% {opacity: 1; }\n}\n\t\n@-webkit-keyframes pulse{\n\t0% {opacity:1; }\n\t50% {opacity: 0.5; }\n 100% {opacity: 1; }\n}\n\t\n@-o-keyframes pulse{\n\t0% {opacity:1; }\n\t50% {opacity: 0.5; }\n 100% {opacity: 1; }\n}","output":"str","x":350,"y":150,"wires":[["67afa70a.c35628"]]},{"id":"e747537e.709ac","type":"watson-speech-to-text","z":"92d160d6.54f31","name":"","alternatives":1,"speakerlabels":false,"smartformatting":false,"lang":"en-US","langhidden":"en-US","langcustom":"NoCustomisationSetting","langcustomhidden":"","custom-weight":"","band":"BroadbandModel","bandhidden":"BroadbandModel","keywords":"","keywords-threshold":"","word-confidence":false,"password":"","apikey":"","payload-response":false,"streaming-mode":false,"streaming-mute":false,"auto-connect":false,"discard-listening":false,"disable-precheck":true,"default-endpoint":false,"service-endpoint":"https://api.eu-gb.speech-to-text.watson.cloud.ibm.com/instances/5a99436a-752e-4a3f-bcbb-7e4a349fdb3f","x":350,"y":285,"wires":[["7e5328f4.4aa2b8"]]},{"id":"eac868c.c377c98","type":"debug","z":"92d160d6.54f31","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"words_spoken","x":825,"y":285,"wires":[]},{"id":"ec16d20c.0ecf4","type":"template","z":"92d160d6.54f31","name":"HTML","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n <head>\n <title>Simple Mic Streamer</title>\n <style>\n {{{payload.styles}}}\n </style>\n </head>\n <body>\n \n <h1>Sean's Friendly Word Counting Assistant</h1>\n\n <button id=\"toggle\" data-state=\"stopped\">Start</button>\n \n <script>\n\n {{{payload.script}}}\n \n </script>\n \n </body>\n</html>","output":"str","x":650,"y":150,"wires":[["f46e6c2b.8ab33"]]},{"id":"67afa70a.c35628","type":"template","z":"92d160d6.54f31","name":"Script","field":"payload.script","fieldType":"msg","format":"javascript","syntax":"mustache","template":"(function(){\n \n 'use strict';\n \n let ws = createWebSocket('wss://' + window.location.host + '/ws/audio');\n bindWebSocketEvents(ws);\n\n function createWebSocket(URL){\n console.log('Attempting to establish WS connection to:', URL);\n return new WebSocket(URL);\n }\n\n function bindWebSocketEvents(WS){\n \n ws.addEventListener('open', function(){\n console.log('WS connection established'); \n }, false);\n \n ws.addEventListener('message', function(msg){\n console.log('WS message:', msg);\n }, false);\n \n ws.addEventListener('error', function(err){\n console.log('WS error:', err);\n }, false);\n \n ws.addEventListener('close', function(e){\n console.log('WS connection closed:', e);\n ws = createWebSocket('wss://' + window.location.host + '/ws/audio');\n bindWebSocketEvents(ws);\n });\n\n }\n\n const button = document.querySelector('button');\n \n let mR;\n\n const constraints = {\n video : false,\n audio : true\n };\n\n navigator.mediaDevices.getUserMedia(constraints)\n .then(function(stream){\n\n mR = new MediaRecorder(stream);\n \n mR.start();\n \n setInterval(function(){\n\n mR.ondataavailable = function(e){\n console.log(e.data);\n \n if(button.dataset.state === 'started'){\n console.log('Sending to server:', e.data);\n if(ws.readyState === 1){\n ws.send(e.data);\n }\n }\n }\n\n mR.stop();\n\n mR = new MediaRecorder(stream);\n mR.start();\n\n }, 5000);\n\n\n })\n .catch(function(err){\n console.log('Media stream err:', err);\n })\n ;\n\n button.addEventListener('click', function(){\n\n this.dataset.state = this.dataset.state === 'stopped' ? 'started' : 'stopped';\n this.textContent = this.dataset.state === 'stopped' ? 'Start' : 'Stop';\n \n }, false);\n \n}());\n","output":"str","x":500,"y":150,"wires":[["ec16d20c.0ecf4"]]},{"id":"ff0f84e9.6e58c8","type":"debug","z":"92d160d6.54f31","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"NB","x":795,"y":345,"wires":[]},{"id":"e6cb0afc.efffd8","type":"mqtt out","z":"92d160d6.54f31","name":"","topic":"gloworb-emulator","qos":"","retain":"","broker":"efc46a04.2ab5d8","x":835,"y":465,"wires":[]},{"id":"b6f8c15e.c18e6","type":"inject","z":"92d160d6.54f31","name":"Red","topic":"","payload":"#FF0000","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":645,"wires":[["e6cb0afc.efffd8"]]},{"id":"acd8ae06.c9bf5","type":"websocket-listener","z":"","path":"/ws/audio","wholemsg":"false"},{"id":"efc46a04.2ab5d8","type":"mqtt-broker","z":"","name":"","broker":"mqtt.eclipse.org","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]
<!DOCTYPE html>
<html>
<head>
<title>Simple Mic Streamer</title>
<style>
{{{payload.styles}}}
</style>
</head>
<body>
<h1>Sean's Friendly Word Counting Assistant</h1>
<button id="toggle" data-state="stopped">Start</button>
<script>
{{{payload.script}}}
</script>
</body>
</html>
(function(){
'use strict';
let ws = createWebSocket('wss://' + window.location.host + '/ws/audio');
bindWebSocketEvents(ws);
function createWebSocket(URL){
console.log('Attempting to establish WS connection to:', URL);
return new WebSocket(URL);
}
function bindWebSocketEvents(WS){
ws.addEventListener('open', function(){
console.log('WS connection established');
}, false);
ws.addEventListener('message', function(msg){
console.log('WS message:', msg);
}, false);
ws.addEventListener('error', function(err){
console.log('WS error:', err);
}, false);
ws.addEventListener('close', function(e){
console.log('WS connection closed:', e);
ws = createWebSocket('wss://' + window.location.host + '/ws/audio');
bindWebSocketEvents(ws);
});
}
const button = document.querySelector('button');
let mR;
const constraints = {
video : false,
audio : true
};
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream){
mR = new MediaRecorder(stream);
mR.start();
setInterval(function(){
mR.ondataavailable = function(e){
console.log(e.data);
if(button.dataset.state === 'started'){
console.log('Sending to server:', e.data);
if(ws.readyState === 1){
ws.send(e.data);
}
}
}
mR.stop();
mR = new MediaRecorder(stream);
mR.start();
}, 5000);
})
.catch(function(err){
console.log('Media stream err:', err);
})
;
button.addEventListener('click', function(){
this.dataset.state = this.dataset.state === 'stopped' ? 'started' : 'stopped';
this.textContent = this.dataset.state === 'stopped' ? 'Start' : 'Stop';
}, false);
}());
/*
* {
background: blue;
}*/
body{
display: flex;
flex-direction: column;
align-items: center;
font-family: sans-serif;
}
#toggle{
width: 200px;
padding: 1em;
border: 1px solid black;
border-radius: 10px;
cursor: pointer;
font-weight: 800;
font-size: 1em;
outline: 0 solid transparent;
}
#toggle[data-state="started"]{
color: white;
border-color: red;
background: #ff7878;
animation: pulse 2.5s infinite;
-moz-animation: pulse 2.5s infinite;
-webkit-animation: pulse 2.5s infinite;
-o-animation: pulse 2.5s infinite;
}
@keyframes pulse{
0% {opacity:1; }
50% {opacity: 0.5; }
100% {opacity: 1; }
}
@-moz-keyframes pulse{
0% {opacity:1; }
50% {opacity: 0.5; }
100% {opacity: 1; }
}
@-webkit-keyframes pulse{
0% {opacity:1; }
50% {opacity: 0.5; }
100% {opacity: 1; }
}
@-o-keyframes pulse{
0% {opacity:1; }
50% {opacity: 0.5; }
100% {opacity: 1; }
}
This is all of the code needed to follow the IBM Developer UK word counter tutorial.
const MAX_WORDS_ALLOWED = 185;
const ALLOWANCE = 40;
const WINDOW_TRANSCRIPTS = context.get('audio') || [];
const data = {
time : Date.now() | 0,
words : msg.transcription.split(' ')
};
WINDOW_TRANSCRIPTS.push(data);
const MINUTE_TRANSCRIPT_WINDOW = WINDOW_TRANSCRIPTS.filter(datum => {return (Date.now() | 0) - datum.time < 60000 });
context.set('audio', MINUTE_TRANSCRIPT_WINDOW);
const WORDS_COUNTED = MINUTE_TRANSCRIPT_WINDOW.reduce( (acc, data) => {
console.log('COUNT!:', acc, data);
return acc + data.words.length
}, 0 );
const TIME_ELAPSED = (MINUTE_TRANSCRIPT_WINDOW[MINUTE_TRANSCRIPT_WINDOW.length - 1].time) - MINUTE_TRANSCRIPT_WINDOW[0].time;
const MULT_FACTOR = (60000 / TIME_ELAPSED);
const WORDS_SPOKEN = WORDS_COUNTED * MULT_FACTOR;
const NB = `EST: ${WORDS_SPOKEN} COUNTED: ${WORDS_COUNTED} TIME ELAPSED: ${TIME_ELAPSED}`;
console.log(NB);
msg.NB = NB;
if(WORDS_SPOKEN > MAX_WORDS_ALLOWED){
msg.payload = '#0000ff';
} else if(WORDS_SPOKEN > MAX_WORDS_ALLOWED - ALLOWANCE){
msg.payload = '#ffff00';
} else {
msg.payload = '#00ff00';
}
msg.words_spoken = WORDS_SPOKEN === Infinity ? 0 : WORDS_SPOKEN;
return msg;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment