Röststyrd Web Visualiseringar med Vue.js och maskininlärning

0
32

I denna handledning kommer vi att par Vue.js, three.js och LUIS (Kognitiv Tjänster) för att skapa en röststyrd webb-visualisering.

Men först, lite sammanhang

Varför skulle vi behöva använda röstigenkänning? Vad problemet kan något som detta att lösa?

Ett tag sedan jag var att komma på en buss i Chicago. Busschauffören ville inte se mig och stängde dörren om min handled. När han började att gå, hörde jag ett knäppande ljud i min handled och han gjorde så småningom att sluta som andra passagerare började skrika, men inte innan han slet av några senor i min arm.

Meningen var att jag skulle ta ledigt från jobbet, men typiskt för museum anställda vid den här tiden var jag på kontraktet och hade ingen riktig sjukförsäkring. Jag ville inte göra mycket till att börja med så tar ledigt bara inte var ett alternativ för mig. Jag arbetade igenom smärtan. Och, så småningom, hälsa på min handled började försämras. Det blev verkligen smärtsamt att ens borsta mina tänder. Röst-till-text inte var den allestädes närvarande tekniken som det är idag, och det bästa verktyget då tillgängliga var Dragon. Det fungerade OK, men var ganska frustrerande att lära sig och jag är fortfarande tvungen att använda mina händer ganska ofta eftersom det ofta fel. Det var 10 år sedan, så jag är säker på att allt tech har förbättrats betydligt sedan dess. Min handled har också förbättrats avsevärt under denna tid.

Hela upplevelsen lämnade mig med ett stort intresse för röst-kontrollerade tekniker. Vad kan vi göra om vi kan styra beteenden på webben i vår favör, bara genom att tala? För ett experiment, jag bestämde mig för att använda LUIS, som är en maskin lärande-baserad tjänst för att bygga naturliga språket genom hjälp av egna modeller, som kontinuerligt kan förbättra. Vi kan använda detta för appar, robotar, och sakernas internet enheter. På detta sätt kan vi skapa en visualisering som svarar för att inte någon röst — och det kan förbättra sig själv genom att lära sig längs vägen.

GitHub Repo

Live Demo

Här är ett fågelperspektiv av vad vi håller på att bygga:

Att sätta upp LUIS

Vi kommer att få ett gratis testkonto för Azure och sedan gå till portalen. Vi väljer Kognitiva Tjänster.

Efter att plocka Nya → AI/maskininlärning, vi kommer att välja “Språk Förståelse” (eller LUIS).

Sedan ska vi plocka ut våra namn och resurs gruppen.

Vi ska hämta ut våra nycklar från nästa skärm och sedan gå över till LUIS dashboard

Det är faktiskt riktigt kul att träna dessa maskiner! Vi ska ställa upp en ny ansökan och skapa några intentioner, vilka resultat vi vill att utlösa baserat på en given förutsättning. Här är provet från denna demo:

Du kanske märker att vi har en namngivning schemat här. Vi gör detta för att det är lättare att kategorisera de intentioner. Vi kommer att först räkna ut känslor och lyssna sedan på intensitet, så att den ursprungliga intentioner ska föregås av antingen App (dessa används främst i Appen.vue komponent) eller Intensitet.

Om vi dyka in i varje särskilt uppsåt, ser vi hur modellen är utbildad. Vi har några liknande fraser som betyder ungefär samma sak:

Du kan se att vi har många synonymer för utbildning, men vi har också “Träna” – knappen uppe för när vi är redo att börja träna modell. Vi klickar på den knappen, få en framgång anmälan, och sedan är vi redo att publicera. 😀

Att sätta upp Vue

Ska vi skapa en ganska standard Vue.js ansökan via Vue CLI. Först kör vi:

vue skapa tre-vue-mönster
# välj sedan Manuellt…

Vue CLI v3.0.0

? Vänligen välj en förinställd:
standard (babel, eslint)
“Manuellt välja funktioner

# Välj sedan PWA-funktionen och den andra med blanksteg
? Vänligen välj en förinställning: välj Manuellt funktioner
? Kontrollera funktioner som behövs för att ditt projekt:
◉ Babel
◯ TypeScript
◯ Progressiva Web App (PWA) Stöd
◯ Router
◉ Vuex
◉ CSS Pre-processorer
◉ Linter / Formatter
◯ Enhetstestning
◯ E2E Testning

? Välj en linter / formatter config:
ESLint med förebyggande av fel bara
ESLint + Airbnb config
“ESLint + Standard config
ESLint + Snyggare

? Plocka ytterligare ludd funktioner: (Tryck på <mellanslag> för att välja, a för att markera allt, jag för att invertera markering)
“◉ Ludd på spara
◯ Ludd och fixa på att begå

Skapat projektet tre-vue-mönster.
Komma igång med följande kommandon:

$ cd-tre-vue-mönster
$ garn tjäna

Detta kommer att snurra upp en server för oss och ger en typisk Vue på välkomstskärmen. Vi kommer även att lägga till några beroenden till vår ansökan: three.js, sinus-vågor, och axios. three.js kommer att hjälpa oss att skapa WebGL visualisering. sinus-vågor ger oss en fin duk abstraktion för lastaren. axios kommer att ge oss en riktigt fin HTTP kunden så att vi kan ringa till LUIS för analys.

garn lägg till tre sinus-vågor axios

Sätta upp vår Vuex butik

Nu när vi har en fungerande modell, låt oss få det med axios och föra in det i vår Vuex butik. Då kan vi sprida information till alla de olika komponenter.

I staten, kommer vi att lagra det som vi kommer att behöva:

tillstånd: {
avsikt: ‘Ingen’,
intensitet: ‘Ingen’,
betyg: 0,
uiState: ‘tom’,
zoom: 3,
disk: 0,
},

uppsåt och intensitet kommer att lagra Appen, intensitet och intentioner, respektive. Poängen kommer att lagra vårt förtroende (vilket är en poäng från 0 till 100 mäta hur väl modellen tror att det kan rangordna ingång).

För uiState, vi har tre olika tillstånd:

  • idle – väntar på användarens inmatning
  • att lyssna – att höra användarens input
  • hämta – användarnas data från API

Både zoom och disken är vad vi ska använda för att uppdatera data visualisering.

Nu, i åtgärder, ska vi ställa det uiState (mutation) för att hämta, och vi ska göra ett anrop till API med axios med den genererade nycklar som vi fick när du ställer upp och LUIS.

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

https: axios({
metod: ‘get’,
url-adressen,
params: {
verbose: sant,
timezoneOffset: 0,
q: yttrande
},
rubriker: {
‘Content-Type”: “application/json’,
‘Ocp-Apim-Prenumeration-Key’: ‘XXXXXXXXXXXXXXXXXXX’
}
})

När vi sedan har gjort att vi kan få de topp-rankade poäng uppsåt och lagra det i vårt land.

Vi behöver också skapa vissa mutationer kan vi använda för att förändra situationen. Vi kommer att använda dessa i våra handlingar. I den kommande Vue 3.0, det här kommer att effektiviseras eftersom mutationer kommer att tas bort.

newIntent: (stat, { uppsåt, betyg }) => {
om (uppsåt.innehåller(‘Intensitet’)) {
stat.intensitet = intent
om (uppsåt.innehåller (“Mer”)) {
stat.counter++
} else if (uppsåt.innehåller (“Mindre”)) {
stat.counter–
}
} else {
stat.avsikten = intent
}
stat.betyg = betyg
},
setUiState: (stat, status) => {
stat.uiState = status
},
setIntent: (stat, status) => {
stat.avsikten = status
},

Detta är alla ganska enkelt. Vi passerar i staten, så att vi kan uppdatera den för varje förekomst — med undantag av Intensitet, vilket kommer att öka räknare upp och ner, i enlighet med detta. Vi kommer att använda för att bekämpa i nästa avsnitt för att uppdatera visualisering.

.då(({ data }) => {
konsolen.log(‘axios resultat”, data)
om (altMaps.hasOwnProperty(data.query)) {
begå(‘newIntent’, {
avsikt: altMaps[data.frågan],
betyg: 1
})
} else {
begå(‘newIntent’, data.topScoringIntent)
}
begå(‘setUiState’, ‘tom’)
begå(‘setZoom’)
})
.catch(err => {
konsolen.error(‘axios fel”, err)
})

I denna åtgärd, kommer vi att begå mutationer vi gick bara över eller logga in fel om något går fel.

Hur logiken fungerar, kommer användaren att göra den första inspelningen för att säga hur de känner. De kommer att trycka på en knapp för att sparka det av. Visualisering kommer att visas, och på den punkten, kommer programmet kontinuerligt att lyssna för användaren att säga mindre eller mer för att styra tillbaka visualisering. Låt oss ställa upp resten av appen.

Ställa in app

I Appen.vue, vi ska visa två olika komponenter till mitten av sidan beroende på om vi har angetts på vårt humör.

<app-recordintent v-if=”avsikten === ‘none’ (Ingen)” / >
<app-recordintensity v-if=”uppsåt !== ‘Ingen'” :emotion=”uppsåt” />

Båda dessa kommer att visa information för betraktaren liksom en SineWaves komponent medan UI är i lyssnande staten.

Basen av ansökan är där visualisering kommer att visas. Det kommer att visa med olika rekvisita beroende på humör. Här är två exempel:

<app-bas
v-if=”avsikten === ‘Glada'”
av :t-config.en=”1″
av :t-config.b=”200″
/>
<app-bas
v-if=”avsikten === ‘Nervös'”
av :t-config.en=”1″
:color=”0xff0000″
:wireframe=”true”
:rainbow=”false”
:emissive=”true”
/>

Ställa in data visualisering

Jag ville arbeta med kaleidoscope-liknande bilder för visualisering och, efter lite letande, hittade denna repa. Det fungerar på så sätt som en form vänder sig i rymden och detta kommer att bryta bilden isär och visa bitar av det som ett kalejdoskop. Nu kanske det låter awesome eftersom (yay!) arbetet är gjort, eller hur?

Tyvärr inte.

Det fanns ett antal större förändringar som behövde göras för att få detta att fungera, och att det faktiskt blev ett massivt företag, även om det slutliga visuella uttryck visas liknar den ursprungliga.

  • På grund av det faktum att vi skulle behöva riva visualisering om vi bestämde oss för att ändra på det, jag var tvungen att konvertera den befintliga koden för att använda bufferArrays, som är mer prestanda för detta ändamål.
  • Den ursprungliga koden var en stor bit, så jag bröt upp några av de funktioner i mindre metoder på en komponent för att göra det lättare att läsa och underhålla.
  • Eftersom vi vill uppdatera saker på fluga, jag var tvungen att lagra några av de punkter som data i komponenter, och så småningom som rekvisita för att det skulle få från förälder. Jag ingår också några fina defaults (glada är vad alla standardvärden ser ut).
  • Vi använder räknaren från Vuex staten att uppdatera avstånd av kamerans placering i förhållande till objektet så att vi kan se mer eller mindre av den och därmed blir det mer och mindre komplex.

För att ändra det sätt som det ser ut enligt de konfigurationer, vi kommer skapa en del rekvisita:

rekvisita: {
numAxes: {
typ: Antal,
standard: 12,
krävs: falskt
},

tConfig: {
standard() {
return {
a: 2,
b: 3,
c: 100,
d: 3
}
},
krävs: falskt
}
},

Vi kommer att använda dessa när vi skapar former:

createShapes() {
detta.bufferCamera.läge.z = i detta.shapeZoom

om (detta.torusKnot !== null) {
detta.torusKnot.material.dispose()
detta.torusKnot.geometri.dispose()
detta.bufferScene.ta detta.torusKnot)
}

var form = new TRE.TorusKnotGeometry(
detta.tConfig.en,
detta.tConfig.b,
detta.tConfig.c,
detta.tConfig.d
),
material

detta.torusKnot = new TRE.Mesh(form, material)
detta.torusKnot.material.needsUpdate = true

detta.bufferScene.lägg till(det här.torusKnot)
},

Som vi nämnde tidigare, detta är nu delas ut i sin egen metod. Vi kommer också att skapa en annan metod som sparkar igång animation, som också kommer att starta om när det uppdateringar. Animeringen använder sig av requestAnimationFrame:

animate() {
detta.storeRAF = requestAnimationFrame(det här.animera)

detta.bufferScene.rotation.x += 0.01
detta.bufferScene.rotation.y += 0.02

detta.renderaren.render(
detta.bufferScene,
detta.bufferCamera,
detta.bufferTexture
)
detta.renderaren.render(det här.scenen denna.kamera)
},

Vi ska skapa ett beräknat egendom kallas shapeZoom som kommer tillbaka zoom från butiken. Om du minns, det här kommer att uppdateras i takt med användarens röst ändrar intensiteten.

beräknad: {
shapeZoom() {
tillbaka detta.$lagra.stat.zooma
}
},

Vi kan då använda en bevakare för att se om zoom-nivå ändringar och avbryta animation, återskapa former, och starta animeringen.

titta på: {
shapeZoom() {
detta.createShapes()
cancelAnimationFrame(det här.storeRAF)
detta.animate()
}
},

I data kan vi även lagra vissa saker som vi behöver för att instansieras i three.js scen — framför allt-se till att kameran är exakt centrerad.

data() {
return {
bufferScene: TRE nya.Scen(),
bufferCamera: TRE nya.PerspectiveCamera(75, 800 / 800, 0.1, 1000),
bufferTexture: TRE nya.WebGLRenderTarget(800, 800, {
minFilter: TRE.LinearMipMapLinearFilter,
magFilter: TRE.LinearFilter,
anti-alias: sanna
}),
kamera: TRE nya.OrthographicCamera(
fönster.innerWidth / -2,
fönster.innerWidth / 2,
fönster.innerHeight / 2,
fönster.innerHeight / -2,
0.1,
1000
),

Det finns mer till detta demo, om du skulle vilja att utforska den repo eller ställa upp själv med dina egna parametrar. Init-metoden gör vad du tror det kan: den initierar hela visualisering. Jag har kommenterat en hel del av de viktiga delarna om du kikade på källkoden. Det finns också en annan metod som uppdaterar den geometri som kallas — du uessed det — updateGeometry. Du kan märka en hel del vars i det också. Det beror på att det är vanligt att återanvända variabler i denna typ av visualisering. Vi drar allt mindre genom att ringa detta.init() i den monterade() lifecycle krok.

  • Igen, här är repo-om du vill spela med kod
  • Du kan göra din egen modell genom att få en gratis Azure-konto
  • Du kommer också vill kolla in LUIS (Kognitiv Tjänster)

Det är ganska kul att se hur långt du kan få skapa saker för webben som inte nödvändigtvis behöver någon handrörelse att kontrollera. Det öppnar upp många möjligheter!