Une petite application de mon cru qui permet la reconnaissance vocale à partir d'un fichier grammatical ("grammar.txt" qui devra être dans le même répertoire que le serveur). La latence de transmission est d'une seconde. Difficile de mieux faire.
L'application utilise l'API de Windows. Cela fonctionne sous VISTA 32/64, Win7 32/64 et supérieur . Pour XP, il faudra vraisemblablement installer des librairies complémentaires. Cette solution ne nécessite donc pas Windows 10 et Unity 5.5+ pour la reconnaissance vocale intégrée.
Le serveur est multi-langue. Il utilise par défaut le "langage" installé sur le système. Bien entendu, la grammaire utilisée doit être en adéquation avec celui-ci.
Syntaxe du fichier de configuration/Grammaire.
# >> Pour ajouter un commentaire.
#I >> L'IP du serveur. 127.0.0.1 si le serveur est sur la même machine que le client.
#P >> Port UDP.
#C >> (CLOSE) Mot "magique" qui prononcé arrête le serveur. Bien sur, il est possible de le stopper manuellement. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#S >> (START) Activation de la reconnaissance, donc l'envoi des mots via UDP. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#E >> (END) Désactivation de la reconnaissance. Rien n'est envoyé via UDP. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#N >> Ajout d'un "Retour Chariot/New Line" -CHR(13)- à la fin du mot envoyé.
#D >> Display/Affichage de tout le blabla dans la console du serveur.
#V >> Degré de Validation de la reconnaissance. 0 à 100%. 70 est un bon chiffre. A expérimenter en fonction du locuteur.
Exemple de grammar.txt
Code : Tout sélectionner
# comment
#P 26000
#I 127.0.0.1
#C Terminer
#N
#S Ouverture
#E Fermeture
#V 70
#D
Merci
Au revoir
Terminer
zéro
un
deux
trois
quatre
cinq
six
sept
huit
neuf
dix
Patrick
Denis
Albert
Jean
Paul
Antoine
Bonjour
Salut
Il fait beau
Matin
Chien
Cheval
Chat
Cochon
Ordinateur
Il fait beau ce matin
Parfait
Ouverture
Fermeture
Le petit chaperon rouge
Unity
Le ciel est bleu et le soleil brille
Gauche
Droite
Haut
Bas
Saute
Tir
1984
2012
1962
1504
2013
22
33
11
Code : Tout sélectionner
// **************************************************************************
// UDP SPEECH RECOGNITION
// **************************************************************************
using System;
using System.Net;
using System.Text;
using UnityEngine;
using System.Threading;
using System.Net.Sockets;
using System.Collections;
public class UDP_RecoServer : MonoBehaviour
{
Thread receiveThread;
UdpClient client;
public int port = 26000; // DEFAULT UDP PORT !!!!! THE QUAKE ONE ;)
string strReceiveUDP = "";
public void Start()
{
Application.runInBackground = true;
receiveThread = new Thread( new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Priority = System.Threading.ThreadPriority.BelowNormal; // AboveNormal, BelowNormal, Normal, Highest, Lowest, Normal
receiveThread.Start();
}
private void ReceiveData()
{
client = new UdpClient(port);
while (true)
{
try
{
IPEndPoint anyIP = new IPEndPoint(IPAddress.Broadcast, port);
byte[] data = client.Receive(ref anyIP);
strReceiveUDP = Encoding.UTF8.GetString(data);
// **********************************************************
Action(strReceiveUDP);
// **********************************************************
}
catch (Exception err)
{
print(err.ToString());
}
}
}
public void Action(string recoReceive)
{
Debug.Log(recoReceive);
if (recoReceive == "bonjour") Debug.Log("J'ai recu un bonjour du serveur");
// etc etc etc ...
}
void OnDisable()
{
if ( receiveThread != null) receiveThread.Abort();
client.Close();
}
}
// **************************************************************************
// UDP SPEECH RECOGNITION
// **************************************************************************
Edit :
Cela fonctionne avec les chiffres. Sympa.
Edit 2 :
Informations complémentaires.
Tout ce qui est nécessaire au bon fonctionnement est résumé dans ce post.....ZJP a écrit : C'est une application (EXE) qui fonctionne sous Windows. Elle s’appuie sur le module de reconnaissance vocale intégré dans l'OS.
Pour un fonctionnement correct, il faut :
a) Effectuer la phase de configuration sous Windows. Apprentissage etc.....
b) Entrez dans un fichier (grammar.txt) la liste des mots (ou phrases) a reconnaitre. Cette liste peut bien sur être modifiée/corrigée à tout instant.
Une fois cela fait, le programme envoie via UDP (réseau) le mot (ou la phrase) reconnu(e). La réception de ce mot est donc possible sous n'importe quelle application (Unity ou pas) dotée d'une connexion réseau. Bien évidemment, le serveur et l'application de "réception" peuvent être sur la même machine (IP 127.0.0.1).
Source...
Code : Tout sélectionner
// **************************************************************************************************************************
// RecoServer UDP Version (c) ZJP
// Free Stuff.***************************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Speech.Recognition;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
namespace RecoServeur
{
class Program
{
public static SpeechRecognitionEngine speechRecognitionEngine;
public static string wordRecognized = "";
public static string endApp = "Terminer";
public static string startReco = "Ouverture";
public static string endReco = "Fermeture";
public static string newLine = "";
public static string ipServer = "127.0.0.1";
public static byte[] data = new byte[512];
public static int port = 26000;
public static double validity = 0.70f;
public static Boolean isReco = false;
public static Boolean isDisplay = false;
public static Socket server;
public static IPEndPoint iep;
public static void Main(string[] args)
{
speechRecognitionEngine = new SpeechRecognitionEngine(SpeechRecognitionEngine.InstalledRecognizers()[0]);
try
{
// create the engine
// hook to events
// speechRecognitionEngine.AudioLevelUpdated += new EventHandler<AudioLevelUpdatedEventArgs>(engine_AudioLevelUpdated);
speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(engine_SpeechRecognized);
// load dictionary
try
{
Choices MyVocabulary = new Choices();
string[] lines = File.ReadAllLines(Environment.CurrentDirectory + "\\grammar.txt");
foreach (string line in lines)
{
//reco UDP Port
if (line.StartsWith("#P"))
{
var parts = line.Split(new char[] { ' ' });
port = Convert.ToInt32(parts[1]);
Console.WriteLine("Port : " + parts[1]);
continue;
}
// Reco IP server
if (line.StartsWith("#I"))
{
var parts = line.Split(new char[] { ' ' });
ipServer = parts[1];
Console.WriteLine("ipServer : " + parts[1]);
continue;
}
// Reco endApp
if (line.StartsWith("#C"))
{
var parts = line.Split(new char[] { ' ' });
endApp = parts[1];
Console.WriteLine("Close Application Word : " + parts[1]);
continue;
}
// Reco startReco
if (line.StartsWith("#S"))
{
var parts = line.Split(new char[] { ' ' });
startReco = parts[1];
Console.WriteLine("Start Recognition Word : " + parts[1]);
continue;
}
// Reco endReco
if (line.StartsWith("#E"))
{
var parts = line.Split(new char[] { ' ' });
endReco = parts[1];
Console.WriteLine("End Recognition Word : " + parts[1]);
continue;
}
// Reco validity
if (line.StartsWith("#V"))
{
var parts = line.Split(new char[] { ' ' });
validity = Convert.ToInt32(parts[1]) / 100.0f;
Console.WriteLine("Validity : " + parts[1]);
continue;
}
// Add NewLine Char after the reco word
if (line.StartsWith("#N"))
{
newLine = "\n";
Console.WriteLine("Add NewLine On....");
continue;
}
// Display Reco
if (line.StartsWith("#D"))
{
isDisplay = true;
Console.WriteLine("Display (Verbose) on...");
continue;
}
// skip comments and empty lines..
if (line.StartsWith("#") || line == String.Empty) continue;
// the recognition grammar
MyVocabulary.Add(line);
} // foreach grammar.txt
Grammar wordsList = new Grammar(new GrammarBuilder(MyVocabulary));
speechRecognitionEngine.LoadGrammar(wordsList);
}
catch (Exception ex)
{
throw ex;
System.Environment.Exit(0);
}
// use the system's default microphone
speechRecognitionEngine.SetInputToDefaultAudioDevice();
// start listening
speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);
}
catch (Exception ex)
{
speechRecognitionEngine.RecognizeAsyncStop();
speechRecognitionEngine.Dispose();
System.Windows.Forms.MessageBox.Show( ex.Message + "\n\nSeem we have an error here : \n\na) Do you have connected a MicroPhone ?! \nb) Have you forgot the 'grammar.txt' file ?!!");
// exit
System.Environment.Exit(0);
}
// UDP init
server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
iep = new IPEndPoint(IPAddress.Parse(ipServer), port);
// Ready
Console.WriteLine("Reco Server Ready.....");
while (true)
{
Thread.Sleep(10);
}
} // main
/*
public static void engine_AudioLevelUpdated(object sender, AudioLevelUpdatedEventArgs e)
{
Console.WriteLine(e.AudioLevel);
}
*/
public static void engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result.Confidence >= validity)
{
wordRecognized = e.Result.Text;
// activate the sending reco.
if (wordRecognized == startReco)
{
isReco = true;
Console.Title = wordRecognized;
Console.BackgroundColor = ConsoleColor.Green;
Console.WriteLine("** Sending words is ENABLE **");
return;
}
// de-activate the sending reco.
if (wordRecognized == endReco)
{
isReco = false;
Console.Title = wordRecognized;
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("** Sending words is DISABLE **");
return;
}
// Use the word
if (isReco)
{
Console.Title = wordRecognized;
data = Encoding.ASCII.GetBytes(wordRecognized + newLine);
server.SendTo(data, iep);
if (isDisplay) Console.WriteLine("Sending this : " + wordRecognized);
// End of app
if (wordRecognized == endApp)
{
speechRecognitionEngine.RecognizeAsyncStop();
speechRecognitionEngine.Dispose();
System.Environment.Exit(0);
} else return;
}
}
}
} // Program
} // RecoServeur
// End source
// **************************************************************************************************************************
// RecoServer UDP Version (c) ZJP
// Free Stuff.***************************************************************************************************************
Le fichier solution (.sln) peut être ouvert et le projet se "compile" sous MonoDevelop sans aucun problème.
Edit :
SharedMemory version.
Code : Tout sélectionner
// *******************************************************************************************************************************************
// RecoServer Shared Array Version Version (c) ZJP
// Free Stuff.********************************************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Speech.Recognition;
using System.Threading;
using System.Diagnostics;
// Share Memory Buffer +++++++++++++++++++
// https://sharedmemory.codeplex.com/
using SharedMemory;
// Share Memory Buffer +++++++++++++++++++
namespace RecoServeur
{
class Program
{
public static SpeechRecognitionEngine speechRecognitionEngine;
public static string wordRecognized = "";
public static string[] ListOfWord;
public static int nbWord = 0;
public static bool SendWordIndex = false;
// Share Memory Buffer +++++++++++++++++++
public static SharedArray<Byte> serverIPC;
public static byte[] data = new byte[256];
// Share Memory Buffer +++++++++++++++++++
public static void Main(string[] args) {
speechRecognitionEngine = new SpeechRecognitionEngine(SpeechRecognitionEngine.InstalledRecognizers()[0]);
try {
// create the engine and hook to events
speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(engine_SpeechRecognized);
// load dictionary
try {
Choices MyVocabulary = new Choices();
ListOfWord = new string[256];
string[] lines = File.ReadAllLines(Environment.CurrentDirectory + "\\grammar.txt");
foreach (string line in lines) {
if (line.StartsWith("#INDEX")){
SendWordIndex = true;
continue;
}
if (line.StartsWith("#") || line == String.Empty) continue;
// the recognition grammar
MyVocabulary.Add(line);
ListOfWord[nbWord] = line;
nbWord++;
} // foreach grammar.txt
Grammar wordsList = new Grammar(new GrammarBuilder(MyVocabulary));
speechRecognitionEngine.LoadGrammar(wordsList);
}
catch (Exception ex){
throw ex;
System.Environment.Exit(0);
}
// use the system's default microphone
speechRecognitionEngine.SetInputToDefaultAudioDevice();
// start listening
speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);
}
catch (Exception ex) {
speechRecognitionEngine.RecognizeAsyncStop();
speechRecognitionEngine.Dispose();
System.Windows.Forms.MessageBox.Show( ex.Message + "\n\nSeem we have an error here : \n\na) Do you have connected a MicroPhone ?! \nb) Have you forgot the 'grammar.txt' file ?!!");
// exit
System.Environment.Exit(0);
}
// Share Memory Buffer +++++++++++++++++++++++++++++++++++
serverIPC = new SharedArray<byte>("WordSharedArray", 256);
serverIPC[0] = 0; // No Word in the buffer !!!
// Share Memory Buffer +++++++++++++++++++++++++++++++++++
// Ready
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("Reco Server Ready.....");
Console.Title = "Reco Server Ready.....";
Console.BackgroundColor = ConsoleColor.Black;
while (true) {
Thread.Sleep(10);
}
} // main
public static void engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) {
if (e.Result.Confidence >= 0.70f) {
wordRecognized = e.Result.Text;
Console.WriteLine ("Sending : " + wordRecognized);
Console.Title = wordRecognized;
if (SendWordIndex) {
// Put the Word index in the Shared array ++++++++++++++++++++++++++++++++++++++++++
serverIPC[0] = 0;
for (int i = 0; i < nbWord; i++) {
if (ListOfWord[i] == wordRecognized)
{
serverIPC[0] = (Byte)(i + 1); // New Word index in the Buffer !!!
return;
}
}
// Put the Word index in the Shared array ++++++++++++++++++++++++++++++++++++++++++
} else {
// Put the Word in the Shared array ++++++++++++++++++++++++++++++++++++++++++
data = Encoding.ASCII.GetBytes(wordRecognized);
for (int i = 0; i < data.Length; i++) {
serverIPC [i + 2] = data[i];
}
serverIPC[1] = (Byte)data.Length;
serverIPC[0] = 1; // New Word in the Buffer !!!
// Put the Word in the Shared array ++++++++++++++++++++++++++++++++++++++++++
}
}
}
} // Program
} // RecoServeur
// End source
// *******************************************************************************************************************************************
// RecoServer Shared Array Version Version (c) ZJP
// Free Stuff.********************************************************************************************************************************
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
// Share Memory Buffer ++++++++++++++++++++++
// https://sharedmemory.codeplex.com/
// Add 'SharedMemory.dll' in a Plugins folder
using SharedMemory;
// Share Memory Buffer ++++++++++++++++++++++
public class WordShared : MonoBehaviour {
SharedArray<byte> clientIPC;
private bool sArray;
public bool WordIndexMode = false;
void Start () {
Debug.Log("SharedMemory Client");
sArray = true;
try {
clientIPC = new SharedArray<byte>("WordSharedArray"); // ouverture du buffer
}
catch (FileNotFoundException ex) {
sArray = false;
}
}
void FixedUpdate()
{
if (!sArray) return;
if (!clientIPC.ShuttingDown)
{
if (WordIndexMode) {
if (clientIPC[0] > 0) // New Index Word in the Buffer ???
{
Debug.Log("New Index Word is coming !!! : " + clientIPC[0] );
clientIPC[0] = 0; // I got the Index Word. Put a new one.
return;
}
} else {
if (clientIPC[0] == 1) // New Word in the Buffer ???
{
// Yes
string response = string.Empty;
for (int i = 0; i < clientIPC[1]; i++) {
response += (char)clientIPC[i + 2];
}
clientIPC[0] = 0; // I got the Word. Put a new one.
Debug.Log("New Word is coming !!! : " + response );
return;
}
}
}
}
}