IBM Watson TextToSpeech - cannot read property .pipe of undefined - text-to-speech

I have the following code, straight from the documentation:
var TextToSpeechV1 = require('watson-developer-cloud/text-to-
speech/v1');
var fs = require('fs');
var textToSpeech = new TextToSpeechV1({
iam_apikey: '---myapikey---',
url: 'https://stream.watsonplatform.net/text-to-speech/api/'
});
var synthesizeParams = {
text: 'Hello world, you dummy ass',
accept: 'audio/wav',
voice: 'en-US_AllisonVoice'
};
// Pipe the synthesized text to a file.
textToSpeech.synthesize(synthesizeParams).on('error', function(error) {
console.log(error);
}).pipe(fs.createWriteStream('hello_world.wav'));
when I run it it gives the following error:
pi#raspberrypi:~/Desktop/tjbotcz_lite $ sudo node ttstest.js
/home/pi/Desktop/tjbotcz_lite/ttstest.js:16
textToSpeech.synthesize(synthesizeParams).on('error', function(error) {
^
TypeError: Cannot read property 'on' of undefined
at Object.<anonymous> (/home/pi/Desktop/tjbotcz_lite/ttstest.js:16:42)
at Module._compile (internal/modules/cjs/loader.js:654:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
at Module.load (internal/modules/cjs/loader.js:566:32)
at tryModuleLoad (internal/modules/cjs/loader.js:506:12)
at Function.Module._load (internal/modules/cjs/loader.js:498:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:695:10)
at startup (internal/bootstrap/node.js:201:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:516:3)
Any clues why? I have the same issue with TJBot, so I tried a simple example from documentation and voila - the same error.
When I use my old service (with username and password, not api key) it works fine. I have the new version of watson-cloud library (3.13.1).
Thanks for any hints.
Regards,
Jan.

I looked here for help but the docs there are definitely wrong. I was able to solve this by using audio.result.pipe(fs.createWriteStream('audio.wav')

I implemented this using promises so I can wait for the audio file to be completely saved and then do further processing. Also, as others stated, the documentation was wrong and the correct way is to use audio.result.pipe() instead of audio.pipe().
function synthesize_audio(text, mp3Path) {
return new Promise((resolve, reject) => {
console.log(`> Synthesizing audio from text: "${text}"`)
const textToSpeech = new TextToSpeechV1({
authenticator: new IamAuthenticator({
apikey: apikey,
}),
url: apiUrl,
});
const synthesizeParams = {
text: text,
accept: 'audio/mp3',
voice: 'pt-BR_IsabelaV3Voice',
};
textToSpeech.synthesize(synthesizeParams)
.then(audio => {
audio.result
.pipe(fs.createWriteStream(mp3Path))
.on('finish', resolve)
.on('error', reject);
})
.catch(err => {
console.log('error:', err);
});
});
}
You can then await and do what you want:
await synthesize_audio(text, outputPath)
.then(() => {
//then you can safely do what you want
})
}

The below code works for me and generating an audio.wav file using the Text-to-Speech API Key
var TextToSpeechV1 = require('watson-developer-cloud/text-to-speech/v1');
var fs = require('fs');
var textToSpeech = new TextToSpeechV1({
iam_apikey: '<API_KEY>',
url: 'https://stream.watsonplatform.net/text-to-speech/api'
});
var synthesizeParams = {
text: 'Hello world',
accept: 'audio/wav',
voice: 'en-US_AllisonVoice'
};
textToSpeech
.synthesize(synthesizeParams, function(err, audio) {
if (err) {
console.log(err);
return;
}
textToSpeech.repairWavHeader(audio);
fs.writeFileSync('audio.wav', audio);
console.log('audio.wav written with a corrected wav header');
});
Updated the code snippet and this works

Related

Pouch Couch DB error when sync and replicate

I am currently having a problem trying to sync or replicate the data from PouchDB to CouchDB. Whenever I try to sync or replicate I always get this error.
Cannot read properties of undefined (reading 'from').
Here is my code:
function openDB() {
return new PouchDB('cows.db', { adapter: 'react-native-sqlite' });
}
function openRemoteDB() {
return new PouchDB('http://admin:asdasd#127.0.0.1:5984/cows');
}
const runPouchDB = async () => {
const db = openDB();
console.log('db info:', await db.info());
const remotedb = openRemoteDB();
console.log('remote db info:', await remotedb.info());
db.replicate.to(remotedb, {})
.on('complete', async () => {
console.log('done!');
})
.on('error', function (err) {
console.error('failed to replicate:', err.message, err.stack);
});
db.sync(remotedb).on('complete', function () {
console.log('done');
// yay, we're in sync!
}).on('error', function (err) {
console.log('error', err);
// boo, we hit an error!
});
}
React.useEffect(() => {
runPouchDB().then(() => console.log('connected'));
}, [])
both approach always return an error. Not sure if it is a package issue or something I did wrong.
UPDATE:
Based on the example it is looking for global.base64FromArrayBuffer but base64FromArrayBuffer does not exist in my global context.
https://github.com/craftzdog/pouchdb-react-native/blob/138f3d6385238e5cf278366d0fb3d0434abbdced/example/src/App.js#L71
Not sure how to add since since I already added the shim which I though would fix the issue.
import { shim as shimBase64 } from 'react-native-quick-base64';
shimBase64();

How to access SEA module in GUNJS without using dynamic require in React Native expo

So I've started this new project using React Native(Expo), and I've imported all packages including GunJS and SEA, however, when I run the app, I get the error that dynamic require is not supported by Metro. I checked the sea.js file and found that the devs use require(arg), which is not supported by React Native. This is a huge bummer and I haven't found any workaround. Is there any other way to access SEA?
import GUN from "gun";
import "gun/sea";
import { userContext } from "../global";
export const gun = GUN();
The below snippet is the sea.js file, which uses dynamic require.
/* UNBUILD */
function USE(arg, req){
return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
arg(mod = {exports: {}});
USE[R(path)] = mod.exports;
}
We got this fixed in the latest GitHub main (hopefully published soon).
Thanks to Aethiop! Who also wrote a great tutorial on this:
https://github.com/aethiop/jot
if you need to use SEA in react-native now without wait the gun community to fix this problem do this build API with nodejs and install gun in after going in your react-native app call this API
see ex:
//nodejs that manage sea so in my case I use auth feature sea
const fastify = require("fastify")();
const Gun = require('gun'); // in NodeJS
require('./sea/sae');
const gun = new Gun ({
peers: ['https://gun-serve.herokuapp.com/gun'],
})
const user = gun.user()
const ADDRESS = "0.0.0.0";
const PORT = process.env.PORT || 3000;
fastify.get("/", function (req, reply) {
reply.send("wellcome");
});
fastify.post('/userregist', async (request, reply) => {
try {
user.create(`${request.body.user}`,`${request.body.password}`, ({ err , pub}) => {
if (err) {
return reply.code(200).send({ "err": `${err}`})
} else {
return reply.code(200).send({"pub": `${pub}`})
}
});
} catch (error) {
request.log.error(error);
return reply.send(500);
}
})
fastify.post('/userlogin', async (request, reply) => {
try{
user.auth(`${request.body.user}`,`${request.body.password}`, ({ err, get, }) => {
if (err) {
return reply.code(200).send({ "err": `${err}`})
} else {
console.log('joshau get', get)
return reply.code(200).send({"pub": `${get}`})
}
});
} catch (error) {
request.log.error(error);
return reply.send(500);
}
})
fastify.listen(PORT, ADDRESS, (err, address) => {
if (err) {
console.log(err);
process.exit(1);
}
});
so i call api my app like that:
//my call api
const loginRequest = async (email, password) => {
try {
return await fetch('https://locahost:3000/userlogin', {
mode: 'no-cors', method: 'POST',
headers: {
'Content-type': 'application/json',
'Accept': ' application/json'
},
body: JSON.stringify({
user: email,
password: password,
}),
})
} catch (error) {
return error;
}
};
// here is way i call it i comp
LoginRequest(email, password)
.then((res)=> {
res.json().then(function (text) {
if(text.err){
LOADING_STOP()
alert(`${text.err}`)
console.log('error message',text.err)
}else{
console.log('public key',text.pub)
LOADING_STOP()
navigation.replace("Dashboard");
}
}).catch((e)=> {
LOADING_STOP()
alert(e)
})
put import shim from "gun/lib/mobile"
at the top of your file. (before the SEA import) :D !
import shim from "gun/lib/mobile"
import SEA from 'gun/sea'

Axios interceptors don't send data to API in production Heroku app

This is part 2 of me debugging my application in production
In part 1, I managed to at least see what was causing my problem and managed to solve that.
When I send a request to my API which is hosted on Heroku using axios interceptor, every single request object looks like this in the API
{ 'object Object': '' }
Before sending out data to the API, I console.log() the transformRequest in axios and I can see that the data I am sending is actually there.
Note: I have tested this process simply using
axios.<HTTP_METHOD>('my/path', myData)
// ACTUAL EXAMPLE
await axios.post(
`${process.env.VUE_APP_BASE_URL}/auth/login`,
userToLogin
);
and everything works and I get data back from the server.
While that is great and all, I would like to abstract my request implementation into a separate class like I did below.
Does anyone know why the interceptor is causing this issue? Am I misusing it?
request.ts
import axios from "axios";
import { Message } from "element-ui";
import logger from "#/plugins/logger";
import { UsersModule } from "#/store/modules/users";
const DEBUG = process.env.NODE_ENV === "development";
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_URL,
timeout: 5000,
transformRequest: [function (data) {
console.log('data', data)
return data;
}],
});
service.interceptors.request.use(
config => {
if (DEBUG) {
logger.request({
method: config.method,
url: config.url
});
}
return config;
},
error => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
console.log('axios interception response', response)
return response.data;
},
error => {
const { response } = error;
console.error('axios interception error', error)
if (DEBUG) {
logger.error(response.data.message, response);
}
Message({
message: `Error: ${response.data.message}`,
type: "error",
duration: 5 * 1000
});
return Promise.reject({ ...error });
}
);
export default service;
Login.vue
/**
* Sign user in
*/
async onClickLogin() {
const userToLogin = {
username: this.loginForm.username,
password: this.loginForm.password
};
try {
const res = await UsersModule.LOGIN_USER(userToLogin);
console.log("res", res);
this.onClickLoginSuccess();
} catch (error) {
throw new Error(error);
}
}
UsersModule (VUEX Store)
#Action({ rawError: true })
async [LOGIN_USER](params: UserSubmitLogin) {
const response: any = await login(params);
console.log('response in VUEX', response)
if (typeof response !== "undefined") {
const { accessToken, username, name, uid } = response;
setToken(accessToken);
this.SET_UID(uid);
this.SET_TOKEN(accessToken);
this.SET_USERNAME(username);
this.SET_NAME(name);
}
}
users api class
export const login = async (data: UserSubmitLogin) => {
return await request({
url: "/auth/login",
method: "post",
data
});
};
I'm not sure what you're trying to do with transformRequest but that probably isn't what you want.
A quote from the documentation, https://github.com/axios/axios#request-config:
The last function in the array must return a string or an instance of Buffer, ArrayBuffer, FormData or Stream
If you just return a normal JavaScript object instead it will be mangled in the way you've observed.
transformRequest is responsible for taking the data value and converting it into something that can actually be sent over the wire. The default implementation does quite a lot of work manipulating the data and setting relevant headers, in particular Content-Type. See:
https://github.com/axios/axios/blob/885ada6d9b87801a57fe1d19f57304c315703079/lib/defaults.js#L31
If you specify your own transformRequest then you are replacing that default, so none of that stuff will happen automatically.
Without knowing what you're trying to do it's difficult to advise further but you should probably use a request interceptor rather than transformRequest for whatever it is you're trying to do.

Dropbox javascript api show error: TypeError: Failed to fetch

I have a problem when uploading file using dropbox api for javacript. Sometime it's done but something it shows error: "TypeError: Failed to fetch" and cannot upload. Can anyone have experience about this error? Thanks in advance.
Here is my page source in Asp.Net:
var dbx = new Dropbox.Dropbox({ accessToken: 'MY_TOKEN' });
var fileInput = document.getElementById('file-upload'); //$('#file-upload');
var filecontent = fileInput.files[0];
var filename = fileInput.files[0].name;//.match(/([^\\\/]+)$/)[0];
if (fileInput.files[0].size < UPLOAD_FILE_SIZE_LIMIT) { // File is smaller than 150 Mb - use filesUpload API
dbx.filesUpload({ path: '/' + filename, contents: filecontent, mode: 'overwrite', autorename: false, mute: false })
.then(function (response) {
alert('success');
console.log(response);
})
.catch(function (error) {
alert(error.name);
console.error(error);
});

Can't access Sails.js app instance in integration tests

I'm trying to write some integration tests in sailsjs. I have a bootstrap.test.js file that lifts my server in a global before as the docs suggest.
In my integration test when I try to pass my sails app to supertest I get an error:
app is not defined
agent = request.agent(app.hooks.http.app);
^
bootstrap.test.js
var Sails = require('sails'),
Barrels = require('barrels'),
app;
before(function(done) {
console.log('Global before hook'); // Never called?
this.timeout(5000);
Sails.lift({
log: {
level: 'error'
},
models: {
connection: 'test',
migrate: 'drop'
}
}, function(err, sails) {
app = sails;
if (err) return done(err);
var barrels = new Barrels();
fixtures = barrels.data;
barrels.populate(function(err) {
done(err, sails);
});
});
});
// Global after hook
after(function (done) {
console.log(); // Skip a line before displaying Sails lowering logs
Sails.lower(done);
});
integration test
var chai = require('chai'),
expect = chai.expect,
request = require('supertest'),
agent = request.agent(app.hooks.http.app);
describe('Species CRUD test', function() {
it('should not allow an unauthenticated user create a species', function(done){
var species = {
scientificName: 'Latin name',
commonName: 'Common name',
taxon: 'Amphibian',
leadOffice: 'Vero Beach',
range: ['Florida', 'Georgia']
};
agent.post('species')
.send(species)
.end(function(err, species) {
expect(err).to.exist;
expect(species).to.not.exist;
done();
});
});
});
I have been trying to make the integration test work for a few days now. This seems to be working fine in my environment. Maybe you can give it a try.
bootstrap.test.js
var Sails = require('sails');
var sails;
before(function(done)
{
Sails.lift({
log: {
level: 'error'
},
connections: {
testDB: {
adapter: 'sails-memory'
}
},
connection: 'testDB',
}, function(err, server)
{
sails = server;
if (err) return done(err);
done(err, sails);
});
});
after(function(done)
{
Sails.lower(done);
});
Test
var request = require('supertest');
it('should return all users', function(done){
request(sails.hooks.http.app)
.get('/user)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res){
// check the response
done();
);
}
I place bootstrap.test.js on the root of my test folder and then use mocha to run the test.
mocha test/bootstrap.test.js test/**/*.test.js
Hope this help.
it seems that since version 3.x of mocha, nodejs global variables capabilities was removed. so if you need it, you should specifically pass it to your environment like that:
mocha --globals global test/bootstrap.test.js test/**/*.test.js
or
in your mocha.opts file :
#test/mocha.opts
--globals global