node-wit
Advanced tools
Comparing version 6.4.0 to 6.5.0
@@ -6,4 +6,4 @@ /** | ||
module.exports = { | ||
DEFAULT_API_VERSION: 20220608, | ||
DEFAULT_API_VERSION: 20220801, | ||
DEFAULT_WIT_URL: 'https://api.wit.ai', | ||
}; |
@@ -10,7 +10,13 @@ /** | ||
const readline = require('readline'); | ||
const uuid = require('uuid'); | ||
const sessionId = uuid.v4(); | ||
const AUDIO_PATH = '/tmp/output.raw'; | ||
const MIC_TIMEOUT_MS = 3000; | ||
const MSG_PREFIX_COMMAND = '!message'; | ||
module.exports = (wit, handleResponse, context) => { | ||
module.exports = (wit, handleResponse, initContextMap) => { | ||
let contextMap = typeof initContextMap === 'object' ? initContextMap : {}; | ||
const rl = readline.createInterface({ | ||
@@ -29,2 +35,7 @@ input: process.stdin, | ||
const makeResponseHandler = rsp => { | ||
const {context_map} = rsp; | ||
if (typeof context_map === 'object') { | ||
contextMap = context_map; | ||
} | ||
if (handleResponse) { | ||
@@ -35,5 +46,31 @@ handleResponse(rsp); | ||
} | ||
prompt(); | ||
return rsp; | ||
}; | ||
const openMic = onComplete => { | ||
const microphone = mic({ | ||
bitwidth: '16', | ||
channels: '1', | ||
encoding: 'signed-integer', | ||
endian: 'little', | ||
fileType: 'raw', | ||
rate: '16000', | ||
}); | ||
const inputAudioStream = microphone.getAudioStream(); | ||
const outputFileStream = fs.WriteStream(AUDIO_PATH); | ||
inputAudioStream.pipe(outputFileStream); | ||
inputAudioStream.on('startComplete', () => { | ||
setTimeout(() => { | ||
microphone.stop(); | ||
}, MIC_TIMEOUT_MS); | ||
}); | ||
inputAudioStream.on('stopComplete', () => onComplete()); | ||
microphone.start(); | ||
console.log('🎤 Listening...'); | ||
}; | ||
wit.on('partialTranscription', text => { | ||
@@ -48,2 +85,5 @@ console.log(text + '...'); | ||
}); | ||
wit.on('response', ({text}) => { | ||
console.log('< ' + text); | ||
}); | ||
@@ -56,23 +96,30 @@ rl.on('line', line => { | ||
// POST /converse | ||
if (line === '!converse') { | ||
const onComplete = () => { | ||
const stream = fs.ReadStream(AUDIO_PATH); | ||
wit | ||
.runComposerAudio( | ||
sessionId, | ||
'audio/raw;encoding=signed-integer;bits=16;rate=16000;endian=little', | ||
stream, | ||
contextMap, | ||
) | ||
.then(makeResponseHandler) | ||
.then(({expects_input}) => { | ||
if (expects_input) { | ||
openMic(onComplete); | ||
} else { | ||
prompt(); | ||
} | ||
}) | ||
.catch(console.error); | ||
}; | ||
return openMic(onComplete); | ||
} | ||
// POST /speech | ||
if (line === '!speech') { | ||
const microphone = mic({ | ||
bitwidth: '16', | ||
channels: '1', | ||
encoding: 'signed-integer', | ||
endian: 'little', | ||
fileType: 'raw', | ||
rate: '16000', | ||
}); | ||
const inputAudioStream = microphone.getAudioStream(); | ||
const outputFileStream = fs.WriteStream(AUDIO_PATH); | ||
inputAudioStream.pipe(outputFileStream); | ||
inputAudioStream.on('startComplete', () => { | ||
setTimeout(() => { | ||
microphone.stop(); | ||
}, MIC_TIMEOUT_MS); | ||
}); | ||
inputAudioStream.on('stopComplete', () => { | ||
const onComplete = () => { | ||
const stream = fs.ReadStream(AUDIO_PATH); | ||
@@ -83,17 +130,26 @@ wit | ||
stream, | ||
context, | ||
) | ||
.then(makeResponseHandler) | ||
.then(prompt) | ||
.catch(console.error); | ||
}); | ||
}; | ||
return openMic(onComplete); | ||
} | ||
microphone.start(); | ||
console.log('🎤 Listening...'); | ||
return; | ||
if (line.startsWith(MSG_PREFIX_COMMAND)) { | ||
// GET /message | ||
return wit | ||
.message(line.slice(MSG_PREFIX_COMMAND.length)) | ||
.then(makeResponseHandler) | ||
.then(prompt) | ||
.catch(console.error); | ||
} | ||
// GET /message | ||
wit.message(line, context).then(makeResponseHandler).catch(console.error); | ||
// POST /event | ||
wit | ||
.runComposer(sessionId, contextMap, line) | ||
.then(makeResponseHandler) | ||
.then(prompt) | ||
.catch(console.error); | ||
}); | ||
}; |
191
lib/wit.js
@@ -23,2 +23,129 @@ /** | ||
runComposer(sessionId, contextMap, message) { | ||
return this.event(sessionId, contextMap, message).then( | ||
this.makeComposerHandler(sessionId), | ||
); | ||
} | ||
runComposerAudio(sessionId, contentType, body, contextMap) { | ||
return this.converse(sessionId, contentType, body, contextMap).then( | ||
this.makeComposerHandler(sessionId), | ||
); | ||
} | ||
converse(sessionId, contentType, body, contextMap) { | ||
if (typeof sessionId !== 'string') { | ||
throw new Error('Please provide a session ID (string).'); | ||
} | ||
if (typeof contentType !== 'string') { | ||
throw new Error('Please provide a content-type (string).'); | ||
} | ||
if (!body instanceof Readable) { | ||
throw new Error('Please provide an audio stream (Readable).'); | ||
} | ||
const {apiVersion, headers, logger, proxy, witURL} = this.config; | ||
const params = { | ||
session_id: sessionId, | ||
v: apiVersion, | ||
}; | ||
if (typeof contextMap === 'object') { | ||
params.context_map = JSON.stringify(contextMap); | ||
} | ||
const method = 'POST'; | ||
const fullURL = witURL + '/converse?' + encodeURIParams(params); | ||
logger.debug(method, 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 rsp of parseResponse(contents)) { | ||
const {error, is_final, text} = rsp; | ||
// Live transcription | ||
if (!(error || is_final)) { | ||
logger.debug('[converse] partialTranscription:', text); | ||
this.emit('partialTranscription', text); | ||
} | ||
} | ||
}); | ||
}), | ||
) | ||
.catch(e => | ||
logger.error('[converse] could not parse partial response', e), | ||
); | ||
return req | ||
.then(response => Promise.all([response.text(), response.status])) | ||
.then(([contents, status]) => { | ||
const finalResponse = parseResponse(contents).pop(); | ||
const {text} = finalResponse; | ||
logger.debug('[converse] fullTranscription:', text); | ||
this.emit('fullTranscription', text); | ||
return [finalResponse, status]; | ||
}) | ||
.catch(e => e) | ||
.then(makeWitResponseHandler(logger, 'converse')); | ||
} | ||
event(sessionId, contextMap, message) { | ||
if (typeof sessionId !== 'string') { | ||
throw new Error('Please provide a session ID (string).'); | ||
} | ||
const {apiVersion, headers, logger, proxy, witURL} = this.config; | ||
const params = { | ||
session_id: sessionId, | ||
v: apiVersion, | ||
}; | ||
if (typeof contextMap === 'object') { | ||
params.context_map = JSON.stringify(contextMap); | ||
} | ||
const body = {}; | ||
if (typeof message === 'string') { | ||
body.type = 'message'; | ||
body.message = message; | ||
} | ||
const method = 'POST'; | ||
const fullURL = witURL + '/event?' + encodeURIParams(params); | ||
logger.debug(method, fullURL); | ||
return fetch(fullURL, {body: JSON.stringify(body), method, headers, proxy}) | ||
.then(response => Promise.all([response.json(), response.status])) | ||
.then(makeWitResponseHandler(logger, 'event')); | ||
} | ||
message(q, context, n) { | ||
@@ -104,2 +231,3 @@ if (typeof q !== 'string') { | ||
const bodyStream = response.body; | ||
bodyStream.on('readable', () => { | ||
@@ -194,3 +322,3 @@ let chunk; | ||
// Live transcription | ||
if (!(error)) { | ||
if (!error) { | ||
if (!is_final) { | ||
@@ -200,3 +328,6 @@ logger.debug('[dictation] partial transcription:', text); | ||
} else { | ||
logger.debug('[dictation] full sentence transcription:', text); | ||
logger.debug( | ||
'[dictation] full sentence transcription:', | ||
text, | ||
); | ||
this.emit('fullTranscription', text); | ||
@@ -209,3 +340,5 @@ } | ||
) | ||
.catch(e => logger.error('[dictation] could not parse partial response', e)); | ||
.catch(e => | ||
logger.error('[dictation] could not parse partial response', e), | ||
); | ||
@@ -227,3 +360,10 @@ return req | ||
synthesize(q, voice, style = "default", speed = 100, pitch = 100, gain = 100) { | ||
synthesize( | ||
q, | ||
voice, | ||
style = 'default', | ||
speed = 100, | ||
pitch = 100, | ||
gain = 100, | ||
) { | ||
if (typeof q !== 'string') { | ||
@@ -249,3 +389,3 @@ throw new Error('Please provide a text input (string).'); | ||
gain: gain, | ||
} | ||
}; | ||
@@ -268,4 +408,41 @@ const method = 'POST'; | ||
} | ||
makeComposerHandler(sessionId) { | ||
const {actions, logger} = this.config; | ||
return ({context_map, action, expects_input, response}) => { | ||
if (typeof context_map !== 'object') { | ||
throw new Error( | ||
'Unexpected context_map in API response: ' + | ||
JSON.stringify(context_map), | ||
); | ||
} | ||
if (response) { | ||
logger.debug('[composer] response:', response); | ||
this.emit('response', response); | ||
} | ||
if (action) { | ||
logger.debug('[composer] got action', action); | ||
return runAction(logger, actions, action, context_map).then( | ||
({context_map, stop}) => { | ||
if (expects_input && !stop) { | ||
return this.runComposer(sessionId, context_map); | ||
} | ||
return {context_map}; | ||
}, | ||
); | ||
} | ||
return {context_map, expects_input}; | ||
}; | ||
} | ||
} | ||
const runAction = (logger, actions, name, ...rest) => { | ||
logger.debug('Running action', name); | ||
return Promise.resolve(actions[name](...rest)); | ||
}; | ||
const makeWitResponseHandler = (logger, endpoint) => rsp => { | ||
@@ -355,2 +532,6 @@ const error = e => { | ||
if (opts.actions && typeof opts.actions !== 'object') { | ||
throw new Error('Please provide actions mapping (string -> function).'); | ||
} | ||
return opts; | ||
@@ -357,0 +538,0 @@ }; |
{ | ||
"name": "node-wit", | ||
"version": "6.4.0", | ||
"version": "6.5.0", | ||
"description": "Wit.ai Node.js SDK", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
38398
10
1198
14
15