Hi,
I’m just wondering if you found a solution to this because I’m having a similar issue.
Thanks
Hi,
I’m just wondering if you found a solution to this because I’m having a similar issue.
Thanks
Hello,
I am using the Cordova Text To Speech Plugin in my Ionic Vue app. I call an api to receive my messages for TTS. The problem is that if the api responds with multiple messages, the TTS speaker function only reads the first function.
My Current Setup:
I save my responses in an array. Then i loop with a while-loop through my array. It works like a queue. I call the first item from my array and then send it to my tts function. When its done, the message is removed from the array. With console.logs I have also outputted everything, but only the first message is read aloud.
Handle my Array:
var messagesArr = [];
for (const rspmsg of responseMessageArr){
const message = rspmsg.text.text[0];
messagesArr.push(message);
}
while(messagesArr.length !== 0){
await this.tts(messagesArr[0]);
messagesArr.shift();
}
My tts function:
async tts(text){
TextToSpeech.speak({
text: text,
identifier: "com.apple.ttsbundle.siri_female_de-DE_compact",
locale: 'de-DE',
rate:0.5})
.then(() => console.log("Success speech"))
.catch((reason) => console.log(reason));
}
Especially if you’re new to web programming, forget that async
and await
exist. They obscure what is actually happening, and it’s IMHO absolutely essential that you get fully grounded in the underlying fundamentals.
Imagine that you are in 1998, before smartphones, sitting in an IRC channel, talking to a friend who is currently not at their keyboard. You want to schedule a meal with them sometime in the next week, and want to know their schedule. In order to move the conversation forward as efficiently as you can, you write:
LMK if you’re free for dinner either Wednesday or Friday, and if so, what time would work for you.
You turn on a bot that looks for dates and times, and books a restaurant based on what your friend responds. The bot doesn’t know when it will be called on, but it knows what to expect in the way of input, and what it is supposed to do in that situation. The pseudocode for the bot looks somewhat like this:
class Reservabot {
book(where: Restaurant, when: Date): Promise<string> {
// implementation details irrelevant
}
sendInvitation(who: Friend, whens: Date[]): Promise<Message> {
// implementation details irrelevant
}
invite(who: Friend, whens: Date[]): Promise<string> {
return this.sendInvitation(who, whens)
.then(rsp => {
return this.book(randomRestaurant(), rsp.when));
});
}
}
Things to note about invite
:
return
. this is always a good thing to strive for, especially when new. doing so avoids common bugs.book
call is going to happen in wall clock terms. all you know is that by the time it does, your friend will have responded with an acceptable time. that time is only known inside that then
clause.Promise
that comes from book
, which itself is going to represent an asynchronous process, because we don’t know when the restaurant will pick up the phone.invite
will have to do so in similar fashion, hanging a then
clause off of the call with whatever is to be done next (tell your friend where to go, for example).Modern Ionic overlays work very much like this. The create
call gives you a Promise
of an alert. Once it resolves, you can call onDidDismiss
on it to get another Promise
that will resolve once the alert has been dismissed (and tell you the data that came with that dismissal). You can also call present
on it, which returns a Promise
that resolves once the alert has been presented (that you can ignore if you wish).
Something like this:
this.alertCtrl.create({...}).then(alert => {
alert.onDidDismiss(rsp => {...});
alert.present();
});
This solution does not work for a production release, API level required according to documentation is currently 29, and should be 30 from November 2021, check the following link 符合 Google Play 的目标 API 级别要求 | Android Developers
Let me know if you had found another solution since
Yes… I’ve tried to make calls to the production site as well as tunneling to a localhost port using ngrok, both of which are hosted on HTTPS, but still no love.
I have to think it is some simple but esoteric thing but I’m at a lost as to what that could be… using tunneling I literally never see the request get to the server.
Is there some kind of permission on an iPhone app that needs to be set to make API calls in an app?
–harris
That makes me suspect CORS. Might that be the issue?
I find async
and await
a solution in search of a problem, and therefore don’t use them, so admittedly I’m not 100% confident in my understanding of their arcane details.
That being said, I believe your tts
function would (probably unexpectedly) desugar as follows:
tts(text: string): Promise<undefined> {
TextToSpeech.Speak({text, ...});
return Promise.resolve(undefined);
}
You are not explicitly returning the Promise
given to you by the TTS plugin to the caller of tts
, so I don’t think your code is actually waiting for the speak
to complete before potentially firing off the next speech request. That may be making the plugin ignore further calls that are hitting it too quickly for it to process. To see if this is the issue, try this:
async tts(text: string): Promise<any> {
return TextToSpeech.speak({text, ...});
}
Thank you for your effort. I tried your solution, and it has the same effect. I did not metion, that i also tried for testing purposes to delay the next call up to 10s. This also had no effect.
Hmm. In that case, the plugin you’re using seems to have been orphaned several years ago. I wonder if it might be worth giving this alternative a shot?
Yes… I think the issue was on the server… I had to update the hosts that could call the API so the tunneling app could make the call.
Thank you for taking the time to respond… it definitely helped!
–harris
Thanks. I didn’t saw it. I’ll give it a shot. I’ll report back if it worked out
Thanks man. It worked
Running the app in the web displays errors in the console. Running through Xcode, logs get logged out just fine but console.error logs just print ⚡️ [error] - ERROR {}
.
Can I add something to capacitor config to pass the actual error up to whatever bridge cap is using?
Chrome console logs showing actual (non-empty) errors:
vs Xcode:
running recent stuff:
Ionic:
Ionic CLI : 6.16.3
Ionic Framework : @ionic/angular 5.6.9
@angular-devkit/build-angular : 0.1102.13
@angular-devkit/schematics : 11.2.13
@angular/cli : 11.2.13
@ionic/angular-toolkit : 3.1.1
Capacitor:
Capacitor CLI : 3.0.1
@capacitor/android : 3.1.2
@capacitor/core : 3.1.2
@capacitor/ios : 3.1.2
It works now. I think it was a combination of all. First I updated to the updated tts version. Then i removed the return from tts and in combination with a change at my API call everything works fine now. Thank you
Any help appreciated!
I have the code below … you’ll see two boolean values that show an ion-badge if true. Problem is … if the values are updated the tabs are reset to screen 0.
Both Variables are set from a subscribe to a service variable. It is updated based on data changing in the database. How do I prevent the Tabs from resetting when the data is changed?
`<ion-tabs *ngIf=“userStatus !=‘suspend’”>
<ion-tab-button tab="matches" title="Matches">
<ion-icon name="heart-outline" style="pointer-events: none;"></ion-icon>
<ion-badge color="danger" *ngIf="hasNewMatches"></ion-badge>
</ion-tab-button>
<ion-tab-button tab="chat-list" title="Messages">
<ion-icon name="chatbubble-outline" style="pointer-events: none;"></ion-icon>
<ion-badge color="danger" *ngIf="newMessageCount">{{ newMessageCount }}</ion-badge>
</ion-tab-button>
<ion-tab-button tab="settings" title="Settings">
<ion-icon name="settings-outline" style="pointer-events: none;"></ion-icon>
</ion-tab-button>
`
What happens if you remove the *ngIf
expression on the <ion-tabs>
itself?
It works if remove the ngIf … Now that mention this … I am going to try ngShow instead. if this works I will be so upset. 3 weeks with this issue.
I don’t think ngShow
exists in modern Angular. Much simpler to just bind [attr.hidden]
or [class.invisible]
combined with a display: none
CSS rule.
yes … sorry I meant [hidden]. I used that instead …and it worked. Lesson learned. ngIf changes the DOM and [hidden] just changes the CSS so there is no need for a repaint.
However… I still find it odd that on the repaint it changes the currently selected Tab. BUT! Its working, so I am happy.
Thanks!