Reconnaissance et synthèse vocale – Web Speech API

Afin de rendre le robot un peu plus intelligent, je l’ai doté dès le début de la reconnaissance vocale. Pour cela, j’ai utilisé la librairie Sphinx 4 avec un ensemble de fichiers pour permettre la reconnaissance de la langue française. J’ai été assez bluffé par les résultats de la reconnaissance mais je me suis vite retrouvé face à un problème. Mon but principal était que le robot puisse reconnaître “tout” ce qu’on lui dit, or,Sphinx 4 se limite à reconnaître les phrases définies dans le fichier grammaire. Ce qui peut vite devenir fastidieux si l’on souhaite développer un moteur de conversation assez poussé. Je me suis donc mis à la recherche d’autres solutions. Et là, je suis tombé sur une petite librairie javascript de reconnaissance vocale, annyang, qui fait appel à la nouvelle API HTML5, la Web Speech API. Je me suis donc inspiré de cette librairie pour mettre en place un script de reconnaissance vocale et dans le même temps, de synthèse vocale (la Web Speech API inclut également cette possibilité). Pour l’instant, cette API n’est implémentée que par le navigateur Chrome (lien who is).

Place maintenant au tutoriel. Pour mettre en pratique cette API (reconnaissance et synthèse vocale), nous allons créer une page qui permet de faire un écho : on dit une phrase, la synthèse vocale nous la répète.

Tout d’abord, mettons en place le script JS permettant de faire appel à l’API. Les explications se trouvent dans les commentaires.
[speech.js]

// Initialisation de la reconnaissance vocale en fonction du navigateur
// Pour l'instant, seul Google Chrome le supporte
var SpeechRecognition = SpeechRecognition ||
                          webkitSpeechRecognition ||
                          mozSpeechRecognition ||
                          msSpeechRecognition ||
                          oSpeechRecognition;
						  
var recognition;
var lastStartedAt;
						  
if (!SpeechRecognition) {
	console.log('Pas de reconnaissance vocale disponible');
	alert('Pas de reconnaissance vocale disponible');
} else {
	
	// Arrêt de l'ensemble des instances déjà démarrées
    	if (recognition && recognition.abort) {
		recognition.abort();
    	}
	
	// Initialisation de la reconnaissance vocale
	recognition = new SpeechRecognition();
	// Reconnaissance en continue
	recognition.continuous = true;
	// Langue française
	recognition.lang = 'fr-FR';
	
	// Evènement de début de la reconnaissance vocale
	recognition.onstart = function() {
		console.log('Démarrage de la reconnaissance');
	};
	
	// Evènement de fin de la reconnaissance vocale
	// A la fin de la reconnaissance (timeout), il est nécessaire de la redémarrer pour avoir une reconnaissance en continu
	// Ce code a été repris de annyang
	recognition.onend = function() {
		console.log('Fin de la reconnaissance');
		var timeSinceLastStart = new Date().getTime()-lastStartedAt;
		if (timeSinceLastStart < 1000) {
			setTimeout(demarrerReconnaissanceVocale, 1000-timeSinceLastStart);
		} else {
			// Démarrage de la reconnaissance vocale
			demarrerReconnaissanceVocale();
		}
	};

	// Evènement de résultat de la reconnaissance vocale
	recognition.onresult = function (event) {
		for (var i = event.resultIndex; i < event.results.length; ++i) {
			var texteReconnu = event.results[i][0].transcript;
			console.log('Résultat = ' + texteReconnu);
			// Synthèse vocale de ce qui a été reconnu
			var u = new SpeechSynthesisUtterance();
			u.text = texteReconnu;
			u.lang = 'fr-FR';
			u.rate = 1.2;
			speechSynthesis.speak(u);
		}
	};
	
	// Démarrage de la reconnaissance vocale
	demarrerReconnaissanceVocale();
}

function demarrerReconnaissanceVocale() {
	// Démarrage de la reconnaissance vocale
	lastStartedAt = new Date().getTime();
    	recognition.start();
}

Voici le petit bout de code de la page HTML faisant appel au script :
[speech.html]

<!DOCTYPE html>
<html>
	<head>
	  <title></title>
	  <meta charset="utf-8">
	  <script src="scripts/speech.js"></script>
	</head>
	<body>
		<h1>Echo</h1>
	</body>
</html>

Pour lancer cet exemple, il est nécessaire de le faire tourner sur un serveur sécurisé (HTTPS). Sans cela, Chrome vous demandera sans cesse l’autorisation d’utiliser votre micro à chaque timeout de la reconnaissance vocale. Une fois en HTTPS, il sera alors possible de considérer l’adresse URL de l’exemple comme exception dans Chrome. Pour cela, nous allons créer un serveur sécurisé avec NodeJS et utiliser un certificat et une clé.
Pour créer un certificat et une clé à titre personnel, rendez-vous à cette adresse : http://www.trustico.fr/ssltools/create/certificate-pem/create-self-signed-ssl-certificate.php. Une fois que vous vos informations saisies, le site génère un certificat que vous allez copier dans un fichier nommé server.crt et une clé que vous aller copier dans un fichier nommé server.key.
Voici maintenant le code du serveur NodeJS https :
[server_speech.js]

var https = require('https');
var fs = require('fs');
var express = require('express');
var app = express();
app.use(express.static('../client/'));

var sslOptions = {
  key: fs.readFileSync('./ssl/server.key'),
  cert: fs.readFileSync('./ssl/server.crt'),
  requestCert: true,
  rejectUnauthorized: false
};

var secureServer = https.createServer(sslOptions,app);

secureServer.listen('8080', function(){
  console.log("Secure Express server listening on port 8080");
});

Voici le ZIP contenant l’ensemble des sources sauf les fichiers de certificat et de clé : Speech.zip
Dézippez-le. Copiez vos fichiers server.crt et server.key dans le dossier server/ssl.

Pour lancer l’exemple, il faut d’abord installer NodeJS sur votre machine. Voici la procédure à suivre sous Ubuntu :
sudo apt-add-repository ppa:chris-lea/node.js
puis
sudo apt-get update
et
sudo apt-get install nodejs

Allez au niveau du dossier server du projet puis tapez la commande suivante afin d’installer les modules nécessaires au script NodeJS, à savoir le module express :
npm install express

Puis lancez le serveur :
node server_speech.js

Enfin, lancez Chrome, puis tapez l’adresse https://localhost:8080/speech.html et amusez-vous à faire répéter à l’ordinateur tout ce que vous dites.
Le navigateur va sûrement vous indiquer “Votre connexion n’est pas privée“. Cliquez sur paramètres avancés puis sur Continuer vers le site localhost. Si quelqu’un a une parade pour pouvoir lancer Chrome sur l’exemple sans obtenir cette page, je suis preneur ;-).

Ensuite, libre à vous de mettre en place des websockets pour communiquer avec la partie serveur (NodeJS ou serveur Jetty embarqué comme je l’ai fait pour mon robot) et de coupler cela avec un moteur de conversation …

Nicolas

Développeur JAVA, je suis passionné de robotique depuis quelques années, notamment tout ce qui concerne la partie programmation (vision artificielle, synthèse et reconnaissance vocale, intelligence artificielle, ...).

8 commentaires :

  1. Bonjour,

    je ne sais pas si tu as déjà jeté un oeil à cette API :
    https://github.com/The-Shadow/java-speech-api

    Elle permet de faire de la reconnaissance vocale en Java en envoyant un fichier son vers google qui te renvoie son interprétation sous forme de texte. Je n’ai pas encore fait beaucoup de tests mais cela semble fonctionner.
    A voir néanmoins, il semble y avoir une limitation à 50 requêtes par jour (mais je n’ai pas encore testé).

    Nicolas F.

    • Bonjour,
      Merci pour le lien. J’étais déjà tombé sur cette API mais sans la tester, ce que j’ai fait aujourd’hui. Malheureusement, je n’arrive pas à faire fonctionner l’exemple “Duplex”. J’ai l’erreur suivante :

      Starting to write
      Error: 403
      Exception in thread "Downstream Thread" java.lang.NullPointerException
      at com.darkprograms.speech.recognizer.GSpeechDuplex$1.run(GSpeechDuplex.java:196)

      Si tu as un bout de code qui fonctionne à me proposer, c’est pas de refus 😉 .
      Ce qui m’embête un peu dans cette API, c’est la limitation à 50 requêtes / jour. Dans le cas de mon robot, c’est une limite qui est très vite atteinte alors qu’avec la solution que je propose via “Web Speech API”, je n’ai pas remarqué de limitation. A voir …

      Nicolas P.

  2. je viens d’utiliser les api google pour la synthèse vocale d’abord puis la reconnaissance vocale, en anglais puis en français.
    ça fonctionne.
    On va dire à peu prés correctement.
    Il faut néanmoins une connexion internet.
    Cependant l’outil est puissant et il est certain qu’il va s’améliorer.
    Example Code de https://github.com/lkuza2/java-speech-api/wiki/Duplex—Hello-World fonctionne bien,
    c’est le second que je n’ai pas réussi à faire fonctionner.
    pour la synthèse vocale j’utilise directement l’api de google.
    un petit hic mais je n’ai pas recherché plus que cela, je n’ai pas pu modifier la voix de sortie.

  3. Ping : Comparaison de synthèses vocales françaises | Roboteek

  4. Bonjour,
    j’aimerais savoir si le code que tu proposes fonctionne pour le web car j’ai besoin d’une reconnaissance vocale pour un projet web, puis je voudrais savoir si tu as aussi un exemple car je viens de commencer le javascript et je connais peu de choses, je te remercie si tu veux bien répondre pour aider un jeune de 15 ans à développer ses compétence dans le web 🙂
    Cordialement.

  5. Bonjour,
    J’ai un chatterbot écrit en C et j’aimerai lui mettre la reconnaissance vocale. Je voudrais savoir comment je peux envoyer le msg reconnu par l’api en js et l’envoyer à mon chatterbot qui lui est écrit en c ?
    Merci beaucoup

    • Bonjour Rémi,

      Je ne sais pas si c’est possible en C, s’il existe des bibliothèques pour ça (je pense que oui), mais je te conseille d’utiliser les websockets pour communiquer entre le JS et le C. C’est ce que j’ai fait pour communiquer avec du JAVA. D’autant que c’est très simple à mettre en plave en JS.
      Ou après, tu peux appeler des webservices. Mais je ne m’y connais pas assez en C pour t’en dire plus. Désolé.

      Cordialement,

      Nicolas

Répondre à Rémi Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *