Tag Archives: Latent Semantic Mapping

Reconnaissance vocale et analyse de texte dans vos applications Xamarin.iOS

Bien qu’existante depuis très longtemps dans l’univers informatique, la reconnaissance vocale est une fonctionnalité encore peu utilisée au sein des applications (aussi bien sur mobile que sur desktop).

Depuis l’annonce de Siri par Apple en 2011, les assistants personnels ont le vent en poupe et une nouvelle étape a été franchie sur iOS 10 lors de la WWDC 2016 puisque le moteur de reconnaissance vocal utilisé par Siri est désormais accessible aux développeurs.

Voyons comment utiliser celui-ci pour intégrer la reconnaissance vocale au sein d’une application Xamarin.iOS, et comment le coupler à des APIs plus anciennes mais relativement méconnues, pour faire de l’analyse de texte.

Speech Recognition API au service des développeurs

Comme nous l’évoquions précédemment, Apple a rendu disponible dans iOS 10 le moteur qui propulse Siri pour la reconnaissance vocale. Pour cela, une nouvelle classe est à la disposition des développeurs : SFSpeechRecognizer.

Ce qu’il est important de noter pour utiliser cette classe, c’est qu’une connexion réseau est nécessaire car tout ce qui sera enregistré via le microphone, sera envoyé à Apple pour que les serveurs qui propulsent Siri, traitent et analysent les informations avant de vous renvoyer la transcription du texte.

Cette phase de communication avec les serveurs Apple a lieu tout au long du processus de reconnaissance vocale (vous récupérez la transcription au fil de l’eau), ce qui fait que si vous utilisez la fonctionnalité trop souvent, cela a tendance à consommer beaucoup de données (sur votre forfait 3G/4G) et d’énergie sur la batterie de votre téléphone/tablette.

C’est pourquoi Apple impose certaines limitations (ex: 1mn maximum pour chaque enregistrement audio) et a également mis en place des quotas d’utilisation permettant à une application d’effectuer un nombre limité de requêtes par jour (un message d’erreur est renvoyé si le quota est dépassé).

Comme pour tout ce qui touche à la vie privée chez Apple, avant de pouvoir utiliser cette API, il est nécessaire de demander l’autorisation à l’utilisateur et de réagir en conséquence selon la réponse qu’il donnera :

SFSpeechRecognizer.RequestAuthorization((SFSpeechRecognizerAuthorizationStatus status) =>
{
  switch (status)
  {
    case SFSpeechRecognizerAuthorizationStatus.Authorized:
      break;
    case SFSpeechRecognizerAuthorizationStatus.Denied:
      break;
    case SFSpeechRecognizerAuthorizationStatus.NotDetermined:
      break;
    case SFSpeechRecognizerAuthorizationStatus.Restricted:
      break;
  }
});

Pour que tout ceci fonctionne sans soucis, il est également nécessaire d’ajouter 2 lignes dans le fichier Info.plist, afin d’indiquer à l’application que vous avez besoin d’utiliser la reconnaissance vocale et le microphone.

Speech Recognition - Info.plist

Maintenant que les bases sont posées pour pouvoir utiliser les composants nécessaires, il ne reste plus qu’à écrire le code. Celui-ci repose sur 3 classes importantes :

  • AVAudioEngine ==> Le moteur audio permettant d’enregistrer ce que l’utilisateur dira via le microphone de son téléphone ou de sa tablette
  • SFSpeechRecognizer ==> Le moteur de reconnaissance vocal qui communiquera avec les serveurs Apple
  • SFSpeechAudioBufferRecognitionRequest ==> Le buffer audio qui servira à stocker les données renvoyées par le moteur audio avant d’être envoyées chez Apple pour analyse

Un exemple de code étant toujours plus parlant qu’un long discours, voici ci-dessous le code associé à notre application de démonstration, qui initie l’enregistrement quand l’utilisateur tape sur un bouton, et met fin à l’enregistrement quand l’utilisateur relâche ce même bouton.

private AVAudioEngine AudioEngine;
private SFSpeechRecognizer SpeechRecognizer;
private SFSpeechAudioBufferRecognitionRequest LiveSpeechRequest;
private SFSpeechRecognitionTask RecognitionTask;
private string sentence;

partial void StartSpeechRecognition(UIButton sender)
{
  SpeechRecognizer = new SFSpeechRecognizer(NSLocale.FromLocaleIdentifier("fr"));
  if (!SpeechRecognizer.Available)
    return;

  AudioEngine = new AVAudioEngine();
  if (AudioEngine.InputNode == null)
    return;

  NSError audioError;
  LiveSpeechRequest = new SFSpeechAudioBufferRecognitionRequest();

  var recordingFormat = AudioEngine.InputNode.GetBusOutputFormat(0);
  AudioEngine.InputNode.InstallTapOnBus(0, 1024, recordingFormat, (AVAudioPcmBuffer buffer, AVAudioTime when) => LiveSpeechRequest.Append(buffer));
  AudioEngine.Prepare();
  AudioEngine.StartAndReturnError(out audioError);
  if (audioError != null)
    return;

  RecognitionTask = SpeechRecognizer.GetRecognitionTask(LiveSpeechRequest, (SFSpeechRecognitionResult result, NSError taskError) =>
  {
    if (taskError != null)
      return;

    if (!result.Final)
    {
      SpeechLabel.Text = result.BestTranscription.FormattedString;
      return;
    }
 
    sentence = result.BestTranscription.FormattedString;
    ParseSpeechRecognition();
  });
}

partial void StopSpeechRecognition(UIButton sender)
{
  AudioEngine?.Stop();
  AudioEngine?.InputNode?.RemoveTapOnBus(0);
  LiveSpeechRequest?.EndAudio();
}

Outre l’initialisation du moteur audio via la définition de paramètres sur la source d’enregistrement (AudioEngine.InputNode), la partie importante repose sur la fonction de “callback” passée à la méthode GetRecognitionTask, qui permet de récupérer la transcription du texte (result.BestTranscription.FormattedString) au fil de l’eau, et de savoir si la reconnaissance est terminée ou non (result.Final).

Une fois tous les éléments assemblés et en réalisant un peu de cosmétique autour de l’interface graphique, cela donne le résultat visible dans la vidéo ci-dessous :

Comme on peut le voir dans cette vidéo, avec juste quelques lignes de code, il est possible d’intégrer la reconnaissance vocale dans une application. Mais hormis si l’on souhaite juste permettre à l’utilisateur de remplir des zones de texte sans rien saisir au clavier, il serait plus intéressant de pouvoir analyser ce texte.

NSLinguisticTagger : Une classe méconnue mais très pratique

C’est à ce moment qu’une classe relativement méconnue surgit, bien qu’elle existe dans iOS depuis la version 5.0. Cette classe porte un nom relativement explicite : NSLinguisticTagger.

Celle classe est capable, à partir d’un texte plus ou moins long, de “tagger” celui-ci, c’est-à-dire d’identifier tous ses composants (noms, pronoms, verbes, adverbes, déterminants, etc…) mais également d’identifier certains éléments marquants (noms de lieux, noms de sociétés…). Malheureusement cette dernière possibilité ne fonctionne qu’en Anglais.

Différentes langues sont supportées par NSLinguisticTagger (Anglais, Français, Allemand…) afin de couvrir les langues les plus fréquemment rencontrées sur iOS.

Comment fonctionne tout ceci ? C’est relativement simple comme on peut le voir dans l’exemple de code ci-dessous :

private void ParseSpeechRecognition()
{
  var options = NSLinguisticTaggerOptions.OmitWhitespace | NSLinguisticTaggerOptions.OmitPunctuation | NSLinguisticTaggerOptions.JoinNames;
  var schemes = NSLinguisticTagger.GetAvailableTagSchemesForLanguage("fr");
  var tagger = new NSLinguisticTagger(schemes, options);
  tagger.AnalysisString = sentence;
  tagger.EnumerateTagsInRange(new NSRange(0, sentence.Length), NSLinguisticTag.SchemeLexicalClass, options, HandleNSLingusticEnumerator);
}

private void HandleNSLingusticEnumerator(NSString tag, NSRange tokenRange, NSRange sentenceRange, ref bool stop)
{
  var token = sentence.Substring((int)tokenRange.Location, (int)tokenRange.Length);
  Console.WriteLine($"{token} = {tag}");
}

A partir d’une liste d’options (ignorer les espaces, ignorer la ponctuation, etc…) et d’une liste de types d’éléments analysables pour une langue (appelées “schemes”), on énumère les “tags” contenus dans le texte à analyser (AnalysisString).

La méthode permettant d’énumérer les tags du texte, prend en paramètre une fonction de “callback” qui sera appelée pour chaque tag identifié.

Si on exécute le code précédent avec la phrase utilisée dans la vidéo de notre application de démonstration, nous obtenons le résultat ci-dessus dans la fenêtre de sortie de Xamarin Studio.

2016-11-27 09:02:57.714 SpeechDemo[919:415497] C' = Pronoun
2016-11-27 09:02:57.714 SpeechDemo[919:415497] est = Verb
2016-11-27 09:02:57.714 SpeechDemo[919:415497] bientôt = Adverb
2016-11-27 09:02:57.715 SpeechDemo[919:415497] Noël = Noun
2016-11-27 09:02:57.715 SpeechDemo[919:415497] j' = Pronoun
2016-11-27 09:02:57.715 SpeechDemo[919:415497] espère = Verb
2016-11-27 09:02:57.716 SpeechDemo[919:415497] que = Conjunction
2016-11-27 09:02:57.716 SpeechDemo[919:415497] vous = Pronoun
2016-11-27 09:02:57.716 SpeechDemo[919:415497] passerez = Verb
2016-11-27 09:02:57.716 SpeechDemo[919:415497] tous = Adjective
2016-11-27 09:02:57.717 SpeechDemo[919:415497] de = Preposition
2016-11-27 09:02:57.717 SpeechDemo[919:415497] bonnes = Adjective
2016-11-27 09:02:57.717 SpeechDemo[919:415497] fêtes = Noun

Comme on le voit ci-dessus, à partir des informations renvoyées par NSLinguisticTagger, il est possible d’envisager les traitements nécessaires à la logique propre à une application (ex: extraire les noms et rechercher des valeurs particulières pour filtrer des résultats).

Pour aller encore plus loin…

Comme nous l’avons vu dans cet article, en couplant la reconnaissance vocale, désormais disponible dans iOS 10, avec un outil de taggage comme NSLinguisticTagger, de nouveaux horizons s’ouvrent pour intégrer des fonctionnalités inédites au sein des applications mobiles.

Toutefois si vous voulez aller encore plus, il existe d’autres éléments qu’il est toujours bon de connaitre, à commencer par la catégorisation de contenus.

Si vous réalisez des applications pour OSX, Apple a mis à disposition un framework appelé Latent Semantic Mapping (LSM) qui permet de catégoriser un contenu (ex: une page web, un fichier…) à partir d’une base d’autres contenus. Une session dédiée à ce framework avait été présentée lors de la WWDC 2011 si vous souhaitez en savoir plus à ce sujet.

Si vous voulez faire une analyse plus poussée du texte renvoyé par la reconnaissance vocale (ex: extraire des entités, identifier le sujet de fond d’un document, etc…) il existe différentes APIs basées sur le Machine Learning qui satisferont tous vos désirs.

On pourra citer comme exemple un projet sur lequel mise beaucoup Microsoft, à savoir Cognitive Services et plus particulièrement la brique Language Understanding Intelligent Service (LUIS). Des alternatives telles que TextRazor méritent également le coup d’oeil.

Advertisements