It is so frustrating. I want to create simple speech to text app, but I have problems with the connection. I am able to get the token, but then something is wrong, here are the screens:handshake error, http error. First I tried to follow this youtube guy, but his code doesn't work. Then I tried to follow the docs, watson-speech npm and ibm-watson npm, but now I'm stuck.
I'm getting the token, but then I can't go further, I'm using the server.js and App.js to achieve this goal and here is the code:
server.js
'use strict';
const express = require('express');
const app = express();
const vcapServices = require('vcap_services');
const cors = require('cors');
const { IamTokenManager } = require('ibm-watson/auth');
if (process.env.VCAP_SERVICES) {
// enable rate-limiting
const RateLimit = require('express-rate-limit');
app.enable('trust proxy'); // required to work properly behind Bluemix's reverse proxy
const limiter = new RateLimit({
windowMs: 30000, // 0.5 minute
max: 100 // limit each IP to 100 requests per windowMs
});
// apply to /api/*
app.use('/api/', limiter);
const secure = require('express-secure-only');
app.use(secure());
}
// app.use(express.static(__dirname + '/static'));
app.use(cors())
const sttAuthenticator = new IamTokenManager(
{
apikey: 'knkk_???_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm'
}
);
// speech to text token endpoint
app.use('/api/speech-to-text/token', function(req, res) {
return sttAuthenticator
.requestToken()
.then(({ result }) => {
res.json({ accessToken: result.access_token, url: 'https://stream.watsonplatform.net/speech-to-text/knkk_???_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm' });
})
.catch(console.error);
});
const port = process.env.PORT || process.env.VCAP_APP_PORT || 3002;
app.listen(port, function() {
console.log('Example IBM Watson Speech JS SDK client app & token server live at http://localhost:%s/', port);
});
// Chrome requires https to access the user's microphone unless it's a localhost url so
// this sets up a basic server on port 3001 using an included self-signed certificate
// note: this is not suitable for production use
// however bluemix automatically adds https support at https://<myapp>.mybluemix.net
if (!process.env.VCAP_SERVICES) {
const fs = require('fs');
const https = require('https');
const HTTPS_PORT = 3001;
const options = {
key: fs.readFileSync(__dirname + '/keys/localhost.pem'),
cert: fs.readFileSync(__dirname + '/keys/localhost.cert')
};
https.createServer(options, app).listen(HTTPS_PORT, function() {
console.log('Secure server live at https://localhost:%s/', HTTPS_PORT);
});
}
App.js
import React, { Component } from 'react';
import './App.css';
import recognizeMic from 'watson-speech/speech-to-text/recognize-microphone';
import WatsonSpeech from 'watson-speech/dist/watson-speech';
class App extends Component {
constructor() {
super()
this.state = {
}
}
onListenClick() {
fetch('http://localhost:3002/api/speech-to-text/token')
.then(function(response) {
return response.text();
}).then((token) => {
console.log('token is', token)
var stream = recognizeMic({
token: token,
objectMode: true, // send objects instead of text
extractResults: true, // convert {results: [{alternatives:[...]}], result_index: 0} to {alternatives: [...], index: 0}
format: false // optional - performs basic formatting on the results such as capitals an periods
});
stream.on('data', (data) => {
this.setState({
text: data.alternatives[0].transcript
})
});
stream.on('error', function(err) {
console.log(err);
});
document.querySelector('#stop').onclick = stream.stop.bind(stream);
}).catch(function(error) {
console.log(error);
});
}
render() {
return (
<div className="App">
<button onClick={this.onListenClick.bind(this)}>Start</button>
<div style={{fontSize: '40px'}}>{this.state.text}</div>
</div>
);
}
}
export default App;
and I'm getting the handshake error when I change the stream variable to this:
var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(Object.assign(token, {
objectMode: true, // send objects instead of text
format: false // optional - performs basic formatting on the results such as capitals an periods
})
After changing to the IamAuthenticator and using the API reference I still can't use it in the terminal. In meanwhile I have tried the Google speech to text and it works:on the left google, on the right ibm.
Can you see any errors in my code?
'use strict';
// Node-Record-lpcm16
const recorder = require('node-record-lpcm16');
const SpeechToTextV1 = require('ibm-watson/speech-to-text/v1');
const { IamAuthenticator } = require('ibm-watson/auth');
const speechToText = new SpeechToTextV1({
authenticator: new IamAuthenticator({
apikey: 'knkk_O4nfg_XjW7C9p4DUxlk6p1B9-rez8gJykyh-rYm',
}),
url: 'https://api.eu-gb.speech-to-text.watson.cloud.ibm.com/instances/c7572958-6b9c-4215-943f-7ff935bb0037',
});
const params = {
objectMode: true,
contentType: 'audio/flac',
model: 'en-US_BroadbandModel',
keywords: ['turn on', 'turn off', 'on', 'off'],
keywordsThreshold: 0.5,
maxAlternatives: 3,
headers: 'chunked'
};
// Create the stream.
const recognizeStream = speechToText.recognizeUsingWebSocket(params);
// Listen for events.
recognizeStream.on('data', function(event) { onEvent('Data:', event); });
recognizeStream.on('error', function(event) { onEvent('Error:', event); });
recognizeStream.on('close', function(event) { onEvent('Close:', event); });
// Display events on the console.
function onEvent(name, event) {
console.log(name, JSON.stringify(event, null, 2));
};
// Start recording and send the microphone input to the Speech API
recorder
.record({
sampleRateHertz: 16000,
threshold: 0, //silence threshold
recordProgram: 'rec', // Try also "arecord" or "sox"
silence: '5.0', //seconds of silence before ending
})
.stream()
.on('error', console.error)
.pipe(recognizeStream);
Support for the token parameter has been removed in version 5. Use
IamAuthenticator
.Take a look at the MIGRATION doc and the API reference example