Bij Harmony Group geloven we dat cutting-edge technologie zoals AI en VR toegankelijk moet zijn—niet intimiderend.
Daarom besloot onze tech lead Owen Corstens te laten zien hoe makkelijk het eigenlijk is om deze technologieën te integreren met het low-code platform van OutSystems.
In deze blogreeks neemt Owen je stap voor stap mee in zijn experimenten. Of je nu developer, business leader of gewoon techliefhebber bent: je zal zien hoe platforms als OutSystems innovatie kunnen versnellen. Let’s dive in! 🏊
Toen ik dit project voor het eerst voor me zag, had ik één duidelijk doel: ik wilde een Virtual Reality-scene maken in OutSystems, waarbij ik de hele wereld om me heen kon bouwen... gewoon door ermee te praten. En het beste deel? Ik wilde niets vooraf definiëren—niet de omgeving, niet de OutSystems-database. AI moest al het zware werk doen. Waarom zou ik het zelf doen? 😉
Belangrijk detail: we bouwen een webapplicatie. Omdat we OutSystems gebruiken en dit in VR willen laten werken, leek dat gewoon de meest logische keuze.
🎯 Cool doel, maar waar begin je?
De eerste stap leek me: zorgen dat mijn stem überhaupt gehoord wordt door de applicatie. Dus ik begon simpel. Het enige doel was: praten tegen de app. Er zijn allerlei manieren om dat voor elkaar te krijgen, maar toen ik ongeveer een jaar geleden begon te experimenteren met speech listeners, had ik daar nog amper ervaring mee.
Ik koos dus voor iets vertrouwds: de ingebouwde WebKitSpeechRecognition
API. Die had ik eerder al gebruikt voor een hackathon, dus dat voelde veilig als startpunt.
Deze web speech API is onderdeel van de browser, maar wat ik toen nog niet wist (en pas ontdekte tijdens de implementatie): het is nog steeds een experimentele feature. En dat zou al snel belangrijk blijken.
Na het opzetten van de juiste listeners en methodes leek alles best soepel te werken. Ik moest het gewoon triggeren—et voilà, hij begon te luisteren.

Nice! Ik zat duidelijk op het juiste spoor—mijn stem op het scherm zien verschijnen voelde als een overwinning 😎😎 Maar helaas, de Web Speech API was niet ideaal. Hij had echt moeite met mijn prachtige accent. Ik liet het me niet teveel raken—ik was vooral op zoek naar een happy flow.
Maar toch kreeg ik veel rare en foute resultaten. Zoals die keer dat ik zei: “make the box with ID object one smaller,” en hij iets opving over ‘warmte’. En dat was al mijn derde poging…
Dus ja, niet ideaal.
We gingen door. De volgende stap: zorgen dat de speech listener automatisch geactiveerd werd—geen knopjes meer moeten indrukken telkens. Dat betekende dat ik iets nodig had als een Wake Word Function. Klinkt cool, toch?\
Na wat snelle research ontdekte ik dat er tools zijn zoals Picovoice die dat voor je doen. Maar natuurlijk wilde ik het zelf bouwen. Makkelijker gezegd dan gedaan.
Ik ging opnieuw creatief aan de slag met WebKitSpeechRecognition
. Door een continuous listener te gebruiken, hield ik de microfoon open. We voegden logica toe zodat hij alleen reageerde op een specifieke command, niet op alles wat ik zei.

Na flink wat trial-and-error werkte het eindelijk—de app reageerde als ik het juiste commando zei. Zoals je al zag in de titel: mijn trigger phrase werd “Hey Daisy.” Oorspronkelijk wilde ik “Hey AIRY,” omdat dat de projectnaam is, maar de API snapte AIRY niet zoals ik het uitsprak thuis. Dus werd het Daisy 😅
Om het echt een Wake Word te maken, moest hij ook luisteren terwijl ik de app niet actief gebruikte. En daar liep ik vast. Zowel iOS als Android blokkeerden een open audioverbinding op de achtergrond. Er zijn shady workarounds, maar die wilde ik voorlopig vermijden.
🙌 ALRIGHT! Alles leek nu op z’n plek te vallen… toch?
Niet helemaal.
Later, tijdens het testen in een VR-omgeving, reageerde niets meer op mijn commando’s. In de gewone browser werkte alles, maar in de VR-omgeving leek het alsof hij me niet hoorde.

Na eindeloos testen en debuggen ontdekte ik de oorzaak: de browser speech APIs worden simpelweg niet ondersteund in de META-browser op de Quest 2. Zelfs alternatieve browsers werkten niet. Tja, experimenteel dus.
Ik maakte een pivot. Wat als ik de commando’s vanaf een ander toestel zou sturen? Omdat de speech wel werkte op mijn desktop én telefoon, leek dat haalbaar.
Nieuwe challenge: hoe krijg ik die commando’s in de headset?
Met OutSystems was het makkelijk om data naar de server te sturen. Maar hoe krijg je die data terug naar de VR-client? Dat was lastiger.
Eerst probeerde ik polling—maar dat belastte de client veel te hard. Geen goed idee. En ja, API’s openen... daar was ik al eerder op afgebrand door een OutSystems tech expert 😅. Timers probeerde ik ook, maar dat loste niks op.
Na wat ChatGpting (yup, we maken er een werkwoord van, net als googlen), stuitte ik op websockets. Dit klonk als een oplossing!
Ik dook erin, begon from scratch en... belandde meteen in het Amazon-universum 😖 Zoveel nieuwe dingen waar ik nul ervaring mee had. Maar hey, ik hou wel van een uitdaging.
(We gaan het opzetten van een websocket in OutSystems behandelen in de volgende blog—nu even focus houden op de speech.)
En jawel, met een websocket werkte het! De omgeving hoorde me eindelijk. Perfect! Maar natuurlijk: los je één probleem op, krijg je er een ander voor terug.
Dat probleem kende ik eigenlijk al, maar had ik genegeerd tot nu. De speech API herkende mijn commando’s niet goed. Soms moest ik een zin tien keer herhalen. Super frustrerend. En het ergste? Je weet nooit waar het fout loopt: speech API? Websocket? AI? Of gewoon slecht verstaan?
Dus… ik gooide alles weg :)
Soms is opnieuw beginnen gewoon het beste. 💡
We hebben de hele command-passing feature gedropt (ik hield het niet droog 🥺). Ik besloot over te stappen naar de Azure Speech APIs. Die gebruikte ik ook bij de hackathon. Niet gratis, maar de hoofdpijn was het niet waard. Ik overwoog Amazon ook, met hun gratis credits, maar ik bleef toch bij Azure.

⚠️ Side note: OutSystems importeert libraries op een specifieke manier—later meer daarover. Voor nu: importeer gewoon de Azure Speech SDK webpack in je OS-project.
Alright, deze blog wordt lang—je bent er bijna! En ja, je krijgt straks de component te zien 😉
Na het toevoegen van Azure Speech API werkte alles bijna perfect. Maar ja, elk opgelost probleem brengt nieuwe mee. Dit keer twee.
De AI probeert je zin te verbeteren. Klinkt handig, maar daardoor herkende hij mijn trigger niet meer. Hij begon komma’s toe te voegen. Mijn oplossing: ik veranderde de command van “Hey Daisy” naar gewoon “Daisy.” Ik zeg nog steeds “Hey Daisy,” maar de continuous listener mist soms het begin, en dat zorgde dat het vaak faalde.

Autoplay policies in browsers. Als je ooit geprobeerd hebt een microfoon of camera meteen na een redirect te openen, dan weet je: dat werkt niet. De WebKit Speech werkte prima direct bij het laden. Maar de Azure SDK? Nope. Geen error, geen waarschuwing.
De fix: ik had een user gesture nodig. In plaats van moeilijke workarounds maakte ik gewoon een startscherm met één grote knop om de app te starten. Simpel. Effectief.
🎉 En daar was het dan: mijn finale fix!
Het was een geweldige rit om het speech-systeem te krijgen zoals ik het voor ogen had. Na al die obstakels hebben we nu een werkende Wakeword Function die mijn voice commands omzet in echte acties in de app.
De WakewordFunction Forge-componenten zijn nu te downloaden! Je krijgt een library component én een demo app (alleen ODC voorlopig). Test het uit, verbeter het en geef vooral feedback :) Ik ben er 100% klaar voor om nog betere WakewordFunctions te bouwen! 💖

Ik heb onderweg een paar mentale crashes gehad, maar ben blij dat ik ben blijven doorzetten. Dit speech-gedeelte is echt een kernonderdeel van mijn project geworden.