I am trying to create a website that scrapes a news website and reads it.
For some reason, whenever I am trying to read the actual info of the article, it reads part of it and stops after a few seconds.
important to point out :
I am using chromium.
The text I'm inserting doesn't reach speechSynthesis.speak()
text limit.
My function :
export async function textToSpeech(text) {
new Promise((resolve) => {
let msg = new SpeechSynthesisUtterance();
msg.voice = voices[6];
msg.lang = "en";
msg.text = text;
speechSynthesis.speak(msg);
msg.addEventListener("end", () => {
resolve();
});
});
}
calling the function :
ReadNews(data) {
textToSpeech(data.Title)
.then(textToSpeech(data.Info))
.then(textToSpeech("Would You like me to continue?"))
.then(
ContinueCON.addEventListener("click", () => {
textToSpeech(data.Content);
})
);
};
The first 3 instances (data.title, data.info, and the default message) are all spoken as expected. But on the 4th instance, stops after a few seconds.
Several things I have tried:
I used window.speechSynthesis.speaking right after the sound stopped working, and it printed true(which is very bizarre)
1st Edit (Yet to be solved)
Changed the code by the comments below
export function textToSpeech(text) {
return new Promise((resolve) => {
let msg = new SpeechSynthesisUtterance();
msg.voice = voices[6];
msg.lang = "en";
msg.text = text;
speechSynthesis.cancel(msg);
speechSynthesis.speak(msg);
msg.addEventListener("end", () => {
resolve();
});
});
}
Async was unnecessary and also "clean" the "Speak" queue (by using cancel)
ReadNews(data) {
textToSpeech(data.Title)
.then(() => textToSpeech(data.Info))
.then(() => textToSpeech("Would You like me to continue?"))
.then(() =>
ContinueCON.addEventListener("click", () => {
textToSpeech(data.Content);
})
);
},
};
I invoked the return value immediately instead of waiting for a resolve and then running the next line of text.
Problem is yet to be solved.
I see a couple issues with your code, which are causing the speech to all get queued up right away, without waiting. But speechSynthesis is supposed to handle that automatically, so it's not clear to me how they would cause what you're seeing. Still, i'll point them out in case they're causing your problem in a subtle way that i can't identify.
The first issue is that your textToSpeech function doesn't return the promise it creates. A promise is implicitly returned since it's an async function, but that promise will not wait for the speech to finish. The fix for this is to add a return in (and you can also remove async if you wish, since you're not awaiting anything)
export function textToSpeech(text) {
return new Promise((resolve) => {
let msg = new SpeechSynthesisUtterance();
msg.voice = voices[6];
msg.lang = "en";
msg.text = text;
speechSynthesis.speak(msg);
msg.addEventListener("end", () => {
resolve();
});
});
}
Secondly, ReadNews is not waiting for the promises to finish. .then(textToSpeech(data.Info)) means "immediately call textToSpeech, passing in data.Info, and then whatever it returns pass that into .then". Instead, you want to pass a function into .then, so that the function will be called once the previous promise has resolved:
ReadNews(data) {
textToSpeech(data.Title)
.then(() => textToSpeech(data.Info))
.then(() => textToSpeech("Would You like me to continue?"))
.then(
() => ContinueCON.addEventListener("click", () => {
textToSpeech(data.Content);
})
);
}
Or with async/await:
async ReadNews(data) {
await textToSpeech(data.Title);
await textToSpeech(data.Info);
await textToSpeech("Would you like me to continue?");
ContinueCON.addEventListener("click", () => {
textToSpeech(data.Content);
})
}
Related
I'm writing a test of event emitting in my Solana program as described here: https://github.com/coral-xyz/anchor/blob/master/tests/events/tests/events.js
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.Events;
it("Is initialized!", async () => {
let listener = null;
let [event, slot] = await new Promise((resolve, _reject) => {
listener = program.addEventListener("MyEvent", (event, slot) => {
resolve([event, slot]);
});
program.rpc.initialize();
});
await program.removeEventListener(listener);
assert.isAbove(slot, 0);
assert.strictEqual(event.label, "hello");
});
It works good if the instruction completes successfully. But if any error happens during execution, the test code silently waits forever for event emitting which expectedly doesn't happen.
Can anyone please suggest a way to deal with such exceptions so that they are not "swallowed" and thrown on upper level?
If I understand the issue correctly, you need to add some sort of timeout when waiting for the event, correct? In that case, you should be able to use a setTimeout to check the result of your listener and error if it hasn't fired, ie:
it("Is initialized!", async () => {
let listener = null;
let event = {label: ""};
let slot = 0;
setTimeout(function(){
assert.isAbove(slot, 0);
assert.strictEqual(event.label, "hello");
},5000);
[event, slot] = await new Promise((resolve, _reject) => {
listener = program.addEventListener("MyEvent", (event, slot) => {
resolve([event, slot]);
});
program.rpc.initialize();
});
await program.removeEventListener(listener);
});
I have an open Websocket connection and it's handing out events. All good, but once a new event arrives, I need to do a whole lot of things and sometimes events arrive so quickly one after the other that there is no time to get the stuff done properly. I need some sort of queue inside this function that tells the events to take it easy and only keep going at most one per second, and otherwise wait in some sort of queue until the second elapses to go ahead and continue.
edit: No external libraries allowed, unfortunately.
ws = new WebSocket(`wss://hallo.com/ws/`);
ws.onmessage = readMessage;
async function readMessage(event) {
print(event)
//do important things
//but not too frequently!
}
How do I do that?
I found this but it goes over my simple head:
"You can have a queue-like promise that keeps on accumulating promises to make sure they run sequentially:
let cur = Promise.resolve();
function enqueue(f) {
cur = cur.then(f); }
function someAsyncWork() {
return new Promise(resolve => {
setTimeout(() => {
resolve('async work done');
}, 5);
}); } async function msg() {
const msg = await someAsyncWork();
console.log(msg); }
const main = async() => {
web3.eth.subscribe('pendingTransactions').on("data", function(tx) {
enqueue(async function() {
console.log('1st print: ',tx);
await msg();
console.log('2nd print: ',tx);
});
}) }
main();
"
I'd honestly use something like lodash's throttle to do this. The following snippet should solve your problem.
ws = new WebSocket(`wss://hallo.com/ws/`);
ws.onmessage = _.throttle(readMessage, 1000);
async function readMessage(event) {
print(event)
//do important things
//but not too frequently!
}
For achieving queuing, you can make use of "settimeout" in simple/core javascript.
Whenever you receive a message from websocket, put the message processing function in a settimeout, this will ensure that the message is processed not immediately as its received, but with a delay, hence in a way you can achieve queuing.
The problem with this is that it does not guarantee that the processing of messages is sequential as they are received if that is needed.
By default settimeout in javascript does give the guarantee of when the function inside will be triggered after the time given is elapsed.
Also it may not reduce the load on your message processor service for a high volume situation and since individual messages are queued two/more functions can become ready to be processed from setimeout within some time frame.
An ideal way to do so would be to create a queue. On a high level code flow this can be achieved as follows
var queue = [];
function getFromQueue() {
return queue.shift();
}
function insertQueue(msg) { //called whenever a new message arrives
queue.push(msg);
console.log("Queue state", queue);
}
// can be used if one does not want to wait for previous message processing to finish
// (function executorService(){
// setTimeout(async () => {
// const data = getFromQueue();
// await processData(data);
// executorService();
// }, 1000)
// })()
(function executorService(){
return new Promise((res, rej) => {
setTimeout(async () => {
const data = getFromQueue();
console.log("Started processing", data)
const resp = await processData(data); //waiting for async processing of message to finish
res(resp);
}, 2000)
}).then((data) =>{
console.log("Successfully processed event", data)
}).catch((err) => {
console.log(err)
}).finally(() => {
executorService();
})
})()
// to simulate async processing of messages
function processData(data){
return new Promise((res, rej) => {
setTimeout(async () => {
console.log("Finished processing", data)
res(data);
}, 4000)
})
}
// to simulate message received by web socket
var i = 0;
var insertRand = setInterval(function(){
insertQueue(i); // this must be called on when web socket message received
i+=1;
}, 1000)
I have this code:
const lineReader = require('line-reader');
var truevar = false;
async function readLines(filename, processLine) {
return new Promise((resolve, reject) => {
lineReader.eachLine(filename, (line, last, callback) => {
if (!callback) throw new Error('panic');
if (truevar) {
// I wanna stop/finish the function here
} else {
processLine(line)
.then(() => last ? resolve() : callback())
.catch(reject);
};
});
})
};
And here's how I call the readLines function:
await readLines('somefile.txt', async (line) => {
await delay(1000) // 1 second
other_function(line);
});
I need to stop reading the file & finish the entire process once it gets to a certain point. I've read the line-reader docs, but found nothing. I also tried to do it the dirty way with "break;" etc but it's obviously just not gonna finish the job and be stuck (can't call it again unless I reload the program) so that's useless.
EDIT: Fixed the problem. I forgot to set the truevar back to false, in order to be able to call the function again.
Try this:
lineReader.eachLine(filename, (line, last, callback) => {
if (!callback) throw new Error('panic');
if (truevar) {
// Add to stop reading
cb(false);
} else {
processLine(line)
.then(() => last ? resolve() : callback())
.catch(reject);
};
});
Source: https://www.npmjs.com/package/line-reader
Found out why I wasn't able to call the function again. It wasn't the issue with async function not being stopped properly, I just didn't set the truevar back to false, in order to be able to call the function again.
I have a function that would return a promise, and in the case of an error, I have to call the same function again. The problem is that whenever I call it again, I get the same response, as if it was never called again.
This is how am resolving:
first_file = async () => {
return new Promise(async (resolve, reject) => {
//Generating the token
(async () => {
while (true) {
console.log("Resolving...");
resolve(token);
await sleep(5000);
resolved_token = token;
}
})();
});
};
I'm generating a token here, which I use in the second script:
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
(async() =>{
while(true){
test = require("./test")
test.first_file ().then(res=>{
console.log(res)
})
await sleep(15000)
}
})()
The expected value here is that every 15000ms (15 sec) I get a new response, but here I'm getting the same response over and over again.
Sorry if the title is inaccurate; I didn't know how to explain the problem.
Promises represent a value + time, a promise's settled value doesn't change like the number 5 doesn't change. Calling resolve multiple times is a no-op*.
What you want to do instead of using the language's abstraction for value + time is to use the language's abstraction for action + time - an async function (or just a function returning a promise)
const tokenFactory = () => {
let current = null;
(async () =>
while (true) {
console.log("Resolving...");
current = token; // get token somewhere
await sleep(5000);
}
})().catch((e) => {/* handle error */});
return () => current; // we return a function so it's captured
};
Which will let you do:
tokenFactory(); // first token (or null)
// 5 seconds later
tokenFactory(); // second token
*We have a flag we added in Node.js called multipleResolves that will let you observe that for logging/error handling
So, I have an adaptation of https://github.com/Dirvann/mediasoup-sfu-webrtc-video-rooms working in vanilla JS that I am attempting to adapt to use React. Instead of every user being a broadcaster, in my version, only the room creator is the broadcaster.
I've hit an issue. In the React version, when a viewer navigates to the room, they are not receiving the stream! I have no idea why since they use the same RoomClient class: https://github.com/Dirvann/mediasoup-sfu-webrtc-video-rooms/blob/master/public/RoomClient.js
This line const consumer = await this.consumerTransport.consume({ id, producerId, kind, rtpParameters, codecOptions, }); seems to be causing the problem, since the log following it doesn't get printed. Inside the consume function, my log that says 'hi' is executed, but 'blah' is not.
Here is a screenshot of the client console:
The most important functions are found below. For the entire class, please click the github link above.
async consume(producer_id) {
//let info = await roomInfo()
console.log('consume ', producer_id);
console.log('dddddddddddd', await this.getConsumeStream(producer_id));
this.getConsumeStream(producer_id).then(
function ({ consumer, stream, kind }) {
console.log('blah');
this.consumers.set(consumer.id, consumer);
let elem;
console.log('clg kind === ', kind);
if (kind === 'video') {
console.log('cons vid');
elem = document.createElement('video');
elem.srcObject = stream;
elem.id = consumer.id;
elem.playsinline = false;
elem.autoplay = true;
elem.className = 'vid';
this.remoteVideoEl.appendChild(elem);
} else {
elem = document.createElement('audio');
elem.srcObject = stream;
elem.id = consumer.id;
elem.playsinline = false;
elem.autoplay = true;
this.remoteAudioEl.appendChild(elem);
}
consumer.on(
'trackended',
function () {
this.removeConsumer(consumer.id);
}.bind(this)
);
consumer.on(
'transportclose',
function () {
this.removeConsumer(consumer.id);
}.bind(this)
);
}.bind(this)
);
}
async getConsumeStream(producerId) {
const { rtpCapabilities } = this.device;
console.log('rtpcaps ', rtpCapabilities);
const data = await this.socketRequest('consume', {
rtpCapabilities,
consumerTransportId: this.consumerTransport.id, // might be
producerId,
}).then((data) => {
console.log('daaatttaaa', data);
return data;
});
const { id, kind, rtpParameters } = data;
console.log('data === ', data);
let codecOptions = {};
console.log('aaaaaaaaaaaaaa', this.consumerTransport.consume);
const consumer = await this.consumerTransport
.consume({
id,
producerId,
kind,
rtpParameters,
codecOptions,
})
.then((result) => {
console.log('bbbbbbb', result);
return result;
});
console.log('consumer === ', consumer);
const stream = new MediaStream();
console.log('stream === ', stream);
stream.addTrack(consumer.track);
console.log('kind ', kind);
return {
consumer,
stream,
kind,
};
}
Many thanks for your time
---update---
This line never resolves: const consumer = await this.consumerTransport.consume({ id, producerId, kind, rtpParameters, codecOptions, })
It ends up executing some complex-looking functions from packages. In fact, It seems to get stuck in an infinite loop in the package called sdp-transform, after executing a few lines in mediasoup-client.
I don't even understand how chrome debugger's working. Because if I put a breakpoint on that line where ...consume(... is called, and click 'step', it parses this line: let answer = await this._pc.createAnswer() ... Which is part of a function called receive, which wasn't called by the breakpoint line... Please, somebody help.
You said something interesting there. 'hi' gets logged and 'blah' not. There isn't much code in between them. This should make us wonder how it is even possible.
Maybe create the same just without any distractions around.
Promise.resolve()
.then(console.log('hi'))
.then(function() {
console.log('blah');
})
What would that do? and why?
.then is a function that expects to be given a function (to be called when the promise resolves...)
What does console.log('hi') return? And when is it executed?
You did not want to execute the log when creating the promise chain and you also want to maybe return the result again since you want to work with the value.
So my guess would be. Changing it to:
.then(result => {
console.log('hi')
return result
})
brings you at least a step closer.