Namaste,

 

Many of mrl services use direct or indirectly language as a parameter ( or should that is the goal )

Ex, Webbit for voice recognition, chatbot for a corresponding set and derivated, speech tts to choose a good voice, translator service etc …

Lots of things can derive from this logic so we can put more intelligence ( user country for weather service, locale money, metric system for measurement etc … )

One place to drive this thing is needed, kwatters made me discover the powefull Locale class, that will do the job for a standardized logic.

One thing we need is also the possibility to override the current system language. My language maybe is not my system language, or to test things.

I chose Runtime as a starting point, because runtime is the mother of all services. And a method “SetLocale” was already here, I just modded it a little : https://github.com/MyRobotLab/myrobotlab/commit/7d5990379932bc53becf85fd7f71f2948a7b918f#diff-3205f8611ba6038c6d7685fb3a6a879eL2354

And added a “getLanguage” derived from Locale.getDefault() , the current system locale.

 

Other linked subject, possibility to store custom parameters: Every services are serialized, at shutdown a json is generated. Next restart the json is parsed. The circle is complete. Great place for a configuration place.

https://github.com/MyRobotLab/myrobotlab/blob/7d5990379932bc53becf85fd7f71f2948a7b918f/src/main/java/org/myrobotlab/service/MarySpeech.java#L51

In this example last MarySpeech voice is saved for eternity …

Ohh I said every services serialized but there is one that is not : Runtime

And remember I need to store a thing related to a parameter inside Runtime : currentLanguage, the last overrided system language.

Pushed a trick to generate a json for it, but maybe we need to find a new place / change the trick

GroG

5 years 9 months ago

Ahoy Moz4r !

I think being able to set MRL's Locale is a very good idea ..
Your absolutely right about how you might not want the Locale of MRL to be the same as your computers default Locale.  And I agree that the Runtime is a good place to put this, such that other services can ask or depdend on the Runtime's setting.

I don't think SpeechSynthesis should have a .setLanguage ..  it should only have setVoice because setLanguage is indeterminate .. however

We could have SpeechSynthesis.getVoices(locale) - which returns a list of voices that are made to support a particular language.

That way in InMoov you could write a function which "tries" to get an appropriate voice for InMoov.setLanguage, and perhaps defaults to a "default" voice if no match is found.

Does this make sense ?

 

GroG

5 years 9 months ago

I remove SpeechSynthesis.setLanguage(lang) locally

and now I'm adding 

Set<String> SpeechSynthesis.getVoices(Locale)

Inside Sweety or InMoov or any bot which wishes to support

bot.setLanguage(lang) - we can add something simillar to what you did in Polly

InMoov.setLanguage(lang) {

recognizer.setLanguage(lang);
Set<String> voices = mouth.getVoices(lang);
if (voices.size > 0){
     mouth.setVoice(voices.get(0));
} else // get default voice

 

The languageMap is a very good idea - mapping of locales to voices and voices to locales would be useful .. so we'll want to push it up into AbstractSpeechSynthesis .. 

I'll have to look into the details if Locale is serializable (it probably is) and if its in the serialized form we want..

Give me a little time and we can review my changes and if they satisfy your requirements.

I think this idea has a lot of potential :)

kwatters

5 years 9 months ago

In reply to by GroG

The voice to locale map is specific to the subclass.  It should be abstract if we define it in the AbstractSpeechSynthesis class.  

preferred approach is that the map itself isn't in the abstract class, but we just define the getVoices(locale)   is moved to the SpeechSynthesis interface.

It's up to each speech synth service to manage it's map of voices and locale

I agree about the getVoices(locale) in the interface..

I would agree the map should not be in AbstractSpeechSynthesis ... certainly not if it contained any actual implementation like Polly's aws voice...  

However,

I also think AbstractSpeechSyntheis should contain map(s) of language & voices as "any" Speech service could understand or utlize, but these data structures must be Pojo or Jvm objects.

For example :

abstract class AbstractSpeechSynthesis { 

// map languages to voices
Map<Locale, String> langMap = new HashMap<Locale,String >();
 

It then becomes a contract that the subclassed concrete speech synthesis service only "fill" this structure.

it would allow 

getVoices() and 
getVoices(Locale)  to be implemented once in the AbstractSpeechSynthesis  (lots of code reduction !)

Additionally, systems and UIs which rely on the serialized data form of these Speech services can count on the normality of the json object - which in turn simplifies downstream code & consumers..

 

 

GroG

5 years 9 months ago

moz4r - what was the purpose of voiceInJsonConfig ?  Were you trying to implement something similar to langMap I mentioned above ?  

Are you trying to get a list of all possible voices & language supported by all speech services ?

Love the idea of Map<Locale, String> langMap = new HashMap<Locale,String >(); !

The friend Map<String, String> langMap = new HashMap<String,String >(); for gender will be so useful also

 

Oh about voiceInJsonConfig will explain what it does ( maybe we can rename the var )  :

First it is a serialised var , I use it to get the last voice used to set back it again for next mrl restart.

It is hashmap because if you do :

MarySpeech speech = (MarySpeech) Runtime.start("speech", "MarySpeech");

and at an other moment ;
NaturalReaderSpeech speech = (NaturalReaderSpeech) Runtime.start("speech", "NaturalReaderSpeech");

The same json file is used. So service class is pushed with the voicename to avoid conflict and crash of setVoice().

The voice names is the only thing that is different between speech services.

 

GroG

5 years 9 months ago

I notice new code in the UI and found this gem ..

Nice moz4r :) .. I started it up and played with the buttons ... was fun :)

I understand the concept of "one language switch rules them all" and I believe I can attempt to accomidate that with the Runtime.getLocale() ..  
I've got a lot more polish to do - but I understand it would be nice to do something like this

runtime = Runtime.getInstance();
runtime.setLanguage("fr")

And all other services (which support "fr") switch appropriately ..

GroG

5 years 9 months ago

It looks like several methods were added to SpeechSynthesis interface

getEngineStatus();
getEngineError();
setEngineStatus(boolean engineStatus);
setEngineError(String engineError);
 
I will be removing them, because all of these can be handled by a single more generalized existing function in the superclass Service called
isReady() - each service has the ability to overload this and put in necessary logic to determin if its "ready" or not.

and there already is a method of for getting the last error of a service -
getLastError()

all services have access to these methods 

 
I'll make the changes ...
 
Do we all agree that this is what is desired ?
 
runtime = Runtime.getInstance()

runtime.setLanguage("fr")
 
And subsequently, all services which "could" support language "fr" attempt to support it ?
 
 

I'm agree ! cleaner than clean

We can try to set mapped language/voice if default voice is not yet set by user, that will be nice 

Thanks for your valuable advice and expertise