Skip to content

Commit

Permalink
Live transcription support
Browse files Browse the repository at this point in the history
Summary:
* emits `partialTranscription` and `fullTranscription` events for `speech()`
* `interactive` integration
* for simplicity, dup the response handler into 2 promises so we don't have to set up timeouts waiting for a final payload before resolving
* showing microphone input feedback in `interactive`
* including proxy support for `speech()`

Reviewed By: ruoyipu

Differential Revision: D34938698

fbshipit-source-id: ec0ac55c8778be8aff4de8b38c6a840f663ca28b
  • Loading branch information
patapizza authored and facebook-github-bot committed Mar 17, 2022
1 parent f38e392 commit 9fff4f4
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v6.2.1

- Emits `partialTranscription` and `fullTranscription` events.
- Shows microphone input feedback for `interactive`.
- Includes `proxy` support for `speech()`.

## v6.2.0

Requires Node.js >= 6.17.1 to support ES6 directly.
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ Takes the following paramters:
- `context` - (optional) the [Context](https://wit.ai/docs/http/#context_link) object
- `n` - (optional) the max number of intents and traits to get back

Emits `partialTranscription` and `fullTranscription` events.
The Promise returns the final JSON payload.

See `lib/interactive.js` for an example.

### interactive
Expand Down
8 changes: 8 additions & 0 deletions lib/interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ module.exports = (wit, handleResponse, context) => {
prompt();
};

wit.on('partialTranscription', text => {
console.log(text + '...');
});
wit.on('fullTranscription', text => {
console.log(text + ' (final)');
});

rl.on('line', line => {
line = line.trim();
if (!line) {
Expand Down Expand Up @@ -72,6 +79,7 @@ module.exports = (wit, handleResponse, context) => {
});

microphone.start();
console.log('🎤 Listening...');

return;
}
Expand Down
58 changes: 47 additions & 11 deletions lib/wit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
const {DEFAULT_API_VERSION, DEFAULT_WIT_URL} = require('./config');
const log = require('./log');
const fetch = require('isomorphic-fetch');
const Url = require('url');
const EventEmitter = require('events');
const HttpsProxyAgent = require('https-proxy-agent');
const {Readable} = require('stream');
const Url = require('url');

class Wit {
class Wit extends EventEmitter {
constructor(opts) {
super();
this.config = Object.freeze(validate(opts));
}

Expand Down Expand Up @@ -76,23 +78,51 @@ class Wit {
const fullURL = witURL + '/speech?' + encodeURIParams(params);
logger.debug(method, fullURL);

return fetch(fullURL, {
const req = fetch(fullURL, {
body,
method,
proxy,
headers: {
...headers,
'Content-Type': contentType,
'Transfer-Encoding': 'chunked',
},
})
});

const _partialResponses = req
.then(
response =>
new Promise((resolve, reject) => {
logger.debug('status', response.status);
const bodyStream = response.body;
bodyStream.on('readable', () => {
let chunk;
let contents = '';
while (null !== (chunk = bodyStream.read())) {
contents += chunk.toString();
}
for (const {error, intents, text} of splitHttpChunks(
contents,
).map(x => JSON.parse(x))) {
if (!(error || intents)) {
logger.debug('[speech] partialTranscription:', text);
this.emit('partialTranscription', text);
} else if (text) {
logger.debug('[speech] fullTranscription:', text);
this.emit('fullTranscription', text);
}
}
});
}),
)
.catch(e => logger.error('[speech] could not parse partial response', e));

return req
.then(response => Promise.all([response.text(), response.status]))
.then(([contents, status]) => {
const chunks = contents
.split('\r\n')
.map(x => x.trim())
.filter(x => x.length > 0);
return [JSON.parse(chunks[chunks.length - 1]), status];
})
.then(([contents, status]) => [
JSON.parse(splitHttpChunks(contents).pop()),
status,
])
.catch(e => e)
.then(makeWitResponseHandler(logger, 'speech'));
}
Expand Down Expand Up @@ -147,6 +177,12 @@ const encodeURIParams = params =>
.map(([key, value]) => key + '=' + encodeURIComponent(value))
.join('&');

const splitHttpChunks = response =>
response
.split('\r\n')
.map(x => x.trim())
.filter(x => x.length > 0);

const validate = opts => {
if (!opts.accessToken) {
throw new Error(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-wit",
"version": "6.2.0",
"version": "6.2.1",
"description": "Wit.ai Node.js SDK",
"keywords": [
"wit",
Expand Down
1 change: 0 additions & 1 deletion tests/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ module.exports.runTests = wit => {
});

it('tests that Wit has correct functions', () => {
expect(Object.keys(client)).to.eql(['config']);
expect(typeof client.message).to.eql('function');
expect(typeof client.speech).to.eql('function');
});
Expand Down

0 comments on commit 9fff4f4

Please sign in to comment.