Nous allons voir dans ce tutoriel comment donner la parole à votre appareil Android avec une librairie Text to Speech (TTS). Que ce soit pour développer des applications pour malvoyant ou pour donner plus de vie à votre système Android, donner la parole à votre projet peut être une fonctionnalité intéressante. Pour cela nous allons intégrer la librairie react-native-tts dans un application Android développée avec React Native.
Matériel
- Appareil Android
- Ordinateur pour la programmation
- Un câble USB pour connecter l’appareil Android au PC
Configuration du projet React Native
La librairie de conversion de texte en parole, react-native-tts permet d’utiliser les voix, ou modèles de synthèse vocale, disponibles sur votre appareil Android afin de lire du texte
npm install react-native-tts --save
Afin de pouvoir sélectionner la voix désirée, nous utilisons une liste déroulante
npm install react-native-dropdown-select-list --save
Utilisation de la librairie react-native-tts
Tout d’abord, nous importons dans le code la librairie TextToSpeech ainsi que la liste déroulante
import Tts from 'react-native-tts'
import { SelectList } from 'react-native-dropdown-select-list'
Dans un composant fonctionnel, nous rajoutons les états qui nous intéresse:
- voix sélectionnée
- engin sélectionné
- liste des voix
- liste des engins
Il y a d’autres paramètres qui pourrait être intéressant à tester
- defaultLanguage
- defaultPitch défini la hauteur de la voix (aiguë ou grave)
- defaultRate défini la vitesse de lecture de la voix
Dans un crochet useEffect, nous initialisons les listes de voix et des engins puis nous affectons la voix et l’engin sélectionné par défaut.
N.B.: Nous utilisons la promesse qui résulte de l’initialisation de l’engin TextToSpeech afin de nous assurer qu’il sera disponible à l’initialisation du composant (Tts.getInitStatus().then(() => {)
useEffect(() => { //console.log("init availableVoice",availableVoice) if(availableVoice.length === 0){ console.log("No data found") Tts.getInitStatus().then(() => { Tts.voices().then(voices => { voicesList = voices.map((voice,index) => { //console.log(voice); return {key: index, value: voice.name+"("+voice.language+")", disabled: voice.notInstalled==true ? true:false} }) ; langList = voices.map((voice,index) => { return {key: index, value: voice.language, disabled: voice.notInstalled==true ? true:false} }) ; //console.log("voicesList", voicesList) setAvailableVoice(voicesList); }, (err) => {console.log("no voice loaded")}); //see all supported voices Tts.engines().then(engines => { engList = engines.map((engine,index) => { return {key: index, value: engine.name} }); //console.log("engList", engList) setAvailableEng(engList); }); //see all supported voices }, (err) => { console.log("TTS not loaded"); if (err.code === 'no_engine') { Tts.requestInstallEngine(); } }); } if(voice !== ""){ Tts.setDefaultVoice(voice); } if(lang !== ""){ Tts.setDefaultLanguage(lang); } }, [availableVoice,availableEng, voice,lang, eng]);
Enfin nous retournons le rendu qui inclus dans l’ordre:
- la liste déroulante contenant les voix disponibles
- la liste déroulante contenant les engins disponibles
- une zone de texte pour écrire le texte à lire
- un bouton pour lire le texte
return ( <View style={{ flexGrow: 1, flex: 1 }}> <Text style={styles.mainTitle}>AC Text to Speech</Text> <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setVoice(val)} data={availableVoice} save="value" /> </View> {/*} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setLang(val)} data={availableLang} save="value" /> </View>*/} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setEng(val)} data={availableEng} save="value" /> </View> <View style={styles.inputBar}> <TextInput style={styles.textInput} placeholder="Enter a message" value={msgText} onChangeText={(text) => setMsgText(text) } /> <TouchableOpacity onPress={() => Tts.speak(msgText, { androidParams: { KEY_PARAM_PAN: -1, KEY_PARAM_VOLUME: 0.5, KEY_PARAM_STREAM: 'STREAM_MUSIC', }, }) } style={[styles.sendButton]}> <Text style={styles.buttonText}> Speak </Text> </TouchableOpacity> </View> {/*<Text>{currentDate}</Text>*/} <View style={{flex: 1 }}> </View> </View> )
Résultat
Une fois votre code compilé et installé sur votre appareil, vous pouvez sélectionner et tester les voix disponibles (les voix non-installées sont grisées). Entrez un texte et appuyer sur le bouton « Speak » pour faire parler votre application.
Code source complet : Text To Speech
/** * npm install react-native-tts --save * https://www.netguru.com/blog/react-native-text-to-speech * https://www.npmjs.com/package/react-native-tts * * npm install react-native-dropdown-select-list --save */ import React, { useEffect, useState } from 'react' import { Text, View, StyleSheet, TextInput, TouchableOpacity } from 'react-native' import Tts from 'react-native-tts' import { SelectList } from 'react-native-dropdown-select-list' //Tts.setDefaultLanguage('en-GB') Tts.setDefaultLanguage('fr-FR') //Tts.setDefaultVoice('com.apple.ttsbundle.Daniel-compact') //Tts.setDefaultRate(0.6); //Tts.setDefaultPitch(1.5); //Tts.setDefaultEngine('engineName'); //request install. app need reinstall after let voicesList: { key: number; value: string; disabled: boolean }[] | ((prevState: never[]) => never[])= [] let langList = [] let engList: { key: number; value: string }[] | ((prevState: never[]) => never[]) = [] const App = () => { const [msgText, setMsgText] = useState(""); const [voice, setVoice] = useState("") const [lang, setLang] = useState("") const [eng, setEng] = useState("") const [availableVoice, setAvailableVoice] = useState([]) const [availableLang, setAvailableLang] = useState([]) const [availableEng, setAvailableEng] = useState([]) useEffect(() => { //console.log("init availableVoice",availableVoice) if(availableVoice.length === 0){ console.log("No data found") Tts.getInitStatus().then(() => { Tts.voices().then(voices => { voicesList = voices.map((voice,index) => { //console.log(voice); return {key: index, value: voice.name+"("+voice.language+")", disabled: voice.notInstalled==true ? true:false} }) ; langList = voices.map((voice,index) => { return {key: index, value: voice.language, disabled: voice.notInstalled==true ? true:false} }) ; //console.log("voicesList", voicesList) setAvailableVoice(voicesList); }, (err) => {console.log("no voice loaded")}); //see all supported voices Tts.engines().then(engines => { engList = engines.map((engine,index) => { return {key: index, value: engine.name} }); //console.log("engList", engList) setAvailableEng(engList); }); //see all supported voices }, (err) => { console.log("TTS not loaded"); if (err.code === 'no_engine') { Tts.requestInstallEngine(); } }); } if(voice !== ""){ Tts.setDefaultVoice(voice); } if(lang !== ""){ Tts.setDefaultLanguage(lang); } }, [availableVoice,availableEng, voice,lang, eng]); return ( <View style={{ flexGrow: 1, flex: 1 }}> <Text style={styles.mainTitle}>AC Text to Speech</Text> <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setVoice(val)} data={availableVoice} save="value" /> </View> {/*} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setLang(val)} data={availableLang} save="value" /> </View>*/} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setEng(val)} data={availableEng} save="value" /> </View> <View style={styles.inputBar}> <TextInput style={styles.textInput} placeholder="Enter a message" value={msgText} onChangeText={(text) => setMsgText(text) } /> <TouchableOpacity onPress={() => Tts.speak(msgText, { androidParams: { KEY_PARAM_PAN: -1, KEY_PARAM_VOLUME: 0.5, KEY_PARAM_STREAM: 'STREAM_MUSIC', }, }) } style={[styles.sendButton]}> <Text style={styles.buttonText}> Speak </Text> </TouchableOpacity> </View> {/*<Text>{currentDate}</Text>*/} <View style={{flex: 1 }}> </View> </View> ) } export default App; let BACKGROUND_COLOR = "#161616"; //191A19 let BUTTON_COLOR = "#346751"; //1E5128 let ERROR_COLOR = "#C84B31"; //4E9F3D let TEXT_COLOR = "#ECDBBA"; //D8E9A8 var styles = StyleSheet.create({ mainTitle:{ color: TEXT_COLOR, fontSize: 30, textAlign: 'center', borderBottomWidth: 2, borderBottomColor: ERROR_COLOR, }, backgroundVideo: { borderWidth: 2, borderColor: 'red', position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, webVideo: { borderWidth: 2, borderColor: 'green', position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, buttonText: { color: TEXT_COLOR, fontWeight: 'bold', fontSize: 12, textAlign: 'center', textAlignVertical: 'center', }, sendButton: { backgroundColor: BUTTON_COLOR, padding: 15, borderRadius: 15, margin: 2, paddingHorizontal: 20, }, inputBar:{ flexDirection: 'row', justifyContent: 'space-between', margin: 5, }, textInput:{ backgroundColor: '#888888', margin: 2, borderRadius: 15, flex:3, }, });
Applications
- Faites parler votre système Android que ce soit un téléphone une voiture ou un robot!