Voice-Kontrollerte Web-Effekter med Vue.js og maskinlæring

0
14

I denne opplæringen vil vi par Vue.js, three.js og LUIS (Kognitiv Services) til å opprette en stemme-kontrollerte web-visualisering.

Men først en liten sammenheng

Hvorfor skulle vi trenger for å bruke talegjenkjenning? Hva kan problemet noe sånt som dette løse?

For en stund siden var jeg komme på en buss i Chicago. Buss-sjåføren fikk ikke se meg og lukket døren på håndleddet mitt. Da han begynte å gå, hørte jeg en smellende lyd i håndleddet mitt, og det gjorde han etter hvert slutte som de andre passasjerene begynte å rope, men ikke før han dratt noen sener i armen min.

Jeg skulle ta fri fra jobben men, typisk for museets ansatte på den tiden, jeg var på kontrakt, og hadde ingen reell helseforsikring. Jeg hadde ikke gjøre mye til å begynne med så det tar tid av var bare ikke et alternativ for meg. Jeg jobbet gjennom smerte. Og, til slutt, helse håndleddet mitt begynte å svekkes. Det ble veldig vondt å selv børste tennene mine. Tale-til-tekst-var ikke den allestedsnærværende teknologi som det er i dag, og det beste verktøyet for deretter var det Dragon. Det fungerte OK, men det var ganske frustrerende å lære, og jeg hadde fortsatt å bruke mine hender ganske ofte, fordi det vil ofte feil ut. Det var for 10 år siden, så jeg er sikker på at særlig tech har forbedret seg betydelig siden da. Håndleddet mitt har også bedret seg betydelig i den tiden.

Hele opplevelsen har gjort meg med en interesse i å talestyrt teknologier. Hva kan vi gjøre hvis vi kan styre atferd på nettet i vår favør, bare ved å snakke? For et eksperiment, jeg bestemte meg for å bruke LUIS, som er en maskin læring-basert tjeneste til å bygge naturlig språk gjennom bruk av spesialtilpassede modeller som kan stadig bli bedre. Vi kan bruke dette for apps, boter, og IoT enheter. På denne måten kan vi lage en visualisering som svarer til noen stemme — og det kan forbedre seg selv ved å lære underveis.

GitHub-Repo

Live-Demo

Her er en fugleperspektiv over hva bygger vi:

Sette opp LUIS

Vi vil få en gratis prøveversjon konto for Azure og deretter gå til portalen. Vi velger Kognitiv Tjenester.

Etter å plukke Nye → AI – /Maskin-Læring, vil vi velge “Language Forståelse” (eller LUIS).

Så får vi plukke ut vårt navn og ressursgruppe.

Vi vil samle våre nøkler på den neste skjermen og deretter gå over til LUIS dashboard

Det er faktisk veldig gøy å trene disse maskinene! Vi vil sette opp en ny applikasjon og lage noen hensikt, som er resultater vi ønsker å utløse basert på en gitt tilstand. Her er et eksempel fra denne demoen:

Du legger kanskje merke til at vi har en navngivingspraksis her. Vi gjør dette slik at det er enklere å kategorisere fullbyrdet. Vi kommer til å først finne ut følelser og deretter lytte til intensitet, så den opprinnelige hensikter er prefikset med enten App (disse brukes først og fremst i Appen.vue komponent) eller Intensitet.

Hvis vi dykke inn i hver bestemt hensikt, vil vi se på hvordan modellen er trent. Vi har noen liknende uttrykk som betyr omtrent det samme:

Du kan se har vi en rekke synonymer for trening, men vi har også “Trene” – knappen øverst for når vi er klar til å begynne å trene modellen. Vi klikker på denne knappen, får en suksess varsel, og vi er klar til å publisere. 😀

Sette opp Vue

Vi vil opprette en ganske standard Vue.js program via Vue CLI. Først skal vi kjøre:

vue lage tre-vue-mønster
# velg deretter Manuelt…

Vue CLI v3.0.0

? Vennligst velg en forhåndsinnstilling:
standard (babel, eslint)
“Manuelt velge funksjoner

# Velg deretter PWA-funksjonen og de andre med mellomrom
? Vennligst velg en forhåndsinnstilling: Manuelt valg av funksjoner
? Sjekk de funksjoner som trengs for prosjektet:
◉ Babel
◯ Maskinskrevet kopi
◯ Progressive Web App (PWA) Støtte
◯ Ruter
◉ Vuex
◉ CSS Pre-prosessorer
◉ Linter / Formatter
◯ Enhetstesting
◯ E2E Testing

? Velg en linter / formatter config:
ESLint med forebygging av feil bare
ESLint + Airbnb config
“ESLint + Standard config
ESLint + Penere

? Plukke flere lo-funksjoner: (Trykk <space> for å velge, til å slå alle, jeg til å invertere utvalget)
“◉ Lo på lagre
◯ Lo og fikse på begå

Opprettet prosjektet tre-vue-mønster.
Komme i gang med følgende kommandoer:

$ cd-tre-vue-mønster
$ garn tjene

Dette vil spinne opp en server for oss og gir et typisk Vue velkommen-skjermen. Vi vil også legge til noen avhengigheter til vår søknad: three.js, sinus-bølger, og axios. three.js vil du hjelpe oss å lage den WebGL-visualisering. sinus-bølger gir oss en fin lerret abstraksjon for lasteren. axios vil tillate oss en veldig fin HTTP klienten, slik at vi kan foreta anrop til LUIS for analyse.

garn legge til tre sinus-bølger axios

Sette opp vår Vuex butikk

Nå som vi har en fungerende modell, la oss gå og få det med axios og bringe det inn i vår Vuex store. Da kan vi spre informasjon til alle de forskjellige komponentene.

I staten, lagrer vi hva vi kommer til å trenge:

tilstand: {
hensikt: ‘Ingen’,
intensitet: ‘Ingen’,
score: 0,
uiState: ‘inaktiv’,
zoom: 3,
skranke: 0,
},

hensikt og intensitet vil lagre App, intensitet, og hensikter, henholdsvis. Poengsummen vil butikken vår tillit (som er en score fra 0 til 100 måle hvor godt modellen mener det kan rangere inngang).

For uiState, har vi tre ulike tilstander:

  • inaktiv – venter for brukeren inngang
  • lytte – å høre brukerinndata
  • hente – å bli bruker data fra API

Både zoom og counter er hva vi skal bruke for å oppdatere data visualisering.

Nå, i handlinger, vil vi sette uiState (en mutasjon) for å hente, og vi vil foreta et anrop til API med axios bruke den genererte nøkler fikk vi da sette opp LUIS.

getUnderstanding({ begå }, tale) {
commit(‘setUiState’, ‘hente’)
const url = `https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/4aba2274-c5df-4b0d-8ff7-57658254d042`

https: axios({
metode: ‘få’,
url,
params: {
detaljert: true,
timezoneOffset: 0,
q: ytring
},
overskrifter: {
‘Content-Type’: ‘application/json’,
‘Ocp-Apim-Abonnement-Key’: ‘XXXXXXXXXXXXXXXXXXX’
}
})

Så, når vi har gjort det vi kan få topp-rangert scoring hensikt og lagre det i vår stat.

Vi trenger også å lage noen mutasjoner som vi kan bruke til å endre tilstand. Vi vil bruke disse i våre handlinger. I den kommende Vue 3.0, vil dette være strømlinjeformet fordi mutasjoner vil bli fjernet.

newIntent: (stat, { hensikt, score }) => {
hvis (hensikter.inkluderer(‘Intensitet’)) {
staten.intensitet = hensikt
hvis (hensikter.inkluderer(‘Mer’)) {
staten.counter++
} else if (hensikter.inkluderer(‘Mindre’)) {
staten.counter–
}
} else {
staten.hensikten = hensikt
}
staten.resultat = resultat
},
setUiState: (stat, status) => {
staten.uiState = status
},
setIntent: (stat, status) => {
staten.hensikten = status
},

Dette er alle ganske grei. Vi passerer i staten, slik at vi kan oppdatere det for hver forekomst — med unntak av Intensitet, som vil øke telleren opp og ned tilsvarende. Vi kommer til å bruke som teller i den neste delen for å oppdatere visualisering.

.deretter(({ data }) => {
– konsollen.logg(‘axios resultat”, data)
hvis (altMaps.hasOwnProperty(data.spørringen)) {
commit(‘newIntent’, {
hensikt: altMaps[data.søket],
poeng: 1
})
} else {
commit(‘newIntent’, data.topScoringIntent)
}
commit(‘setUiState’, ‘inaktiv’)
commit(‘setZoom’)
})
.catch(err => {
– konsollen.error(‘axios feil’, err)
})

I denne handlingen, vil vi forplikte mutasjoner vi bare gikk over eller logg en feilmelding hvis noe går galt.

Slik at logikken fungerer, brukeren vil gjøre den første opptak for å si hvordan de føler seg. De vil trykke på en knapp for å sparke det hele av. Visualiseringen skal vises, og på det punktet vil programmet kontinuerlig lytte for brukeren å si mindre eller mer for å styre tilbake visualisering. La oss sette opp resten av appen.

Sette opp appen

I Appen.vue, skal vi vise to forskjellige komponenter for midten av siden, avhengig av hvorvidt vi allerede har angitt vår humør.

<app-recordintent v-hvis=”intensjon === ‘Ingen'” />
<app-recordintensity v-hvis=”intensjon !== ‘Ingen'” :følelser=”hensikt” />

Begge disse vil vise informasjon for brukeren, så vel som en SineWaves komponent mens du UI er i et lyttende tilstand.

Basen av programmet er der visualisering vil bli vist. Det vil vise med ulike virkemidler avhengig av humøret. Her er to eksempler:

<app-base
v-hvis=”intensjon === ‘Begeistret'”
:t-config.a=”1″
:t-config.b=”200″
/>
<app-base
v-hvis=”intensjon === ‘Nervøs'”
:t-config.a=”1″
:color=”0xff0000″
:trådnett=”true”
:rainbow=”false”
:emissive=”true”
/>

Sette opp data visualisering

Jeg ønsket å jobbe med kaleidoskop-lignende bilder for visualisering og, etter litt leting, fant denne repo. Måten det fungerer på er at en form slår på plass og dette vil bryte bilde fra hverandre og vise deler av det som et kaleidoskop. Nå, det høres kanskje fantastisk fordi (yay!) arbeidet er gjort, ikke sant?

Dessverre ikke.

Det var en rekke store endringer som måtte gjøres for å gjøre dette arbeidet, og det er faktisk endte opp med å bli en massiv oppgave, selv om den endelige visuelle uttrykket vises lik den originale.

  • På grunn av det faktum at vi trenger å rive ned visualisering hvis vi besluttet å endre det, jeg hadde for å konvertere eksisterende kode for å bruke bufferArrays, som er mer effektivt for dette formålet.
  • Den opprinnelige koden var en stor klump, så jeg slo opp noen av funksjonene i mindre metoder på komponent for å gjøre det enklere å lese og vedlikeholde.
  • Fordi vi ønsker å oppdatere ting på sparket, jeg hadde til å lagre noen av elementene som data i komponenten, og til slutt som rekvisitter at det ville få fra den overordnede. Jeg har også tatt noen fine defaults (spent er hva alle standardinnstillingene se ut som).
  • Vi bruker counter fra Vuex staten til å oppdatere avstand av kameraets plassering i forhold til objektet, slik at vi kan se mindre eller mer av det og dermed blir det mer og mindre komplekse.

For å endre opp slik at det ser ut i henhold til konfigurasjonene, vi vil lage noen rekvisitter:

rekvisittar: {
numAxes: {
type: Antall,
standard: 12,
nødvendig: false
},

tConfig: {
standard() {
tilbake {
a: 2,
b: 3,
c: 100,
d: 3
}
},
nødvendig: false
}
},

Vi vil bruke disse når vi lage figurene:

createShapes() {
dette.bufferCamera.posisjon.z = dette.shapeZoom

hvis (denne.torusKnot !== null) {
dette.torusKnot.materiale.kast()
dette.torusKnot.geometri.kast()
dette.bufferScene.fjern(denne.torusKnot)
}

var shape = new TRE.TorusKnotGeometry(
dette.tConfig.a,
dette.tConfig.b,
dette.tConfig.c,
dette.tConfig.d
),
materiale

dette.torusKnot = new TRE.Mesh(form, materiale)
dette.torusKnot.materiale.needsUpdate = true

dette.bufferScene.legg til(denne.torusKnot)
},

Som vi har nevnt før, dette er nå delt ut i sin egen metode. Vi vil også opprette en annen metode som går av animasjonen, som også vil starte når den oppdateres. Animasjonen gjør bruk av requestAnimationFrame:

animate() {
dette.storeRAF = requestAnimationFrame(denne.animere)

dette.bufferScene.rotasjon.x += 0.01
dette.bufferScene.rotasjon.y += 0.02

dette.renderer.render(
dette.bufferScene,
dette.bufferCamera,
dette.bufferTexture
)
dette.renderer.render(denne.scene, dette.kamera)
},

Vi vil opprette en beregnet eiendom kalt shapeZoom som vil returnere zoom fra butikken. Hvis du husker, dette vil bli oppdatert etter brukerens stemme endringer intensitet.

beregnet: {
shapeZoom() {
gå tilbake til denne.$butikken.staten.zoom
}
},

Vi kan da bruke en watcher å se om zoom-nivå endringer og avbryte animasjon, gjenskape former, og starte animasjonen.

se: {
shapeZoom() {
dette.createShapes()
cancelAnimationFrame(denne.storeRAF)
dette.animate()
}
},

I data, kan vi også lagre noen ting vi trenger for å starte den three.js scene — særlig å sørge for at kameraet er nøyaktig sentrert.

data() {
tilbake {
bufferScene: nye TRE.Scene(),
bufferCamera: nye TRE.PerspectiveCamera(75, 800 / 800, 0.1, 1000),
bufferTexture: nye TRE.WebGLRenderTarget(800, 800, {
minFilter: TRE.LinearMipMapLinearFilter,
magFilter: TRE.LinearFilter,
antialias: true
}),
kamera: nye TRE.OrthographicCamera(
vinduet.innerWidth / -2,
vinduet.innerWidth / 2,
vinduet.innerHeight / 2,
vinduet.innerHeight / -2,
0.1,
1000
),

Det er mer til denne demoen hvis du ønsker å utforske repo eller sette den opp selv med dine egne parametre. Init-metoden ikke hva du tror det kanskje: det initialiseres hele visualisering. Jeg har kommentert mange av de viktigste delene hvis du kikket på kildekoden. Det er også en annen metode som oppdaterer geometri som heter — du uessed det — updateGeometry. Du kan merke en masse vars i det så vel. Det er fordi det er vanlig å bruke variabler i denne form for visualisering. Vi sparker alt av ved å ringe dette.init() i montert() lifecycle kroken.

  • Igjen, her er repo hvis du ønsker å spille med kode
  • Du kan lage din egen modell av å få en gratis Azure konto
  • Du vil også være lurt å sjekke ut LUIS (Kognitiv Tjenester)

Det er ganske morsomt å se hvor langt du kan få lage ting for web som ikke nødvendigvis trenger noen håndbevegelser til å styre. Det åpner opp mange muligheter!