Posts taggés NodeJS

Comment créer un assistant d’accueil avec Raspberry Pi ?

2

Le projet

Dans le cadre de PLANET (Plan d’excellence technologique), nous souhaitions nous lancer dans un projet en rapport avec le monde des objets connectés.
C’est comme cela que lors d’un brainstorming, nous avons émis l’idée de créer un « assistant » d’accueil basé sur une des nouvelles plateformes d’IoT (Internet of Things) qui sont apparus récemment.
Nous avions le choix entre plusieurs solutions : RaspberryPi, Galileo (Intel), Adruino, etc. …

Nous avons finalement choisi la RaspberryPi 2 qui est une des plus performantes par rapport au prix et qui, de plus, est suivie et supportée par une très grande communauté active sur internet.

Les différentes solutions

Nous étant mis d’accord sur la base de travail de notre assistant, nous nous sommes mis à la recherche de solutions open-source existantes permettant de gérer les commandes vocales.

Nous avons trouvé plusieurs solutions et avons finalement sélectionné deux solutions pour tenter une première implémentation : JASPER et S.A.R.A.H.

JASPER est une solution qui nous a semblé prometteuse et qui a l’avantage d’avoir été conçue pour fonctionner sur RaspberryPi.

Malheureusement après nos premiers tests, nous nous somme rapidement aperçu d’une limitation assez gênante : La majorité des moteurs de STT (Speech to Text) qui sont compatibles avec la solution ne supportent pas très bien la langue française.

Le seul moteur de reconnaissance qui gérait très bien la langue de Molière était celui fourni avec l’API Google. Là encore, il y’a un gros bémol : L’API possède une limitation du nombre d’appels d’environ 50 appels/jour. Cela a fini par sceller le sort de Jasper en ce qui nous concerne.
Notre solution devant être un assistant d’accueil dans nos locaux (en France), cela n’était tout simplement pas viable sur le plan pratique.

S.A.R.A.H. nous a finalement convenu parfaitement.
La solution se base sur la reconnaissance vocale de Windows qui gère très bien la langue française de manière native.
S.A.R.A.H. n’étant compatible qu’avec Windows, nous avons donc décidé d’installer S.A.R.A.H. sur un ordinateur et de déporter la capture audio et vidéo sur la RaspberryPi grâce au module RTP de S.A.R.A.H.

Principe de fonctionnement de S.A.R.A.H.

La solution S.A.R.A.H. est donc conçue pour fonctionner sur Windows.

Elle se décompose en deux parties :

  • Le client: C# (avec gestion de la Kinect) pour la gestion de la reconnaissance de la voix, des gestes, des visages et des des QRCodes.
  • Le serveur: NodeJS (ExpressJs) pour la communication et l’interaction avec le reste des fonctionnalités et les objets connectés.

La partie « client » recueille les commandes (vocales en ce qui nous concerne) et après reconnaissance les transmet au serveur NodeJs.
Grâce au fichier de grammaire défini dans chacun de nos plugins (NodeJs) S.A.R.A.H. détermine le code à exécuter.

Il suffit donc de coder la fonctionnalité et de renvoyer une réponse au format texte que S.A.R.A.H. va faire prononcer par Windows.

Architecture de la solution

1

La solution complète que nous avons retenu est constituée de :

  • Serveur Windows (un simple ordinateur peut faire l’affaire)
  • RaspberryPi 2 model B avec un dongle Wifi
  • Une webcam USB Logitech HD Pro C920 avec micro intégré
  • Haut-parleurs externes connectés sur le port Jack de la Raspberry

 

Une transaction classique se déroulera de la façon suivante :

1. La Raspberry capture l’audio et la transmet à S.A.R.A.H. via RTP grâce à FFMpeg
2. S.A.R.A.H. effectue le traitement et donne sa réponse audio
3. La réponse audio est transférée à la RaspberryPi via RTP grâce à FFMpeg et Virtual Audio Capture Grabber
4. La Raspberry « joue » la réponse audio reçu sur les haut-parleurs

Installation de S.A.R.A.H.

Nous avons donc décidé d’installer S.A.R.A.H. à l’aide de l’installateur blog.encausse.net/sarah/

Nous nous somme basé sur la version 4.0 Bêta, le module RTP ne fonctionnant pas sur la version 3.
Nous reviendrons plus tard sur cette fonctionnalité.

Nous avons également installé les modules suivants pour faire fonctionner la solution :

 

Installation RaspberryPi

Nous avons choisi de nous baser sur la distribution Raspbian.

Il nous a ensuite fallut installer :

 

Interconnexion S.A.R.A.H. et RaspberryPi

Une fois que le client et le serveur S.A.R.A.H. sont démarrés, nous allons pouvoir leur envoyer des commandes vocales.

Pour pouvoir capturer l’entrée audio depuis la Raspberry on lance la commande suivante :

arecord -D hw:0,0 -f S16_LE -r 16000 -c 2 -t wav | ffmpeg -i pipe:0 -bufsize 64k -ac 2 -f "volume=20dB"  -ar 16000 -acodec pcm_s16le -f rtp rtp://[IP_SERVER_SARAH]:7887

-D hw:0,0  » correspond au device de capture.
Pour trouver l’id de votre périphérique de capture, il vous suffira de lancer la commande « arecord -l », ils seront alors tous listés avec un ID de « device » et de « subdevice »

 

Maintenant les commandes vocales devraient être reconnues par S.A.R.A.H. mais la réponse audio se fera entendre sur l’ordinateur sur lequel S.A.R.A.H. est installée.

Pour pouvoir faire suivre les réponses vers la RaspberryPi. Il faut lancer le l’utilitaire de Virtual Audio Capture Grabber

Démarrer > Tous les programmes > Screen Capture Recorder > Record > broadcast > Setup local audio broadcast streaming server

Ensuite lancer l’invité de commande de Windows puis exécuter la commande suivante :

ffmpeg -f dshow -i audio="virtual-audio-capturer" -acodec libmp3lame -f rtp rtp://[IP_RASPBERRY_PI]:7888

Maintenant, Il suffit de parler dans le micro de la webcam reliée à la Raspberry et ainsi recevoir la réponse instantanément sur la sortie audio.

 

Mise en place de la reconnaissance faciale

La mise en place de la reconnaissance faciale est décrite en détail dans l’article suivant : Reconnaissance faciale avec OpenCV

Je vais quand même décrire le principe de fonctionnement que nous avons mis en place.

Nous avons décomposé la reconnaissance faciale en deux parties.
En effet, principalement pour des raisons de performances, nous avons découpé la reconnaissance faciale comme suit :

1. Le script de détection de visages est lancé sur la Raspberry en tâche de fond
2. Une fois qu’un ou plusieurs visages sont détectés, la ou les photos découpées des visages sont transmises sur le serveur S.A.R.A.H. (qui est également un serveur Web NodeJs)
3. Le contrôleur coté S.A.R.A.H. dépose les fichiers dans un dossier en attente de traitement et met à jour une table avec le nombre de personnes détectées devant la Raspberry
4. Le script de reconnaissance faciale est lancé sur le même serveur ou se situe S.A.R.A.H.
5. Ce script scanne en permanence le dossier contenant les photos déposées par le détecteur de visages
6. Il va ensuite effectuer la reconnaissance faciale et loguer les noms des personnes reconnues en BDD
7. Il suffit désormais de faire une requête en BDD depuis n’importe quel handler de commande S.A.R.A.H. pour savoir si une ou plusieurs personnes se situent devant la Webcam et si elles ont été reconnues.
Ainsi, nous pouvons personnaliser encore plus les réponses de l’assistant et imaginer des questions du type « S.A.R.A.H. est-ce que J’ai des RDV aujourd’hui ? », la réponse devenant contextuelle à l’interlocuteur de S.A.R.A.H qui interrogera par exemple le calendrier Outlook de la personne reconnue.

Difficultés rencontrées

Voilà maintenant notre solution entièrement fonctionnelle. Mais cela n’a pas été une promenade de santé.

Nous avons en effet rencontrés de nombreuses difficultés que nous avons eu à surmonter pour arriver à une solution fonctionnelle. Je ne citerais que les 2 principales :

La transmission audio

La transmission audio n’a pas été simple à mettre en place au début car nous avions utilisé la première webcam que nous avions eue sous la main, pensant que cela pourrait faire l’affaire.
Ainsi, nous avons été incapables de faire reconnaître quoi que ce soit à S.A.R.A.H. via la transmission RTP jusqu’à ce que nous changions de Webcam.
Le fait de de passer sur une webcam avec une capture audio digne de ce nom, nous a permis de trouver notre salut.
Pensez donc à vous équiper d’une webcam disposant d’un bon micro. De notre côté, nous avons trouvé notre bonheur via la Logitech HD Pro C920.

Performances

Au début, nous avions décidé de mettre la capture audio, la détection de visages et la reconnaissance faciale sur la Raspberry. Nous avions surestimé grandement la puissance de cette dernière et nous nous sommes retrouvé avec des décalages de détection/reconnaissance faciale de l’ordre de 4 secondes, avec des pointes de consommation mémoire et CPU de l’ordre de 99%.

Après de nombreux tests nous avons finalement conservé uniquement la détection de visage sur la Raspberry et avons déporté la reconnaissance faciale sur un serveur bien plus puissant.

Conclusion

Cet article décrit le cheminement de notre réflexion pour mettre en place un assistant d’accueil, en intégrant des solutions open source et peu coûteuses.

On peut voir qu’aujourd’hui, il est relativement simple (en étant un peu bidouilleur) de mettre en place ce genre d’installation.

La seule limite est finalement l’imagination et les possibilités d’interfaçage avec d’autres services ou fonctionnalités.

Nous allons continuer à améliorer notre solution et espérons bientôt pouvoir publier une vidéo de démonstration de notre assistant dans des conditions d’utilisation normales.

Pourquoi intégrer TypeScript à ses équipes web?

0

Aujourd’hui, le JavaScript est partout, aussi bien sur les sites Web (JQuery, AngularJS), sur les serveurs Web (NodeJS) que dans les applications mobiles (WinJS ou Apache Cordova). Microsoft a longtemps cherché à fournir aux développeurs .NET des alternatives, comme les controles sous ASP.NET WebForms pour leurs faciliter la vie. Mais cet âge sombre est révolu et le géant de Redmond se fait pardonner en nous offrant un langage qui permet de faire le pont entre C# et JavaScript, j’ai nommé TypeScript. 

Avoir des développeurs .NET séniors c’est super, surtout quand on a besoin de faire des applications .NET : ils sont compétents et efficaces. Mais parce qu’il est probable qu’ils aient débuté avec ASP.NET WebForms, ou avec technologies de clients lourds comme Winforms ou WPF, ils ont naturellement tendance à favoriser les contrôles serveurs sur le JavaScript client.

Les développeurs juniors sont mieux armés car JavaScript est définitivement à la mode, mais le manque d’expérience sur un langage objet par prototype ne pardonne pas. Il n’est pas rare de voir de très grandes disparités de qualité de production entre deux personnes avec à priori la même expérience.

Bref le JavaScript, sauf à partir du moment où il travaille essentiellement avec ASP.NET MVC, proche du web moderne et du JavaScript, n’est pas vraiment critique pour un développeur exclusivement .NET. Et c’est un problème dans un monde où les applications sont de plus en plus hybrides. Le développeur .NET possède les outils cognitifs et l’expérience pour exploiter au maximum le paradigme objet de classe comme on le trouve en C#, en Visual Basic ou en Java. En revanche maîtriser le paradigme objet de prototype qu’on trouve en JavaScript est un effort. C’est une sortie de la zone de confort et la montée en compétence peut parfois être très lente. C’est précisément pour palier à ce type de situation, avec des compétences en programmation orientée objet mais un déficit en JavaScript, que les équipes de Microsoft ont conçu TypeScript.

Le langage TypeScript est utilisé en interne par Microsoft pour la grande partie des travaux JavaScript récent, tel Babylon.js leur moteur 3D pour le Web par exemple. Il possède 2 grandes forces que je vais expliquer à mesure que je vais présenter son fonctionnement : la barrière d’apprentissage quasi-nulle et le fait que l’intégrer représente une prise de risque réellement nulle pour vos projets aussi bien à court terme qu’à long terme.

Comparons les spécifications du C#, du JavaScript et du TypeScript :

C# JS TS
Paradigme objet Classe Prototype Classe
Typage  Statique et dynamique Dynamique Statique et dynamique
Gestion des libraires Simple Simple Simple
Debug Visual Studio Navigateur Visual Studio

On observe donc que le TypeScript a effectivement été développé depuis sa conception initiale pour pouvoir s’intégrer aux travaux en NET. On remarque d’ailleurs que le père du TypeScript est Anders Hejlsberg, également architecte du C#, du Delphi et du Turbo Pascal.

Tout d’abord, il faut savoir que TypeScript est un langage qui va être compilé en JavaScript, que le compilateur de TypeScript a été conçu en TypeScript et que, par conséquence, il est possible de le compiler via Visual Studio 2013.2+ et 2015 (logique pour une technologie Microsoft) mais aussi via Node.JS (logique pour un programme en JavaScript). Autre conséquence directe, puisque le compilateur est un outil autonome, on peut développer en TypeScript avec une myriade d’IDE : Visual Studio 2013.2+ donc, WebStorm, Eclipse, Sublime Text, VI, Emacs et Atom (au moment de la rédaction de ce billet), pour seulement ensuite le compiler en JavaScript.

Revenons sur le langage en lui-même. TypeScript est open source, il est d’ailleurs disponible sur GitHub, et vise à intégrer les spécifications de ECMAScript 6, l’avenir de JavaScript.

En pratique, pourquoi est-ce que le TypeScript est un outil naturellement accessible ? Parce que c’est du JavaScript. Du JavaScript où nous allons pouvoir optionnellement décrire le type des variables de manière statique.

La présence de typage statique offre la possibilité à Intellisense de signaler quand le développeur commet une erreur de type sans que celui-ci ne soit contraint d’engager une démarche fastidieuse pour trouver l’origine de ces erreurs,  ce qui va se traduire en gain de temps substantiel.

 

typescript1

 

Ainsi si vous compilez du code JavaScript en JavaScript via le compilateur TypeScript, il n’y aura aucune différence entre le code d’entrée et le code de sortie. Autrement dit, tout code JavaScript est du code TypeScript.

Le compilateur va uniquement transformer un certain nombre de structures et de syntaxes en JavaScript. Cela tombe bien, car ces structures sont celles, à quelques détails près, du C#.

 

typescript2

typescript3

 

Et cela même dans les fonctionnalités complexes comme les lambdas, les génériques et les inférences de type. Les classes seront transformées en fonctions de prototypage. Il existe même la possibilité d’utiliser des spécificateurs d’accès mais uniquement dans du code TypeScript à typage statique (public, protected et private, en leurs absences la valeur par défaut est public et non protected comme en C#, dans un souci d’harmonie avec le JavaScript). Les interfaces peuvent être implémentées de manière implicite, ce qui facilite l’utilisation à certaines librairies.

L’héritage est également présent, avec son lot de notions à garder en tête par rapport au JavaScript.

 

typescript4

typescript5

typescript6

typescript7

 

Grâce à IntelliSense et au compilateur, nous instaurons un certain cadre de développement, afin de toujours garder une cohérence entre les structures que nous définissons et ce que l’on peut écrire, même quand le JavaScript n’est pas aussi strict. Une notion important en TypeScript est le comportement du mot-clé « this » : en TypeScript, « this » fait toujours référence à l’objet qui appelle la méthode. Le type de « this » dépends donc de sa position.

Donc si on récapitule, les développeurs vont écrire du simili-C# en JavaScript. C’est un coup à prendre mais un coût en temps humain bien inférieur à l’adoption de CoffeeScript, Dart ou d’un autre langage qui propose d’accélérer le travail des développeurs en JavaScript. Non seulement l’adoption est rapide mais elle tellement rapide que quelques heures suffisent pour permettre à un développeur d’augmenter son efficacité.

Si on revient sur le processus d’utilisation du TypeScript, on a vu que l’on  génére du code JavaScript. Donc si pour une raison quelconque, vous ne souhaitez plus utiliser TypeScript, il vous suffit de générer une dernière fois vos fichiers .js et de supprimer vos fichiers .ts. Voilà, votre migration est faîtes. Vous trouverez des exemples de codes ainsi que les spécifications détaillées sur le site http://www.typescriptlang.org/.

Il existe des outils très pratiques, comme TypeLite par exemple, qui va permettre de transformer des interfaces en C# .NET vers du TypeScript.

Finalement, TypeScript est un langage à mi-chemin entre JavaScript et C#. Il convient donc d’avoir à l’esprit les particularités du JavaScript et du C# lors de son utilisation. Malgré tout, l’intégration dans Visual Studio et la disponibilité d’outils en ligne gratuit offre un gain d’efficacité qui permettra à une équipe peu performante dans ses clients légers de produire des applications web évoluées ainsi que d’amener des perspectives différentes comme la découverte de Node.JS.