Comment travailler avec JavaScript et Mendix | Mendix

Passer au contenu principal

Comment travailler avec JavaScript et Mendix

Comment travailler avec JavaScript et Mendix

Pendant le confinement, j'avais beaucoup de temps libre et, comme beaucoup de gens, j'ai passé la plupart de ce temps à regarder des séries et à faire des marathons de films. C'est lors d'un marathon de films de près d'un mois que j'ai eu envie de voir si je pouvais créer une application vocale dans Mendix en utilisant JavaScript.

Ceux qui connaissent les films de super-héros et autres genres de science-fiction seront familiers avec les acolytes numériques qui piratent les systèmes de sécurité et plus encore pour le protagoniste principal de l'histoire. Mais pour ma construction, je me concentrerais sur les aspects parole-texte et texte-parole de mon application vocale d'assistant numérique. Je veux dire, à quel point cela pourrait-il être difficile après tout ? Sans me soucier de ma propre santé mentale ou de mon niveau de stress, je me suis plongé tête la première dans l'abîme des technologies de synthèse vocale et de la façon de les implémenter en Javascript et Mendix.

« JavaScript est le seul langage que je connaisse dont les gens estiment qu'ils n'ont pas besoin d'apprendre avant de commencer à l'utiliser. »

— Douglas Crockford

L'idée

Le design est simple, enfin aussi simple que je pouvais le faire. L'idée est de créer un Mendix Une application capable d'entendre et de comprendre les mots prononcés par un utilisateur, puis de répondre par sa propre « voix ». Cela semble facile, n'est-ce pas ? Une fois que j'ai décidé du design, il était temps de rechercher les technologies existantes que je pourrais utiliser. Cela ne sert à rien de tout redévelopper à partir de zéro alors qu'il existe déjà de nombreuses plateformes vocales, telles que Watson d'IBM et Cloud AI Platform de Google.

Cependant, j'ai déjà créé des chatbots auparavant, l'année dernière. Mendix Monde, j'ai organisé une session Low Code live avec Jan de Vries. Au cours de la session, j'ai développé une compétence Alexa qui permettait à un utilisateur d'interagir avec un Mendix application, en parlant à Alexa. Cette fois-ci, j'ai décidé de me concentrer moins sur la conversation et le dialogue réels, et davantage sur l'aspect de la parole réelle de cette construction. Si vous souhaitez en savoir plus sur la création d'arbres de conversation, je vous recommande de regarder l'enregistrement de Mendix Monde 2020.

La conception

Alors, que vais-je réellement construire ? Après quelques recherches, j'ai opté pour un design, mon application se concentrerait sur 2 aspects principaux :

  1. Un widget enfichable Speech-to-Text qui pourra entendre et comprendre la voix de l'utilisateur.
  2. Une action JavaScript de synthèse vocale qui permettra à l'application de répondre à voix haute à l'utilisateur.

Pour le widget, j'utiliserais une bibliothèque que j'ai trouvée sur Github, qui utilise Bibliothèques de synthèse vocale de Mozilla.

Heureusement pour l'action JavaScript, je suis tombé sur un Tutoriel JavaScript créé par Mendix qui fait exactement cela dans notre propre documentation.

Enfin, dans les films, le héros a toujours un nom sympa pour son acolyte robotique. En l'honneur de cela, j'ai décidé de nommer mon application MAEVIS Qui veut dire "MendixSystème génial, excellent et très intelligent »

Bâtiment MAEVIS

En général, lorsque je crée une application, j'essaie de me concentrer d'abord sur les processus les plus difficiles ou les plus complexes. Comme j'avais déjà une idée approximative de la manière de faire parler l'application, j'ai décidé de me concentrer sur la création du widget qui permettrait à MAEVIS de entends moi. Comme je l'ai mentionné ci-dessus, j'ai décidé d'utiliser ceci Bibliothèque by Nik Valdez sur Github.

J'ai utilisé l' Mendix Générateur de widgets pour créer mon échafaudage de widgets. J'ai choisi de le construire en utilisant JavaScript ES6 et il est conçu pour les applications Web et mobiles hybrides.

Le principal problème que j'ai rencontré en adaptant ce code pour qu'il fonctionne dans MAEVIS était que l'exemple utilise un composant fonctionnel et que l'échafaudage du widget génère le code en tant que composant de classe. Une fois que j'ai compris le problème, il a été simple de le résoudre.

J'ai fini avec ceci comme code de widget final :

import React,{ Component, createElement, useState, useEffect } from "react";
import "./ui/SpeechToText.css";
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const mic = new SpeechRecognition();
mic.continuous = true;
mic.interimResults = true;
mic.lang = 'en-US';
export default function SpeechToText(){
const [isListening, setIsListening] = useState(false);
const [note, setNote] = useState('');
const [savedNotes, setSavedNotes] = useState([]);
useEffect(() => {
handleListen()
}, [isListening]);
const handleListen = () => {
if (isListening) {
mic.start()
mic.onend = () => {
console.log('continue..')
mic.start()
}
} else {<mic.stop()
mic.onend = () => {
console.log('Stopped Mic on Click')
handleSaveNote()
}
}
mic.onstart = () => {
console.log('Mics on')
}
mic.onresult = event => {
const transcript = Array.from(event.results)
.map(result => result[0])
.map(result => result.transcript)
.join('')
console.log(transcript)
//textAttribute(transcript)
setNote(transcript)
mic.onerror = event => {
console.log(event.error)
}
}
}
const handleSaveNote = () => {
setSavedNotes([...savedNotes, note])
setNote('')
}
return  <span className="flexColumn">
<>
<p>{note}</p>
<button
className={isListening ? 'pulse-button btn-danger' : 'pulse-button'}
onClick={() => setIsListening(prevState => !prevState)}>
{isListening ? <span>🎙️Stop</span> : <span>🛑Start</span>}
</button>
</>
<>
<h2>Notes</h2>
{savedNotes.map(n => (
<p key={n}>{n}</p>
))}
</&gt
</span>
}

J'ai également ajouté quelques styles pour modifier le front-end des widgets, afin qu'ils soient plus esthétiques que les boutons classiques sur un écran :

.flexColumn{
display: inline-flex;
flex-direction: column;
}
.container {
width: 200px;
height: 100%;
margin: 0 auto 0;
perspective: 1000;
-webkit-perspective: 1000;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
background: #fff;
}
.pulse-button {
position: relative;
margin: auto;
display: block;
width: 10em;
height: 10em;
font-size: 1.3em;
font-weight: light;
font-family: 'Trebuchet MS', sans-serif;
text-transform: uppercase;
text-align: center;
line-height: 100px;
letter-spacing: -1px;
color: white;
border: none;
border-radius: 50%;
background: #5a99d4;
cursor: pointer;
box-shadow: 0 0 0 0 rgba(90, 153, 212, 0.5);
-webkit-animation: pulse 1.5s infinite;
animation: pulse 1.5s infinite;
}
.pulse-button:hover {
-webkit-animation: none;
animation: none;
}
@-webkit-keyframes pulse {
0% {
-moz-transform: scale(0.9);
-ms-transform: scale(0.9);
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
70% {
-moz-transform: scale(1);
-ms-transform: scale(1);
-webkit-transform: scale(1);
transform: scale(1);
box-shadow: 0 0 0 50px rgba(90, 153, 212, 0);
}
100% {
-moz-transform: scale(0.9);
-ms-transform: scale(0.9);
-webkit-transform: scale(0.9);
transform: scale(0.9);
box-shadow: 0 0 0 0 rgba(90, 153, 212, 0);
}
}
@keyframes pulse {
0% {
-moz-transform: scale(0.9);
-ms-transform: scale(0.9);
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
70% {
-moz-transform: scale(1);
-ms-transform: scale(1);
-webkit-transform: scale(1);
transform: scale(1);
box-shadow: 0 0 0 50px rgba(90, 153, 212, 0);
}
100% {
-moz-transform: scale(0.9);
-ms-transform: scale(0.9);
-webkit-transform: scale(0.9);
transform: scale(0.9);
box-shadow: 0 0 0 0 rgba(90, 153, 212, 0);
}
}

Je dois dire que je considère que l'affichage de ce widget à l'écran est l'un de mes plus grands exploits de développement à ce jour, et c'est la première fois de ma vie que j'ai vraiment ressenti ce moment « AHA ! » en codant en JavaScript. Pour ceux qui se demandent combien de temps cela a pris, j'ai dû m'arracher les cheveux et crier sur mon ordinateur portable pendant environ 3 jours, mais au final, le résultat a été énorme pour moi.

La partie difficile étant terminée, il était facile de simplement suivre ceci tutoriel sur la création d'actions JavaScript.

En seulement une heure ou deux, j'ai eu une action qui pouvait lire à voix haute n'importe quel texte que je lui donnais comme paramètre. Pour ceux qui recherchent simplement le code, le voici, mais je vous recommande de suivre ce tutoriel si vous débutez avec les actions JavaScript dans Mendix.

// This file was generated by Mendix Studio Pro.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the import list
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Big } from "big.js";
// BEGIN EXTRA CODE
// END EXTRA CODE
/**
* @param {string} text
* @returns {Promise.<boolean>}
*/
export async function JS_TextToSpeech(text) {
// BEGIN USER CODE
if (!text) {
return false;
}
if ("speechSynthesis" in window === false) {
throw new Error("Browser does not support text to speech");
}
// const utterance = new SpeechSynthesisUtterance(text);
// window.speechSynthesis.speak(utterance);
// return true;
return new Promise(function(resolve, reject) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.onend = function() {
resolve(true);
};
utterance.onerror = function(event) {
reject("An error occured during playback: " + event.error);
};
window.speechSynthesis.speak(utterance);

});
// CODE UTILISATEUR FINAL
}

Il est temps de le tester

Alors sans plus tarder, je voudrais vous présenter à tous ma création MAÉVIS.

Emballage en place

Je tiens à souligner à quel point j'ai appris beaucoup de choses sur ce projet, et même si c'était un défi, je vous recommande vivement de l'essayer vous-même. J'aurais aimé ajouter plus à cette construction, mais avec d'autres projets vraiment passionnants en cours, je dois m'arrêter là.

Idéalement, je voulais que le widget lui-même déclenche le Nanoflow qui déclenche l'action JavaScript Text to Speech. Et je pense qu'il serait formidable d'utiliser des accessoires pour extraire le dialogue du widget dans Mendix, au lieu de simplement le stocker dans l'état du widget. Je continuerai à travailler sur ces fonctionnalités et je publierai peut-être un suivi à ce sujet à l'avenir, mais en attendant, je pense que c'est un excellent exercice pour vous tous d'essayer de faire exactement cela ! N'hésitez pas à me contacter si vous utilisez cela, j'aimerais voir quelles idées folles cela vous donne à tous. D'ici là, n'oubliez pas : allez-y !

Choisissez votre langue