Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Real-time transcription and sentiment analysis of audio streams; on the phone and in the browser

Real-time transcription and sentiment analysis of audio streams; on the phone and in the browser

These are slightly updated slides for Geektime Code 2017, unfortunately, there is not a recording of that session. You can view a previous version of this talk with slightly different slides here: https://www.youtube.com/watch?v=v69dJbCfb-8

Discover how you can use Artifical Intelligence to perform sentiment analysis of an audio stream, in real-time! In this talk, we’re going to learn how to create a virtual rapporteur. A digital assistant who can join any conference call; record it, and then by using IBM Watson provide participants with a real-time transcript and insights into the overall tone of the call. All pushed to their browser via WebSockets.

Aaron Bassett

June 06, 2018
Tweet

More Decks by Aaron Bassett

Other Decks in Technology

Transcript

  1. (function poll() { new Ajax.Request('/api/', { method:'get', onSuccess: function() {

    ... }, onFailure: function() { ... } }); setTimeout(poll, 1000); }());
  2. (function poll() { new Ajax.Request('/api/', { method:'get', onSuccess: function() {

    ... }, onFailure: function() { ... } }); setTimeout(poll, 1000); }());
  3. (function poll() { new Ajax.Request('/api/', { method:'get', onSuccess: function() {

    ... }, onFailure: function() { ... } }); setTimeout(poll, 1000); }());
  4. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  5. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  6. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  7. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  8. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  9. (function poll() { new Ajax.Request('/api/', { method: 'get', timeout: 60000,

    onSuccess: function() { // Do something poll(); }, onFailure: function() { // Do something else poll(); } }); }());
  10. ish

  11. var soundAllowed = function (stream) { window.persistAudioStream = stream; var

    audioContent = new AudioContext(); var audioStream = audioContent.createMediaStreamSource( stream ); } var soundNotAllowed = function (error) { h.innerHTML = "You must allow your microphone."; console.log(error); } navigator.getUserMedia({audio:true}, soundAllowed, soundNotAllowed);
  12. var soundAllowed = function (stream) { window.persistAudioStream = stream; var

    audioContent = new AudioContext(); var audioStream = audioContent.createMediaStreamSource( stream ); } var soundNotAllowed = function (error) { h.innerHTML = "You must allow your microphone."; console.log(error); } navigator.getUserMedia({audio:true}, soundAllowed, soundNotAllowed);
  13. var soundAllowed = function (stream) { window.persistAudioStream = stream; var

    audioContent = new AudioContext(); var audioStream = audioContent.createMediaStreamSource( stream ); } var soundNotAllowed = function (error) { h.innerHTML = "You must allow your microphone."; console.log(error); } navigator.getUserMedia({audio:true}, soundAllowed, soundNotAllowed);
  14. var soundAllowed = function (stream) { window.persistAudioStream = stream; var

    audioContent = new AudioContext(); var audioStream = audioContent.createMediaStreamSource( stream ); } var soundNotAllowed = function (error) { h.innerHTML = "You must allow your microphone."; console.log(error); } navigator.getUserMedia({audio:true}, soundAllowed, soundNotAllowed);
  15. def proxy(self): return [ { 'action': 'connect', 'eventUrl': [f'{self.base_url}/events'], 'from':

    os.environ['NEXMO_NUMBER'], 'endpoint': [ { 'type': 'websocket', 'uri': f'{os.environ["WEBSOCKET_SERVER_URL"]}/socket', 'content-type': 'audio/l16;rate=16000', 'headers': {} } ] } ]
  16. def proxy(self): return [ { 'action': 'connect', 'eventUrl': [f'{self.base_url}/events'], 'from':

    os.environ['NEXMO_NUMBER'], 'endpoint': [ { 'type': 'websocket', 'uri': f'{os.environ["WEBSOCKET_SERVER_URL"]}/socket', 'content-type': 'audio/l16;rate=16000', 'headers': {} } ] } ]
  17. def proxy(self): return [ { 'action': 'connect', 'eventUrl': [f'{self.base_url}/events'], 'from':

    os.environ['NEXMO_NUMBER'], 'endpoint': [ { 'type': 'websocket', 'uri': f'{os.environ["WEBSOCKET_SERVER_URL"]}/socket', 'content-type': 'audio/l16;rate=16000', 'headers': {} } ] } ]
  18. def on_message(self, message): transcriber = yield self.transcriber if type(message) !=

    str: transcriber.write_message(message, binary=True) else: logger.info(message) data = json.loads(message) data['action'] = "start" data['continuous'] = True data['interim_results'] = True transcriber.write_message(json.dumps(data), binary=False)
  19. def on_message(self, message): transcriber = yield self.transcriber if type(message) !=

    str: transcriber.write_message(message, binary=True) else: logger.info(message) data = json.loads(message) data['action'] = "start" data['continuous'] = True data['interim_results'] = True transcriber.write_message(json.dumps(data), binary=False)
  20. def on_message(self, message): transcriber = yield self.transcriber if type(message) !=

    str: transcriber.write_message(message, binary=True) else: logger.info(message) data = json.loads(message) data['action'] = "start" data['continuous'] = True data['interim_results'] = True transcriber.write_message(json.dumps(data), binary=False)
  21. def on_message(self, message): transcriber = yield self.transcriber if type(message) !=

    str: transcriber.write_message(message, binary=True) else: logger.info(message) data = json.loads(message) data['action'] = "start" data['continuous'] = True data['interim_results'] = True transcriber.write_message(json.dumps(data), binary=False)
  22. def on_transcriber_message(self, message): if message: message = json.loads(message) if 'results'

    in message: transcript = message['transcript'] tone_results = self.tone_analyzer.tone( tone_input=transcript, content_type="text/plain" ) tones = tone_results['tones'] DashboardHandler.send_updates(json.dumps(tones))
  23. def on_transcriber_message(self, message): if message: message = json.loads(message) if 'results'

    in message: transcript = message['transcript'] tone_results = self.tone_analyzer.tone( tone_input=transcript, content_type="text/plain" ) tones = tone_results['tones'] DashboardHandler.send_updates(json.dumps(tones))
  24. def on_transcriber_message(self, message): if message: message = json.loads(message) if 'results'

    in message: transcript = message['transcript'] tone_results = self.tone_analyzer.tone( tone_input=transcript, content_type="text/plain" ) tones = tone_results['tones'] DashboardHandler.send_updates(json.dumps(tones))
  25. def on_transcriber_message(self, message): if message: message = json.loads(message) if 'results'

    in message: transcript = message['transcript'] tone_results = self.tone_analyzer.tone( tone_input=transcript, content_type="text/plain" ) tones = tone_results['tones'] DashboardHandler.send_updates(json.dumps(tones))
  26. def on_transcriber_message(self, message): if message: message = json.loads(message) if 'results'

    in message: transcript = message['transcript'] tone_results = self.tone_analyzer.tone( tone_input=transcript, content_type="text/plain" ) tones = tone_results['tones'] DashboardHandler.send_updates(json.dumps(tones))
  27. class DashboardHandler(tornado.websocket.WebSocketHandler): waiters = set() def open(self): DashboardHandler.waiters.add(self) def on_close(self):

    DashboardHandler.waiters.remove(self) @classmethod def send_updates(cls, tones): for waiter in cls.waiters: try: waiter.write_message(tones) except: pass
  28. class DashboardHandler(tornado.websocket.WebSocketHandler): waiters = set() def open(self): DashboardHandler.waiters.add(self) def on_close(self):

    DashboardHandler.waiters.remove(self) @classmethod def send_updates(cls, tones): for waiter in cls.waiters: try: waiter.write_message(tones) except: pass
  29. class DashboardHandler(tornado.websocket.WebSocketHandler): waiters = set() def open(self): DashboardHandler.waiters.add(self) def on_close(self):

    DashboardHandler.waiters.remove(self) @classmethod def send_updates(cls, tones): for waiter in cls.waiters: try: waiter.write_message(tones) except: pass
  30. class DashboardHandler(tornado.websocket.WebSocketHandler): waiters = set() def open(self): DashboardHandler.waiters.add(self) def on_close(self):

    DashboardHandler.waiters.remove(self) @classmethod def send_updates(cls, tones): for waiter in cls.waiters: try: waiter.write_message(tones) except: pass
  31. var emotions = { anger: new TimeSeries(), disgust: new TimeSeries(),

    fear: new TimeSeries(), joy: new TimeSeries(), sadness: new TimeSeries() }
  32. var websocket = new WebSocket('{{ server_url }}/dashboard-socket'); websocket.onmessage = function(evt)

    { JSON.parse(evt.data).map(function(emotion){ emotions[emotion.tone_id].append( new Date().getTime(), emotion.score ) }); }
  33. var websocket = new WebSocket('{{ server_url }}/dashboard-socket'); websocket.onmessage = function(evt)

    { JSON.parse(evt.data).map(function(emotion){ emotions[emotion.tone_id].append( new Date().getTime(), emotion.score ) }); }
  34. var websocket = new WebSocket('{{ server_url }}/dashboard-socket'); websocket.onmessage = function(evt)

    { JSON.parse(evt.data).map(function(emotion){ emotions[emotion.tone_id].append( new Date().getTime(), emotion.score ) }); }
  35. var websocket = new WebSocket('{{ server_url }}/dashboard-socket'); websocket.onmessage = function(evt)

    { JSON.parse(evt.data).map(function(emotion){ emotions[emotion.tone_id].append( new Date().getTime(), emotion.score ) }); }