• No results found

Att utveckla en chattbot med Rasa

N/A
N/A
Protected

Academic year: 2022

Share "Att utveckla en chattbot med Rasa"

Copied!
68
0
0

Loading.... (view fulltext now)

Full text

(1)

To develop a chatbot using Rasa

William Ganrot Paul Johansson

Fakulteten för hälsa, natur-och teknikvetenskap Datavetenskap

C-uppsats 15hp

Handledare: Kerstin Andersson Examinator: Stefan Alfredsson Datum: 2020-06-01

(2)
(3)

Världen blir alltmer digitaliserad och i med det, utvecklas nya metoder för att kun- na underlätta arbetet för oss människor med automatiserade system som bland annat kontrolleras av AI (artificiell intelligens). Nya utmaningar står inför dörren för att få samhällen att anpassa sig till den nya framtiden. En av dessa metoder är chattbottar som med hjälp av AI kan automatisera en stor del av det manuella arbetet.

Denna uppsats bygger på ett projekt som vi blev tilldelade av CGI, att utveckla en chattbot som en demoprodukt. Syftet med demoprodukten är att ge CGI möjlighet att visa för kunder vad en chattbot är för något och vilka användningsområden den kan ha. Chattbotten utvecklades med hjälp av ett open source-projekt som kallas för Rasa som är ett ramverk för att utveckla chattbottar med. Resultatet är en demoprodukt i form av en chattbot som kan boka semester och möten samt hjälpa användare att få ett nytt lösenord om de har glömt sitt och svara på vanliga frågor.

i

(4)

The world becomes more and more digital and with that, new methods are being deve- loped to ease the work for us humans with automatic systems including those controlled by AI (Artificial Intelligence). New challenges are faced every day to make us more accustomed to the new future. One of the methods is chatbots and with the help of AI they can be used to automate a big chunk of the manual labour.

This dissertation is based on an assignment by CGI, to develop a chatbot as a demo. The purpose of the demo is for CGI to show to customers what a chatbot is and what use cases a chatbot can have. The development of the chatbot used an open source project called Rasa which is a framework to create chatbots with. The result is a demo in the shape of a chatbot that can book vacations and meetings as well as help users receive a new password if they forgot theirs and answer frequently asked questions (FAQ).

ii

(5)

Sammanfattning i

Abstract ii

Figurer vii

Kodexempel viii

1 Introduktion 1

1.1 Syfte och mål . . . 1

1.2 CGI . . . 2

1.3 Disposition . . . 2

2 Bakgrund 3 2.1 ELIZA . . . 3

2.2 Turingtestet . . . 4

2.3 Natural Language Processing & Understanding . . . 4

2.4 AI-assistenter . . . 6

2.4.1 Nivå 1 - påminnelser . . . 7

2.4.2 Nivå 2 - frågor och svar . . . 7

2.4.3 Nivå 3 - Contextual Assistants . . . 8

2.4.4 Nivå 4 - personligt . . . 9 iii

(6)

2.4.5 Nivå 5 - automatiskt . . . 9

2.5 Rasa . . . 9

2.5.1 Rasa NLU . . . 9

2.5.2 Rasa Core . . . 11

2.5.2.1 Config . . . 11

2.5.2.2 Domain . . . 11

2.5.2.3 Stories . . . 12

2.5.2.4 Custom Actions . . . 12

2.5.2.5 Forms . . . 12

2.5.3 Arkitektur . . . 13

2.5.4 Rasa X . . . 13

2.6 Verktyg & hjälpmedel . . . 14

2.6.1 Visual Studio Code . . . 14

2.6.2 Git och GitHub . . . 14

2.6.2.1 Integrera med Rasa X . . . 15

3 Implementation 16 3.1 Översikt . . . 16

3.2 Kom igång med Rasa - moodbot . . . 17

3.2.1 Custom actions . . . 23

3.2.1.1 Träningsexempel med forms . . . 24

3.3 Demoprodukten . . . 25

3.3.1 Förståelseområden . . . 26

3.3.1.1 Semesterbokning . . . 26

3.3.1.2 Mötesbokning . . . 29

3.3.1.3 “Help desk” . . . 34

3.3.2 Server för kalenderoperationer . . . 36

3.3.2.1 Funktioner för semesterbokning . . . 37

(7)

3.3.2.2 Funktioner för mötesbokning . . . 38

4 Resultat 40 4.1 Rasa . . . 40

4.1.1 Rasa X . . . 41

4.2 Chattbotten . . . 41

4.2.1 Semesterbokning . . . 41

4.2.2 Mötesbokning . . . 42

4.2.3 “Help desk” . . . 43

4.3 Servern . . . 44

4.4 Problem . . . 45

4.4.1 Rasa . . . 45

4.4.1.1 Rasa X . . . 45

4.4.1.2 Duckling . . . 46

4.4.2 Chattbotten . . . 46

4.4.3 Google autentisering . . . 46

5 Slutsats 48 5.1 Utvärdering av projektet . . . 48

5.2 Framtida arbete . . . 49

5.3 Slutord . . . 49

Litteraturförteckning 50

Bilagor 54

A Förkortningar 55

B Begrepp 56

(8)

C Kommandon 57

D Länkar 58

(9)

2.1 Rasas nivåer av AI-assistenter [1]. Använd med tillåtelse. . . 7

2.2 Illustration över intents. . . 10

2.3 Hur Rasa behandlar ett inkommande meddelande [2]. Använd med tillå- telse. . . 14

3.1 Visar hur installationen av rasa går till i Ubuntu. . . 17

3.2 Exempelkonversation med moodbot [3]. Använd med tillåtelse. . . 18

3.3 Alla slots fyllda samtidigt. . . 24

3.4 En slot i taget blir ifylld. . . 24

3.5 Exempel på hur Duckling omvandlar ett datum. . . 26

4.1 Exempel på en konversation där användaren försöker planera sin semester. 42 4.2 Exempel på en konversation där användaren försöker planera ett möte. . 43

4.3 Exempel på en konversation där användaren har glömt sitt lösenord. . . 43

4.4 Exempel på en konversation där användaren ställer några frågor. . . 44

vii

(10)

3.1 Domain för moodbot [3]. . . 19

3.2 NLU för moodbot [3]. . . 19

3.3 Genererad moodbot intent ranking för “Hello”. . . 21

3.4 Stories för moodbot [3]. . . 22

3.5 Custom action-exempel [4]. . . 23

3.6 Request Directions FormAction. . . 24

3.7 En utter-action med den byggda URL:en i träningsexemplet. . . 25

3.8 Slot mapping för formuläret “vacation_form”. . . 27

3.9 Metoden som avgör om användarens önskade semester är tillåten. . . . 28

3.10 Delen av storyn där is_valid_dates är true. . . 29

3.11 Delen av storyn där is_valid_dates är false. . . 29

3.12 Slot mapping för mötesboknings FormAction. . . 31

3.13 Metod som validerar inviteemail. . . 32

3.14 Metod som validerar invitemorebool. . . 33

3.15 Custom action för glömt lösenord. . . 35

3.16 Utter-action för glömt lösenord. . . 35

3.17 Utter-actions för FAQ. . . 36

3.18 Hur en Google-händelse skapas. . . 37

viii

(11)

Introduktion

Digitaliseringen av världen sker för fullt och mycket forskning kring AI sker varje dag.

Ett av de områden som använder denna forskning är utvecklandet av AI-assistenter.

En AI-assistent är en bot som hjälper till med att till exempel svara på frågor. AI- assistenterna kan vara text- eller röstbaserade, i den här uppsatsen ligger textbaserat i fokus [5]. Några av de populära AI-assistenterna är Googles Assistant, Amazons Alexa, Apples Siri och Microsofts Cortana.

1.1 Syfte och mål

Den här uppsatsen bygger på ett projekt som vi blev tilldelade av CGI, att utveckla en chattbot som en demoprodukt. Syftet med demoprodukten är att ge CGI möjlighet att visa kunder vad en chattbot är för något och vad en chattbot kan göra, till exempel boka ett möte. För att lyckas med detta valdes “Rasa” som är ett ramverk med öppen källkod som används för att utveckla chattbottar.

Vår handledare på CGI bestämde att vi skulle använda Rasa, både eftersom det är gratis och eftersom man på företaget vill få utökad kunskap om ramverket.

1

(12)

1.2 CGI

Arbetet utfördes hos företaget CGI på deras kontor i Karlstad. CGI är ett av världens största konsultföretag, de har totalt 87 000 anställda utspridda på över 400 platser runt om i världen [6].

1.3 Disposition

Kapitel 2 berättar lite historisk bakgrund om chattbottar, sedan gås Natural Language Processing, Natural Language Understanding, AI-assistenter samt Rasas ramverk i de- talj och vad för slags verktyg som använts under projektet. Kapitel 3 går igenom hur man kommer igång med Rasa samt utvecklingen av projektets chattbot. Kodexempel visas med förklaringar. Kapitel 4 berättar vad resultatet blev samt de problem som stötts på under projektets gång. Kapitel 5 innehåller slutord som sammanfattar uppsatsen.

Bilagorna A, B, C och D som finns med i uppsatsen är listor på förkortningar, begrepp, Rasa-kommandon och länkar. Begreppen har vi valt att inte översätta till svenska för att inte skapa förvirring om man är intresserad av att lära sig mer om Rasa.

(13)

Bakgrund

Detta kapitel går igenom lite historisk bakgrund bakom chattbottar såsom ELIZA och Turingtestet för att ge läsaren förståelse för att utvecklingen av chattbottar har pågått länge. Kapitlet berättar även vad Natural Language Processing, Natural Language Un- derstanding och AI-assistenter är för något, samt hur ramverket Rasa är uppbyggt i detalj. Kapitlet avslutas med verktyg och hjälpmedel.

2.1 ELIZA

ELIZA skapades av Joseph Weizenbaum på 1960-talet och är en av de första chatt- bottarna. ELIZA är konstruerad med två “pusselbitar”, där den första pusselbiten är en språkanalysator och den andra ett skript. Skriptet innehåller regler för hur ELIZA ska föra en konversation. Det mest kända skriptet är “DOCTOR”-skriptet som härmar en psykoterapeut vars roll är att upprepa vad patienterna har nyss sagt. Ett kortfattat exempel på en sådan konversation finns i [7, s.3] som citeras nedanför:

“Men are all alike.

IN WHAT WAY

3

(14)

They’re always bugging us about something or other.

CAN YOU THINK OF A SPECIFIC EXAMPLE Well, my boyfriend made me come here.

YOUR BOYFRIEND MADE YOU COME HERE He says I’m depressed much of the time.

I AM SORRY TO HEAR YOU ARE DEPRESSED”. [7, s.3].

Weizenbaum blev väldigt förvånad när personer som chattade en liten stund med ELIZA började visa känslor. Ett fall var Weizenbaums sekreterare som visste om att ELIZA bara var ett datorprogram, eftersom hon hade sett Weizenbaum jobba med det i flera månader, ville bli lämnad ifred [7, s.2-7]. Det sägs att ELIZA klarade “Turingtestet” [8, s.112], läs mer om testet i nästa avsnitt 2.2.

2.2 Turingtestet

Turingtestet bygger på en fråga som Alan Turing på 1950-talet ställde i [9]: “Can machi- nes think?”. [9, s.433]. I testet finns tre deltagare: en man, en kvinna samt ytterligare en person som befinner sig i ett annat rum. Målet med testet är för den tredje deltagaren bestämma vem som är kvinnan. Kommunikationen mellan de två rummen sker via skrift eftersom rösten kan hjälpa den tredje deltagaren att lista ut vem som är vem. Det går att ändra testet så att en maskin ersätter första eller andra deltagaren. Om den tredje deltagaren inte kan skilja på människan och maskinen har maskinen klarat testet [9].

2.3 Natural Language Processing & Understanding

Natural Language Processing (NLP) är en delmängd av AI och handlar om att omvandla stora mängder språkdata i mindre delar för att göra det mer strukturerat och förståeligt

(15)

[10]. Microsoft Word till exempel använder sig av NLP för sina grammatikkontroller [11].

Natural Language Understanding (NLU) är en delmängd av NLP, men NLP använder inte alltid NLU. NLU gör att maskiner kan tolka och förstå mänskligt språk genom att använda AI. Det gör att maskiner förstår att fraserna “Hur är vädret?” och

“Hur ser vädret ut?” betyder samma sak. Det finns flera sätt att fråga hur vädret är och med hjälp av NLU kan maskinen känna igen att det är samma fråga som är uttryckt på flera sätt [10].

Skillnaden mellan NLP och NLU är att NLU fokuserar på semantiken medan NLP fokuserar på strukturen. När man skriver ett meddelande analyserar NLP:n texten och kontrollerar att språket är rätt utan att förstå vad texten handlar om, medan NLU:n förstår betydelsen i texten även om texten kan innehålla felaktiga ord och stavfel [10].

Idag bygger alla moderna NLP-implementationer på AI och maskininlärning (ML), där man applicerar en ML-algoritm på testdata och algoritmen försöker hitta mönster i språket och därifrån sätta regler på hur språket ska vara strukturerat [11]. NLP har dock inte alltid baserats på AI, det var först i slutet av 1980-talet som mycket av forskningen kring AI utfördes. Innan det var NLP oftast regelbaserat [12]. Det innebär att alla grammatiska regler var skrivna för hand [12, 13]. Ett exempel i det engelska språket är att om ett substantiv slutar med ett “s” syftar det oftast på substantivet i plural [11].

Både regelbaserade och ML-baserade system har sina för- och nackdelar. Det största och mest uppenbara problemet med regelbaserad NLP är att utvecklingen av sådana system kräver hjälp från språkexperter, eftersom nästan ingen utvecklare har kunskap om alla grammatiska regler [14]. Resultatet av en regelbaserad NLP ger ett system med hög precision [12]. Vid utveckling av en ML-baserad NLP behövs inte denna expertis eftersom det bygger på ML. Istället behövs tillräckligt mycket data som systemet kan träna på och ta fram egna regler från. Överlag går det snabbare att utveckla

(16)

en ML-baserad NLP om en bra datamängd finns tillgänglig [14]. En ML-baserad NLP är även mer flexibel ur den synvinkeln att algoritmen kan lära sig på ett sådant sätt att den även kan förstå och hantera felstavningar, vilket inte är lika lätt i en regelbaserad NLP [12].

2.4 AI-assistenter

Det finns olika typer av assistenter som använder sig av AI. Avsnittet berättar vilka typerna är utifrån Rasas perspektiv samt nämner några andra välkända AI-assistenter.

Figur 2.1 illustrerar de olika nivåer av AI-assistenter som Rasa har introducerat.

Idag går det att utveckla AI-assistenter som förstår sammanhang men ännu inte riktigt uppnått nivå 3. Det beräknas att nivå 4 nås inom tre till fem år och nivå 5 inom tio år [1]. Dock är nivå 4 och 5 endast spekulationer. Längden på staplarna representerar intelligens hos assistenterna, det vill säga nivå 3 är smartare än nivå 1 och 2 men mindre smart än nivå 4 och 5. Dessa nivåer representerar hur Rasa anser att AI-assistenter kommer att utvecklas över tiden. Det finns även andra som utvecklar AI-assistenter.

Några av dessa AI-assistenter är Googles Assistant, Amazons Alexa, Apples Siri och Microsofts Cortana.

(17)

Figur 2.1: Rasas nivåer av AI-assistenter [1]. Använd med tillåtelse.

2.4.1 Nivå 1 - påminnelser

Nivå 1 är den mest grundläggande, assistenten meddelar bara användaren utan att föra en konversation. Push-notiser på mobiltelefoner fungerar på liknande sätt genom att automatiskt skicka information eller en påminnelse [1].

2.4.2 Nivå 2 - frågor och svar

Nivå 2 ger möjlighet att föra enkla konversationer mellan assistenten och användare genom att ställa frågor och få svar direkt. Det är mer effektivt än att leta på en hemsida.

(18)

Assistenter på den här nivån saknar förståelse för betydelsen bakom ett meddelande vilket var ett stort problem när man ville utveckla chattbottar som skulle följa upp användarens meddelanden vilket inte var möjligt då det inte gick att spara undan in- formation som har sagts tidigare. Detta medförde att konversationerna blev längre för att användaren behövde upprepa sig flera gånger [1].

2.4.3 Nivå 3 - Contextual Assistants

Nivå 3 tar steget vidare och löser problemen som fanns i nivå 2 genom att förstå sam- manhang vilket ger mer frihet till användaren att skriva vad den vill där chattbotten an- passar sig efter de inkommande meddelanden. Chattbotten kommer även ihåg vad som har sagts tidigare i konversationen vilket medför att användaren inte behöver upprepa samma information flera gånger [1].

En Contextual Assistant är en typ av chattbot som använder sig utav NLP och NLU för att driva en mänsklig konversation mellan en dator och en användare. Sådana system är speciellt vanliga inom kundtjänst och service. Området har utvecklats snabbt och bli allt vanligare. Nu för tiden väljer många att hellre kommunicera med en bot än att fylla i ett klassiskt formulär. Det går till exempel att ofta att utföra uppgifter som att boka tandläkartid via en chattbot. Det som är viktigt hos en Contextual Assistant är att den ska kunna hantera alla typer av användare på ett smidigt sätt, det vill säga att kunna hålla en konversation från början till slut men kan behöva att en människa tar över direkt eller indirekt (ge telefonnummer till kundtjänst). Andra viktiga mål är att assistenten ska kunna anpassa sig om användaren byter ämne och komma ihåg vad som har sagts tidigare i konversationen men även kunna hantera tvetydighet genom att fråga användaren innan assistenten går vidare. “Contextual” syftar på sammanhanget i konversationen och kan assistenten förstå sammanhang behöver konversationerna inte bli så långa [15].

(19)

2.4.4 Nivå 4 - personligt

Nästa steg i utvecklingen är det kommande nivå 4 vilket kommer ge chattbottar möjlig- het att känna av när det är dags att ta kontakt med användaren och uppdatera efter hens behov. Chattbotten kommer ihåg användarens inställningar och kan på så vis ge förslag till exempel om användaren vill byta abonnemang [1].

2.4.5 Nivå 5 - automatiskt

Slutmålet är med nivå 5 att det finns ett nätverk med chattbottar som kan automatisera en stor del hos ett företag, med till exempel marknadsföring, försäljning och finans. AI:n kommer att utan hjälp från människan sköta beslut, underskrifter m.m. [1].

2.5 Rasa

Rasa är ett ramverk med öppen källkod som är till för att underlätta utvecklandet av chattbottar. Rasa har introducerat fem nivåer av AI-assistenter som beskriver hur Rasa ser på utvecklingen över assistenter, mer om detta i förgående avsnitt 2.4. Ramverket består av tre huvudsakliga komponenter som arbetar tillsammans: Rasa NLU, Rasa Core samt Rasa X [16]. Nu har dock källkoden för Rasa NLU och Rasa Core slagits ihop till en enhet [17].

2.5.1 Rasa NLU

Rasa NLU är komponenten i ramverket som ansvarar för att tolka en användares inmat- ning. Den gör detta genom att från användarens inmatning kategorisera vilket intent det är och extrahera vilka entities som finns. Ett intent kan ses som en kategori, där alla meddelanden med samma innebörd samlas, medan entities är nyckelord i meddelandet [18]. Figur 2.2 visar en illustration vad intents är. “Intent 1” samlar hälsningar medan

(20)

“Intent 2” samlar meddelanden som har innebörden när man tar farväl.

En extraherad entity, som är en typ av ett nyckelord, lagras i en så kallad slot, så att chattbotten kan komma ihåg den senare i konversationen. En slot i Rasa kan ses som en minnesvariabel som håller nyckeldata under konversationen. till exempel i meningen

“Jag vill köpa en Capricciosa” ska NLU:n kunna avgöra att intentet är att användaren vill köpa en pizza och att Capricciosa är en entity [16].

Figur 2.2: Illustration över intents.

För att extrahera entities på ett så effektivt sätt som möjligt kan man konfigurera en pipeline. Detta görs genom att lista alla de komponenter som ska behandla meddelan- det. Alla dessa komponenter är till för olika saker och har olika förutsättningar. Alltså används ofta olika komponenter i pipelinen beroende på vilket språk botten ska förstå och vilka typer av entities den ska extrahera. Ett exempel på en sådan komponent är

“WhitespaceTokenizer” som delar upp varje ord som tokens [19].

För att träna NLU:n måste man förse den med träningsdata. Till en början skrivs träningsdata oftast manuellt men bör så snart som möjligt genereras av flera testanvän- dare så att träningsdatan inte blir enformig, exempelvis genom Rasa X vilket beskrivs senare i 2.5.4. Träningsdata anges i en fil som kallas nlu.md. Syftet med träningsdatan är att ge större sannolikhet för NLU:n att matcha användarens inmatning med rätt intent.

(21)

Mer om hur detta fungerar i avsnitt 3.2. Ett exempel på hur träningsdata kan se ut ses i kodexempel 3.2.

2.5.2 Rasa Core

Rasa Core är den komponent som sköter flödet av dialogen. Det är här det avgörs vad som ska svaras eller utföras beroende på vad användaren skriver och vad som har sagts tidigare i konversationen. Rasa Core använder en tränad modell för att göra besluten under konversationens gång. För att träna en sådan modell använder man kommandot

“rasa train” men man behöver förse algoritmen med lämplig data. För att generera denna modell använder Rasa fyra filer: config.yml, domain.yml, stories.md samt nlu.md, [20].

Dessa fyra filer tillsammans bygger en modell som Rasa kan använda för att starta chattbotten med.

2.5.2.1 Config

Config.yml bestämmer språket, vilka komponenter man vill ha i sin “pipeline” som avgör hur entities extraheras samt “policies” som bestämmer vilka actions botten ska ta i varje steg i konversationen [21]. Ett action kan exempelvis vara ett enkelt meddelande som chattbotten skickar till användaren eller skräddarsytt som beskrivs i 2.5.2.4.

2.5.2.2 Domain

Domain.yml specificerar intents, entities, slots, actions samt templates. Dessa element bestämmer hur chattbotten kommer att fungera [22]. För att använda dessa typer av element måste de specificeras i domain, annars vet inte botten att de existerar. Intents, entities och slots beskrivs i avsnitt 2.5.1, actions beskrivs i 2.5.2.4. Templates är en sek- tion i domain-filen som innehåller alla svar som chattbotten kan skriva till användaren.

(22)

2.5.2.3 Stories

Stories.md specificerar hur konversationerna mellan chattbotten och användaren kan se ut. Varje story definierar en väg konversationen kan ta [23]. I en story beskrivs användarens möjliga intents samt vilka actions botten ska svara dem med. En dialog kan dock gå på många olika sätt, det är inte alltid användaren svarar på bottens fråga;

en användare kan byta spår mitt under konversationen. På grund av detta blir denna fil ofta väldig lång och svår att hålla strukturerad [24].

2.5.2.4 Custom Actions

Actions.py innehållar alla skräddarsydda actions. Ett custom action används för att göra något mer än att endast svara på användaren. Det kan till exempel vara ett API-anrop eller en matematisk uträkning. För att kunna utföra alla actions i filen behöver en action- server köras. När Rasa Core gör en förfrågan till action-servern för att exekvera ett specifikt action ger den tillåtelse att göra ändringar i trackern. Trackern håller koll på tillståndet i konversationen. På så sätt kan man från ett action till exempel läsa av samt skriva till slots. Man kan alltså till exempel fylla en slot med ett resultat av ett API-anrop [20].

2.5.2.5 Forms

Forms är ett enklare sätt att utföra “Slot Filling” som innebär att man skapar ett action som körs tills alla krävda slots är fyllda. Uppsatsen benämner forms som formulär. I varje formulär definieras vilka slots som ska fyllas för att formuläret ska klassas som slutfört. Ordningen eller hur många slots som ska fyllas spelar ingen roll. Formulär används när chattbotten behöver samla flera delar av information på rad. Ett exempel är om man har en restaurang-bot så kan botten fråga var du vill äta, vilken typ av mat och hur stort sällskap där sedan informationen sparas i separata slots [25].

(23)

2.5.3 Arkitektur

Figur 2.3 visar den övergripande arkitekturen av Rasa, hela vägen från att användaren skriver ett meddelande tills dess att assistenten ger någon typ av respons. När assistenten tar emot ett meddelande från en användare skickas meddelandet direkt till en program- tolk som analyserar texten och konverterar den till JSON-formaterad data som innehåller textens intents, entities samt ett värde som representerar hur säker assistenten är på att den har förstått intenten och hittat korrekta entities. Rasa NLU hanterar assistentens förståelse. Tracker håller koll på vilket tillstånd konversationen befinner sig i. Policy tar emot konversationens läge av trackern. Utifrån detta läge avgör Policy vilket action som ska utföras. Det action som valdes av Policy loggas till Tracker. Action-modulen exekverar sen sin kod som kan vara till exempel ett API-anrop. Sedan returneras en respons till användaren.

2.5.4 Rasa X

Rasa X är ett verktyg som kan ses som ett lager över Rasa-ramverket. Syftet med Rasa X är att underlätta utvecklingen av en chattbot. När en Rasa X-server startas presenteras alla filer och projektet med ett webbgränssnitt. Utvecklaren kan även kommunicera med botten via webbgränssnittet och ifall botten skulle svara något konstigt på en fråga kan utvecklaren rätta detta direkt i konversationen.

En stor fördel med Rasa X är möjligheten att dela botten med testanvändare. Du kan snabbt sätta upp en Rasa X-användare och dela din bot till vem du vill. Rasa X lagrar alla konversationer och som utvecklare kan man se vart botten begick misstag och enkelt fixa dem. Rasa rekommenderar att man så snabbt som möjligt ska få ut botten till riktiga användare eftersom det är mer effektivt att träna botten från data som är generarad från riktiga användare istället för att träna botten på data som en utvecklare har skrivit då den ofta blir enformig.

(24)

Rasa X erbjuder även en experimentell funktion för integrerad versionshantering med GitHub. I avsnitt 2.6.2.1 kan man läsa hur Rasa X kan integreras med GitHub.

Figur 2.3: Hur Rasa behandlar ett inkommande meddelande [2]. Använd med tillåtelse.

2.6 Verktyg & hjälpmedel

I det här kapitel tas de verktyg och hjälpmedel som har använts under arbetets gång upp.

2.6.1 Visual Studio Code

Visual Studio Code är en källkodsredigerare som utvecklats av Microsoft. En käll- kodsredigerare är en typ av textredigerare som är designad för att redigera källkod.

Visual Studio Code möjliggör det att installera obegränsat antal tredje-parts-tillägg för att anpassa verktyget precis som du vill. Visual Studio Code har även stöd för Git. Det betyder att man kan sköta all versionshantering direkt i redigeraren [26].

2.6.2 Git och GitHub

Git är ett open source-projekt som utvecklare världen över använder för versionhante- ring. När man gör en ändring så sparas historiken. På så sätt kan man se hur projektet såg

(25)

ut i ett tidigare stadie. Om något har gått snett kan man även gå tillbaks till ett tidigare skede i historiken.

Projektet använder sig av Git för att enkelt kunna dela upp arbetet och GitHub till att ha en plats att ladda upp arbetet på. GitHub är en populär plattform som använder Git.

2.6.2.1 Integrera med Rasa X

Det går att integrera Rasa X med GitHub och få versionshantering så att ändringar som görs i Rasa X kan pushas direkt till GitHub. Detta underlättar till exempel när ett team jobbar mot samma bot. För att koppla Rasa X till GitHub krävs så kallade “deploy keys”

som är ett par av SSH-nycklar [27]. SSH står för Secure Shell och är ett asymmetriskt kryptografiskt protokoll och därav använder sig av två nycklar, en publik och en privat [28]. För att upprätta kopplingen ges den publika nyckeln till GitHub, vilket innebär att vem som helst med den privata nyckeln kan koppla sig till repositoriet.

(26)

Implementation

Det här kapitlet börjar med att gå igenom hur man installerar samt använder Rasa.

För att ge en tydligare förståelse över hur Rasa fungerar i praktiken kommer kapitlet sedan gå igenom en chattbot som kallas “moodbot” på kodnivå. Moodbot är en chattbot som tillhandahålls av Rasa som ofta används för att bekanta sig med Rasa-ramverket.

Moodbot gås igenom för att bekanta läsaren med ramverket innan det gås in på hur demoprodukten implementerades. Detta görs eftersom ramverket kan vara lite överväl- digande. Slutligen beskrivs det praktiska arbetet hur demoprodukten implementerades, hur den hanterar de olika fallen som kan uppstå i en konversation.

3.1 Översikt

Rasas dokumentation, bilaga D, beskriver på djupet hur man installerar och kommer igång med Rasa. Figur 3.1 visar en översiktsbild på hur Rasa installeras i Ubuntu.

16

(27)

Figur 3.1: Visar hur installationen av rasa går till i Ubuntu.

3.2 Kom igång med Rasa - moodbot

I det här avsnittet kommer det framgå vad Rasas egna “moodbot” är för något samt hur den fungerar på kodnivå.

För att komma igång med Rasa erbjuder Rasa en grundläggande chattbot som kallas för “moodbot”. Med hjälp av kommandot rasa init –no-prompt skapas ett Rasa- projekt i den nuvarande mappen med moodbot som exempel. Moodbot är ett bra exem- pel för att få en grundläggande överblick hur alla komponenter hänger samman.

Moodbot försöker uppmuntra användaren genom att hålla en glad ton i sina svar, se figur 3.2 för ett exempel på hur en konversation med moodbot kan se ut.

(28)

Figur 3.2: Exempelkonversation med moodbot [3]. Använd med tillåtelse.

Den första komponenten man bör undersöka är domain.yml. Som det togs upp i kapitel 2.5.2.2 definieras miljön botten befinner sig i här. Kodexempel 3.1 visar hur en del av domain-filen ser ut för moodbot. Här går det att se vilka intents som chattbotten är programmerad att förstå. Botten kan då svara på dessa intents genom sina actions.

Stories.md bestämmer vilket action som ska köras mot ett visst intent. I kodexemplet 3.4 är intents markerade med * medan actions med -. Till exempel om användaren börjar konversationen med intentet greet, svarar botten med action utter_greet. Under templates i domain.yml framgår det vad som sker när ett utter-action körs, alltså ett action som endast skriver till användaren. I det är fallet kan man se att utter_greet gör att botten svarar med ett meddelande: “Hey! How are you?”. I mera komplicerade bottar går det även exekvera kod genom custom actions, som är körbar kod skrivet i Python.

För att custom actions ska fungera krävs det en action-server. Det finns en action-server inkluderat med Rasa som kan startas genom att kör kommandot “rasa run actions”. I avsnitt 3.2.1 går det mer in på detalj hur man skriver ett Custom Action.

(29)

1 i n t e n t s :

2 - g r e e t

3 - m o o d _ g r e a t

4 - m o o d _ u n h a p p y

5 a c t i o n s :

6 - u t t e r _ g r e e t

7 - u t t e r _ c h e e r _ u p

8 - u t t e r _ h a p p y

9 t e m p l a t e s :

10 u t t e r _ g r e e t :

11 - t e x t : " Hey ! How are you ? "

12 u t t e r _ c h e e r _ u p :

13 - t e x t : " H e r e is s o m e t h i n g to c h e e r you up : "

14 i m a g e : " h t t p s :// i . i m g u r . com / n G F 1 K 8 f . jpg "

15 u t t e r _ h a p p y :

16 - t e x t : " Great , c a r r y on ! "

Kodexempel 3.1: Domain för moodbot [3].

Kodexempel 3.2 visar en del av hur nlu.md för moodbot ser ut. Filen har en tendens att bli lång och därför är inte hela med i uppstatsen. Filen innehåller träningsdata för NLU:n som beskriver varje intent och hur ett meddelelande kan se ut för att klassas som ett visst intent. Det är viktigt att ha flera exempel för varje intent för att botten ska kunna tolka användaren korrekt. Ifall för få exemplen för ett intent finns är det större chans att botten tolkar användarens inmatning till fel intent.

1 # # i n t e n t : g r e e t

2 - hey

3 - h e l l o

4 - hi

5 - g o o d m o r n i n g

6 - g o o d e v e n i n g

7 - hey t h e r e

8 # # i n t e n t : m o o d _ g r e a t

(30)

9 - p e r f e c t

10 - v e r y g o o d

11 - g r e a t

12 - a m a z i n g

13 - w o n d e r f u l

14 - I am f e e l i n g v e r y g o o d

15 - I am g r e a t

16 - I am g o o d

17 # # i n t e n t : m o o d _ u n h a p p y

18 - sad

19 - v e r y sad

20 - u n h a p p y

21 - bad

22 - v e r y bad

23 - a w f u l

24 - t e r r i b l e

25 - not v e r y g o o d

26 - e x t r e m e l y sad

27 - so sad

Kodexempel 3.2: NLU för moodbot [3].

För att bestämma vilket intent ett inkommande meddelande från användaren ska matchas mot rangordnas intenten efter sannolikhet. NLU:n väljer då ut det intent med störst sannolikhet att stämma överens med användaren inmatning. Det går att bestämma ett gränsvärde för hur säker NLU:n måste vara för att kunna välja ut ett intent. Det görs i config.yml genom FallbackPolicy som innehåller “nlu_threshold”

där värdet är mellan 0.0 och 1.0. Om sannolikheten är för liten för att passera gräns- värdet anropas ett fallback-action som är definierad i FallbackPolicy. Exempelvis “ac- tion_default_fallback” som informerar användaren att botten inte förstod och att använ- daren måste omformulera sig.

Kodexempel 3.3 visar hur det ser ut när NLU:n rangordnar alla intents efter san-

(31)

nolikhet när användaren skriver “Hello” till moodbot. Här syns det att intentet “greet”

har en sannolikhet på 99,2% medan mood_unhappy har 0,12% och mood_great 0,03%

vilket betyder att NLU:n väljer ut greet eftersom det har störst sannolikhet.

1 {

2 " i n t e n t ": {

3 " na m e ": " g r e e t ",

4 " c o n f i d e n c e ": 0 . 9 9 2 4 3 0 5 0 8 1 3 6 7 4 9 3

5 } ,

6 " e n t i t i e s ": [] ,

7 " i n t e n t _ r a n k i n g ": [

8 {

9 " na m e ": " g r e e t ",

10 " c o n f i d e n c e ": 0 . 9 9 2 4 3 0 5 0 8 1 3 6 7 4 9 3

11 } ,

12 {

13 " na m e ": " m o o d _ u n h a p p y ",

14 " c o n f i d e n c e ": 0 . 0 0 1 2 4 3 1 2 5 1 8 1 6 4 5 1 5 5

15 } ,

16 {

17 " na m e ": " m o o d _ g r e a t ",

18 " c o n f i d e n c e ": 0 . 0 0 0 3 2 5 9 2 7 4 8 1 7 5 3 7 5 1 6 4

19 }

20 ] ,

21 " te x t ": " H e l l o "

22 }

Kodexempel 3.3: Genererad moodbot intent ranking för “Hello”.

En konversation kan ta många riktningar. I filen stories.md måste alla dessa riktningar anges och det görs med hjälp av intents och actions. På grund av att en konversation kan ta många vägar blir stories-filen ofta stor vilket kan leda till att den blir svår att hitta i.

(32)

I kodexempel 3.4 visas några stories för moodbot. När användaren skriver “Hel- lo” som ger intentet greet påbörjas flera vägar samtidigt: happy path, sad path 1 samt sad path 2. Moodbot svarar då med utter_greet som är meddelandet “Hey! How are you?” vilket man kan se i kodexempel 3.1 på rad 18. Om användaren sedan skriver ett meddelande som klassifieras till intentet mood_great riktas vägen in på happy path eftersom sad path 1 och 2 istället fortsätter om intentet var mood_unhappy.

1 # # h a p p y pa t h

2 * g r e e t

3 - u t t e r _ g r e e t

4 * m o o d _ g r e a t

5 - u t t e r _ h a p p y

6 # # sad pa t h 1

7 * g r e e t

8 - u t t e r _ g r e e t

9 * m o o d _ u n h a p p y

10 - u t t e r _ c h e e r _ u p

11 - u t t e r _ d i d _ t h a t _ h e l p

12 * a f f i r m

13 - u t t e r _ h a p p y

14 # # sad pa t h 2

15 * g r e e t

16 - u t t e r _ g r e e t

17 * m o o d _ u n h a p p y

18 - u t t e r _ c h e e r _ u p

19 - u t t e r _ d i d _ t h a t _ h e l p

20 * d e n y

21 - u t t e r _ g o o d b y e

Kodexempel 3.4: Stories för moodbot [3].

(33)

3.2.1 Custom actions

Moodbot använder sig inte av custom actions, men det är fortfarande en väsentlig del av Rasa. Därför tas området upp innan uppsatsen går in på implementationen av demopro- dukten.

Om man vill att botten ska kunna exekvera kod behöver man lägga det i ac- tions.py. Det kan till exempel vara API-anrop för att hämta någon typ av data. Kodex- empel 3.5 visar ett “Hello World!”-exempel. Exemplet visar att varje action definieras som en egen klass; namnet på klassen spelar ingen roll. För att custom actions ska fungera krävs det att action-servern är igång som tidigare nämnts i 3.2. Precis som med vanliga actions behöver man i domain.yml lägga till sin custom action under actions och namnet måste matcha det som returneras i klassens name-metod i actions.py. I hello world-exemplet skulle det vara “action_hello_world”. Sedan kan man använda det i stories.md.

Koden som ska exekveras körs i metoden “run”. I hello world-exemplet är det bara ett meddelande: “Hello World!”.

1 c l a s s A c t i o n H e l l o W o r l d ( A c t i o n ) :

2 def n a m e ( s e l f ) - > T e x t :

3 r e t u r n " a c t i o n _ h e l l o _ w o r l d "

4 def run ( self , d i s p a t c h e r : C o l l e c t i n g D i s p a t c h e r ,

5 t r a c k e r : Tracker ,

6 d o m a i n : D i c t [ Text , Any ]) - > L i s t [ D i c t [ Text , Any ]]:

7 d i s p a t c h e r . u t t e r _ m e s s a g e ( t e x t =" H e l l o W o r l d ! ")

8 r e t u r n []

Kodexempel 3.5: Custom action-exempel [4].

(34)

3.2.1.1 Träningsexempel med forms

Innan projektet drogs igång på riktigt gjordes ett testfall med vägbeskrivningar som an- vände sig av Google Maps. I exemplet tränades “Forms” som beskrevs tidigare i avsnitt 2.5.2.5. I kodexempel 3.6 visas projektets träningsexempel där Forms utnyttjades. Det finns tre slots som måste fyllas: to_location, from_location och travel_mode. Eftersom det är en Form kommer den att köras tills alla tre slots är fyllda. Det går att fylla flera slots samtidigt, i figur 3.3 fylldes alla slots direkt medan i figur 3.4 fylldes de en i taget.

Figur 3.3: Alla slots fyllda samtidigt.

Figur 3.4: En slot i taget blir ifylld.

1 c l a s s A c t i o n R e q u e s t D i r e c t i o n s ( F o r m A c t i o n ) :

2 """ E x a m p l e of a c u s t o m f o r m a c t i o n """

3

4 def n a m e ( s e l f ) - > T e x t :

5 r e t u r n " d i r e c t i o n s _ f o r m "

6

7 @ s t a t i c m e t h o d

8 def r e q u i r e d _ s l o t s ( t r a c k e r : T r a c k e r ) - > L i s t [ T e x t ]:

9 """ A l i s t of r e q u i r e d s l o t s t h a t the fo r m has to f i l l """

10 r e t u r n [" t o _ l o c a t i o n ", " f r o m _ l o c a t i o n ", " t r a v e l _ m o d e "]

(35)

11

12 def s u b m i t ( self , d i s p a t c h e r : C o l l e c t i n g D i s p a t c h e r , t r a c k e r : Tracker , d o m a i n : D i c t [ Text , Any ] ,) - > L i s t [ D i c t ]:

13 d i s p a t c h e r . u t t e r _ m e s s a g e ( t e m p l a t e =" u t t e r _ s u b m i t ")

14 r e t u r n []

Kodexempel 3.6: Request Directions FormAction.

Det enklaste sättet att presentera svaret för användaren var att bygga en URL till Google Maps som sedan skickas till användaren. Detta gjordes med ett enkelt utter- action. Ett utter-action är ett action som endast kan svara med ett meddelande, till skillnad från custom actions som kan utföra en mer komplicerad uppgift. I länken placerades alla slots på rätt plats. Slots kan användas som variabelnamn, det betyder att man kan skriva slot-namnet mellan två måsvingar: {namn} så byts det ut med värdet istället. Se kodexempel 3.7 hur det ser ut.

1 u t t e r _ g i v e _ d i r e c t i o n s :

2 - t e x t : " h t t p s :// www . g o o g l e . com / m a p s / dir /? api =1& o r i g i n ={

f r o m _ l o c a t i o n }& d e s t i n a t i o n ={ t o _ l o c a t i o n }& t r a v e l m o d e ={

t r a v e l _ m o d e } "

Kodexempel 3.7: En utter-action med den byggda URL:en i träningsexemplet.

3.3 Demoprodukten

I det här avsnittet kommer de framgå vad den praktiska delen av projektet gick ut på, samt hur den implementerades. Delavsnitt 3.3.1 kommer redovisa vilka områden botten är programmerad att förstå samt hur den hanterar uppgifterna den kan bli ombedd att utföra. Vissa av dessa uppgifter kommer kräva tillgång till Google Kalender-API:t. Där- för kommer det också framgå hur en webbserver implementerades för att autentisiera en användare och använda API:t.

(36)

3.3.1 Förståelseområden

I det här avsnittet beskrivs vad botten är programmerad att förstå samt hur användarens frågor hanteras. Det kommer också framgå på kodnivå hur botten kan använda sig utav Custom Actions för att utföra mer komplicerade uppgifter.

3.3.1.1 Semesterbokning

Semesterbokning är ett av de exemplen som botten ska kunna utföra. Botten ska alltså kunna underlätta för användaren att boka sin semester. För att samla in information som krävs för semesterbokningen används forms som togs upp i avsnitt 2.5.2.5. Informatio- nen som krävs är de två datumen som användaren vill ha semester mellan. Problemet med datum är att det kan se ut och formateras på många olika sätt. En användaren kan till exempel skriva “03/04/2020” eller “den tredje april”. Oavsett hur användaren väljer att uttrycka sitt datum måste det standardiseras. Det inmatade datumet behöver alltså omvandlas till ett standardformat. Det är precis det här Duckling är till för. Duckling är ett bibliotek som parsar text till strukturerad data. I figur 3.5 visas ett exempel på hur Duckling fungerar.

Figur 3.5: Exempel på hur Duckling omvandlar ett datum.

Rasa erbjuder “DucklingHTTPExtractor” som är en entity extractor. Duckling- HTTPExtractor läggs till i bottens pipeline. Detta innebär så fort användaren skriver in ett meddelande som innehållet ett datum omformateras datumet till det standar- diserade formatet, oavsett ifall botten förväntar sig ett datum eller inte. När Duck- lingHTTPExtractor har lyckats extrahera ett datum läggs datumet automatiskt i ett slot som kallas “time”. Eftersom formuläret tar emot fler än ett datum måste det nuvarande datumet som finns i time flyttas till ett annat slot så att time kan skrivas över med ett nytt

(37)

datum. För att kunna skriva över time behöver man lägga till en metod som kallas för

“slot_mappings”. Slot_mappings är en metod som kan definieras där man kan specifiera vilka värden slots ska fyllas med. Om slot_mappings inte definieras fylls slots med de entities som har samma namn.

Kodexempel 3.8 visar hur slot mapping ser ut för semesterbokningsformuläret.

I detta fall är det ganska enkelt då allt den gör är att kopiera innehållet i “time” till antingen “minDate” eller “maxDate” beroende på vad som efterfrågas.

1 def s l o t _ m a p p i n g s ( s e l f ) - > D i c t [ Text , U n i o n [ Dict , L i s t [ D i c t ] ] ] :

2 r e t u r n {

3 " m i n D a t e ": [ s e l f . f r o m _ e n t i t y ( e n t i t y =" ti m e ") ] ,

4 " m a x D a t e ": [ s e l f . f r o m _ e n t i t y ( e n t i t y =" ti m e ") ]

5 }

Kodexempel 3.8: Slot mapping för formuläret “vacation_form”.

När båda datumen är extraherade kontrolleras att inget av de mellanliggande datumen är ett otillåtet datum. Eftersom formuläret enbart sparade användarens önska- de datum i minDate och maxDate behöver kontrollen ske i en annan custom action:

“check_if_valid_dates”. Eftersom botten som utvecklas endast är en demoprodukt lig- ger de otillåtna datumen i ett Python-dictionary, syftet är att visa för en kund att samma princip skulle kunna implementeras med en databas. Om datumen visar sig vara tillåtna, tillfrågas användaren om hen vill lägga till semestern i sin Google Kalender.

För att avgöra om användarens önskade semester ligger emellan otillåtna datum eller inte används action “check_if_valid_dates”. check_if_valid_dates hämtar använ- darens datum som sparades i minDate och maxDate och sedan parsa dem till datatypen dateTime. Därefter skapas en lista (“not_allowed_dates”) av datum som ska representera de otillåtna datumen. Sedan läggs varje datum mellan “parsedMinDate” till “parsed- MaxDate” i en ny lista: “between_dates”. På rad 18 i kodexempel 3.9 jämförs båda listorna för att se om de inte innehåller något gemensamt datum. Sloten “is_valid_dates”

(38)

sätts till true eller false beroende på om det fanns ett gemensamt datum mellan listorna eller inte.

1 def run ( self , d i s p a t c h e r : C o l l e c t i n g D i s p a t c h e r , t r a c k e r : Tracker , d o m a i n : D i c t [ Text , Any ]) - > L i s t [ D i c t [ Text , Any ]]:

2

3 m i n D a t e = t r a c k e r . g e t _ s l o t (" m i n D a t e ")

4 m a x D a t e = t r a c k e r . g e t _ s l o t (" m a x D a t e ")

5

6 p a r s e d M i n D a t e = p a r s e ( m i n D a t e )

7 p a r s e d M a x D a t e = p a r s e ( m a x D a t e )

8

9 v a i l d _ d a t e _ r a n g e = F a l s e

10 n o t _ a l l o w e d _ d a t e s = [ d a t e t i m e (2020 , 2 , 12 , 0 , 0 , t z i n f o = t i m e z o n e ( t i m e d e l t a ( d a y s =0 , s e c o n d s = 3 6 0 0 ) ) ) ,

11 d a t e t i m e (2020 , 7 , 23 , 0 , 0 , t z i n f o =

t i m e z o n e ( t i m e d e l t a ( d a y s =0 , s e c o n d s = 3 6 0 0 ) ) ) ,

12 d a t e t i m e (2020 , 3 , 9 , 0 , 0 , t z i n f o =

t i m e z o n e ( t i m e d e l t a ( d a y s =0 , s e c o n d s = 3 6 0 0 ) ) ) ,

13 d a t e t i m e (2020 , 2 , 17 , 0 , 0 , t z i n f o =

t i m e z o n e ( t i m e d e l t a ( d a y s =0 , s e c o n d s = 3 6 0 0 ) ) ) ]

14

15 d e l t a = p a r s e d M a x D a t e - p a r s e d M i n D a t e

16 b e t w e e n _ d a t e s = [ p a r s e d M i n D a t e + t i m e d e l t a ( d a y s = i ) for i in r a n g e( d e l t a . d a y s + 1) ]

17

18 if not any( x in n o t _ a l l o w e d _ d a t e s for x in b e t w e e n _ d a t e s ) :

19 v a i l d _ d a t e _ r a n g e = T r u e

20

21 r e t u r n [ S l o t S e t (" i s _ v a l i d _ d a t e s ", v a i l d _ d a t e _ r a n g e ) ]

Kodexempel 3.9: Metoden som avgör om användarens önskade semester är tillåten.

Beroende på om “is_valid_dates” sätts till true eller false tar konversationen olika vägar.

(39)

Vägval beroende på en slots värde kan göras genom stories. Kodexempel 3.10 och 3.11 är delar av två stories där “is_valid_dates” har värdet true respektive false. Kodexempel 3.10 visar att om “is_valid_dates” sätts till true svarar botten med “utter_ask_add_to_calender”, vilket innebär att användaren blir tillfrågad om hen vill lägga till semestern i sin kalen- der. Kodexempel 3.11 visar att om “is_valid_dates” är false svarar botten istället med

“utter_not_valid_dates” vilket innebär att botten meddelar användaren att det inte går att boka semestern mellan de valda datumen.

1 - s l o t {" i s _ v a l i d _ d a t e s ": t r u e }

2 - u t t e r _ a s k _ a d d _ t o _ c a l e n d e r

3 * a f f i r m

4 - b o o k _ i n _ c a l e n d e r

Kodexempel 3.10: Delen av storyn där is_valid_dates är true.

1 - s l o t {" i s _ v a l i d _ d a t e s ": f a l s e }

2 - u t t e r _ n o t _ v a l i d _ d a t e s

Kodexempel 3.11: Delen av storyn där is_valid_dates är false.

Efter att datumen är extraherade och godkända är det dags att lägga in semestern som en händelse i användarens Google Kalender. För att få tillgång att ändra användarens kalender skapades en webbserver som utförde alla nödvändiga handlingar. Mer infor- mation om varför en webbserver användes samt hur servern implementeras kan läsas i avsnitt 3.3.2.

3.3.1.2 Mötesbokning

Botten ska även kunna utföra mötesbokningar. Det är likt semesterbokningen att den också använder sig utav Google Kalender. Däremot är det annan data som botten behö- ver samla in samt att den bearbetas på ett annat sätt. Syftet med detta intent är att boka ett möte som passar alla inbjudna personer tidsmässigt. Informationen botten behöver är e-postadresser till alla personer som ska delta i mötet och ett preliminärt datum

(40)

för mötet. Botten använder en slot “invite_more_bool” som innehåller en boolean som representerar ifall användaren vill bjuda in ytterligare personer.

Även här används Duckling för datum. Duckling kan även extrahera e-postadresser, då de extraherade e-postadresserna hamnar i slot som heter “email”. Precis som i föregå- ende exempel 3.3.1.1 behövs formulärets slots kartläggning anpassas. Listing 3.12 visar hur slot mappingen ser ut i formuläret för mötesbokning. Det finns två slots: “invitee- mail” och “meeting_date” där inviteemail fylls med värdet från email och meeting_date fylls med värdet från time. Om användarens inmatning matchar någon av dessa intents:

“affirm_add_more”, “affirm” eller “inform_email” sätts invite_more_bool till true, om inmatningen matchar istället till intentet “deny” sätts invite_more_bool till false.

(41)

1 def s l o t _ m a p p i n g s ( s e l f ) - > D i c t [ Text , U n i o n [ Dict , L i s t [ D i c t ] ] ] :

2 r e t u r n {

3 " i n v i t e e m a i l ": [

4 s e l f . f r o m _ e n t i t y ( e n t i t y =" e m a i l ")

5 ] ,

6 " m e e t i n g _ d a t e ": [

7 s e l f . f r o m _ e n t i t y ( e n t i t y =" ti m e ")

8 ] ,

9 " i n v i t e _ m o r e _ b o o l ": [

10 s e l f . f r o m _ e n t i t y ( e n t i t y =" i n v i t e _ m o r e _ b o o l ") ,

11 s e l f . f r o m _ i n t e n t ( i n t e n t =" a f f i r m _ a d d _ m o r e ", v a l u e = T r u e ) ,

12 s e l f . f r o m _ i n t e n t ( i n t e n t =" a f f i r m ", v a l u e = T r u e ) ,

13 s e l f . f r o m _ i n t e n t ( i n t e n t =" i n f o r m _ e m a i l ", v a l u e = T r u e ) ,

14 s e l f . f r o m _ i n t e n t ( i n t e n t =" de n y ", v a l u e = F a l s e ) ,

15 ]

16 }

Kodexempel 3.12: Slot mapping för mötesboknings FormAction.

Klassen innehåller också två valideringsmetoder som definieras på följande sätt validate_{slot_name}. Validate körs precis innan en slot fylls med ett värde, på så sätt kan man kontrollera att värdet är korrekt. Nedanför förklaras varför metoderna

“validate_inviteemail” och “validate_invite_more_bool” behöver definieras.

Kodexempel 3.13 visar hur validate_inviteemail är skriven. Metoden behövs för att hantera de fall då användaren anger flera e-postadresser i samma meddelande eller i olika meddelanden. Ifall användaren skriver in flera e-postadresser i samma meddelande så läggs de i en lista som Duckling skapar automatiskt. Om det är en e-postadress lägger Duckling den som en sträng. E-postadresserna genom Duckling kan nås ifrån parame- tern value. Metoden skapar sedan en temporär sträng: “new_email_list” där alla angivna e-postadresser läggs till, separerade med kommatecken. Strängen new_email_list skrivs eller konkateneras ihop till en slot “emaillist” beroende på om emaillist var fyllt sen

(42)

tidigare eller inte.

1 def v a l i d a t e _ i n v i t e e m a i l ( self , v a l u e : Text , d i s p a t c h e r :

C o l l e c t i n g D i s p a t c h e r , t r a c k e r : Tracker , d o m a i n : D i c t [ Text , Any ] ,) - > D i c t [ Text , Any ]:

2

3 n e w _ e m a i l _ l i s t = " "

4

5 if ty p e( v a l u e ) == li s t:

6 for e in v a l u e :

7 n e w _ e m a i l _ l i s t = n e w _ e m a i l _ l i s t + e + " , "

8 e l s e:

9 n e w _ e m a i l _ l i s t = v a l u e + " , "

10

11 if t r a c k e r . g e t _ s l o t (" e m a i l l i s t ") == N o n e :

12 r e t u r n {" e m a i l l i s t ": n e w _ e m a i l _ l i s t }

13 e l s e:

14 r e t u r n {" e m a i l l i s t ": t r a c k e r . g e t _ s l o t (" e m a i l l i s t ") + n e w _ e m a i l _ l i s t }

Kodexempel 3.13: Metod som validerar inviteemail.

Den andra valideringsfunktionen “validate_invite_more_bool” som visas i ko- dexempel 3.14 behövs för att göra det möjligt för användaren att bjuda in ytterligare personer i ett nytt meddelande. Metoden blir anropad när sloten invite_more_bool ska fyllas, alltså när användaren svarar på bottens fråga om hen vill bjuda in ytterligare personer. Det första som kontrolleras är om användarens meddelande klassificeras som intentet affirm_add_more eller inform_email. Om detta är fallet betyder det att an- vändaren svarade på frågan genom att ange ytterligare e-postadresser. Dessa adresser läggs sedan till emaillist på samma sätt som i validate_inviteemail. Samtidigt töms invite_more_bool vilket innebär att botten kommer fråga användaren igen om hen vill bjuda in flera personer.

Om meddelandet klassificeras till dessa intents: “affirm” eller “deny” har inga

(43)

fler e-postadresser angivits. Om parametern value har värdet true vet botten att an- vändaren ändå vill ange fler e-postadresser, då töms invite_more_bool och inviteemail.

Om värdet på parametern är false betyder det att användaren svarade nej när hen blev tillfrågad att bjuda in fler personer och då fylls invite_more_bool med false och därmed avslutas formuläret.

1 def v a l i d a t e _ i n v i t e _ m o r e _ b o o l ( self , v a l u e : Text , d i s p a t c h e r :

C o l l e c t i n g D i s p a t c h e r , t r a c k e r : Tracker , d o m a i n : D i c t [ Text , Any ] ,) - > D i c t [ Text , Any ]:

2

3 if t r a c k e r . l a t e s t _ m e s s a g e [’ i n t e n t ’]. get (’ na m e ’) == "

a f f i r m _ a d d _ m o r e " or t r a c k e r . l a t e s t _ m e s s a g e [’ i n t e n t ’]. get (’ n a m e ’ ) == " i n f o r m _ e m a i l ":

4

5 e m a i l s = [ e [’ a d d i t i o n a l _ i n f o ’][’ v a l u e ’] for e in t r a c k e r . l a t e s t _ m e s s a g e [’ e n t i t i e s ’]]

6

7 n e w _ e m a i l _ l i s t = " "

8 for e in e m a i l s :

9 n e w _ e m a i l _ l i s t = n e w _ e m a i l _ l i s t + e + " , "

10

11 r e t u r n {" e m a i l l i s t ": t r a c k e r . g e t _ s l o t (" e m a i l l i s t ") + n e w _ e m a i l _ l i s t , " i n v i t e e m a i l ": t r a c k e r . g e t _ s l o t (" e m a i l ") , "

i n v i t e _ m o r e _ b o o l ": N o n e }

12

13 e l s e:

14 if v a l u e == T r u e :

15 r e t u r n {" i n v i t e _ m o r e _ b o o l ": None , " i n v i t e e m a i l ": N o n e }

16 e l s e:

17 r e t u r n {" i n v i t e _ m o r e _ b o o l ": v a l u e }

Kodexempel 3.14: Metod som validerar invitemorebool.

Botten skickar sedan all information som ett POST-request till samma server

(44)

som i semesterbokningen för att skapa mötet. När servern tar emot förfrågningen skapar den unika länkar för varje inbjuden e-postadress som sedan skickas. Länkarna leder till en sida på servern som direkt skickar användaren till Googles autentiseringssida där hen kan ge servern tillåtelse att få tillgång till hens kalender. När detta är gjort skickas en token tillbaka till servern som den kan använda sig av för att komma åt kalendern. Denna token sparas sedan undan som en pickle-fil som möjliggör det för servern att komma åt användarens kalender igen utan hen behöver ge tillåtelse en gång till. För att läsa mer om Google autentisiering läs avsnitt 3.3.2.

När alla inbjudna medlemmar har autentisierat sig går servern igenom de inbjud- na personernas kalendrar utgående från det preliminära datumet som botten samlade in.

Servern kommer åt kalendrarna eftersom den lagrade användarnas autentiseringstoken som pickle-filer. Servern försöker sedan hitta en timme mellan kl. 8-17.00 på vardagar där alla inbjudna personer är lediga, vilket är när ingen av personerna har en händelse i sin kalender. När detta är gjort är mötestiden bestämd och läggs till i allas kalendrar. I avsnitt 3.3.2 framgår det mer utförligt hur serverns ser ut och fungerar.

3.3.1.3 “Help desk”

En bot som kan hjälpa användaren få ett nytt lösenord samt svarar på vanliga frågor som till exempel öppningstider, jobbtillfällen och adressen till hemsidan. Om kundtjänst slipper svara på vanliga frågor och istället har en bot som ger svaren sparar kundtjänst mycket tid.

Kodexempel 3.15 visar hur botten kan hjälpa en användare som glömt sitt lö- senord. När en användare skriver till botten att hen har glömt sitt lösenord ber botten användaren att ange sin e-postadress så att botten kan skicka ett nytt lösenord. Eftersom botten är en demoprodukt sker detta dock inte på riktigt, utan är endast i demosyfte.

Precis som i mötesbokningen i avsnitt 3.3.1.2 används Duckling för att extrahera använ- darens e-postadress, där adressen sparas i “host_email” som är en slot. När host_email

(45)

är fylld svarar botten med en utter-action att ett slumpmässigt lösenord har skickats till den angivna e-postadressen. Se figur 4.3 för att se ett exempel på hur en konversation med glömt lösenord kan se ut.

1 c l a s s A c t i o n F o r g o t P a s s w o r d ( F o r m A c t i o n ) :

2 def n a m e ( s e l f ) - > T e x t :

3 r e t u r n " f o r g o t _ p a s s w o r d _ f o r m "

4

5 @ s t a t i c m e t h o d

6 def r e q u i r e d _ s l o t s ( t r a c k e r : T r a c k e r ) - > L i s t [ T e x t ]:

7 r e t u r n [" h o s t _ e m a i l "]

8

9 def s l o t _ m a p p i n g s ( s e l f ) - > D i c t [ Text , U n i o n [ Dict , L i s t [ D i c t ] ] ] :

10

11 r e t u r n {

12 " h o s t _ e m a i l ": [

13 se l f . f r o m _ e n t i t y ( e n t i t y =" e m a i l ")

14 ]

15 }

16

17 def s u b m i t ( self , d i s p a t c h e r : C o l l e c t i n g D i s p a t c h e r , t r a c k e r : Tracker , d o m a i n : D i c t [ Text , Any ] ,) - > L i s t [ D i c t ]:

18

19 d i s p a t c h e r . u t t e r _ m e s s a g e ( t e m p l a t e =" u t t e r _ s u b m i t ")

20 r e t u r n []

Kodexempel 3.15: Custom action för glömt lösenord.

1 u t t e r _ r e s e n d _ p a s s w o r d :

2 - t e x t : " A r a n d o m i z e d p a s s w o r d has be e n s e n t to { h o s t _ e m a i l } "

Kodexempel 3.16: Utter-action för glömt lösenord.

Botten ska även klara av att svara på vanliga frågor. Varje fråga har ett eget svar

(46)

i form av utter-action, det vill säga att botten endast svarar med ett enkelt meddelande.

Figur 3.17 visar hur utter-actions kan se ut.

1 u t t e r _ g i v e _ o p e n i n g _ h o u r s :

2 - t e x t : " Our o p e n i n g h o u r s are monday - f r i d a y : 8 -17 , s a t u r d a y : 9 -17 and s u n d a y : 10 -17. "

3 u t t e r _ g i v e _ w e b s i t e :

4 - t e x t : " Mo r e i n f o r m a t i o n can be f o u n d on our w e b s i t e at h t t p s ://

s o m e c o m p a n y n a m e . com "

5 u t t e r _ g i v e _ j o b _ p a g e :

6 - t e x t : " Job o p p o r t u n i t i e s , c a r e e r s and m o r e can be f o u n d on our w e b s i t e at \ n h t t p s :// s o m e c o m p a n y n a m e . com / jo b s "

Kodexempel 3.17: Utter-actions för FAQ.

3.3.2 Server för kalenderoperationer

Efter att chattbotten har samlat all information kring en uppgift som använder sig av Google Kalender krävs det att man gör lämpliga förfrågningar till Google Kalender- API:t som till exempel POST-request för att lägga till en händelse i kalendern. Innan det kan utföras behöver ägaren av kalendern autentisera sig och tillåta servern att göra ändringar i kalendern. Det är därför en webbserver behövs, för att be användaren om åtkomst till kalendern. Autentisieringen sker med hjälp av Google Oauth 2.0 som är Googles implementation av protokollet OAuth 2.0 Authorization Framework. Ramver- ket möjliggör det för en tredjeparts applikation att få begränsad åtkomst till en HTTP- applikation [29].

Autentiseringen inleds med att användaren blir omdirigerad till Google där hen kan logga in och välja att ge applikationen tillgång till det som efterfrågas, i det här fallet Google Kalender. När detta är gjort skickas användaren tillbaka till tredjeparts- applikationen samt att applikationen får en behörighetskod som kan bytas mot en access- och refresh token. Access- och refresh token användas för att tredjeparts-applikationen

(47)

ska komma åt den data användaren tillät när hen loggade in sig i början av autentiseri- engen. För att få tillgång till en behörighetskod måste man definiera en callback-adress vilket är dit koden skickas när användaren har autentisierat sig [30].

Detta betyder att en webbserver behövs för att gör alla förfrågningar till Google kalender API:t. Webbservern är skrivet i Python tillsammans med Flask, som är ett ramverk som möjliggör det att snabbt sätta upp en webbserver. Vi valde att hosta servern med hjälp av PythonAnywhere. PythonAnywhere tillåter en att sätta upp en server med begränsat minne i en begränsad tid helt gratis. PythonAnywhere gjorde det också lätt för oss att hosta en webbserver som använde Flask samt att det var enkelt att installera de Python-paket som krävdes.

3.3.2.1 Funktioner för semesterbokning

Som det framgick i avsnitt 3.3.1.1 skulle funktionaliteten för att lägga till en semester i sin Google Kalender finnas. För att göra detta kan servern anropas med addressen /bookvacation. När detta görs exekverar en funktion som tar emot URL-parametrarna

“minDate” och “maxDate”. Parametrarna sparas i en session där de sedan kan nås efter att användaren har autentiserat om hen inte gjort det vid tidigare tillfälle. Efter att användaren har autentiserat sig kan händelsen skapas. Det görs genom att skapa en Python dictionary som fylls med den data man vill skicka. Vilka fält som ska finnas i den samt vilken data som fälten ska innehålla beskrivs i Googles dokumentation för kalender-API:t.

Kodexempel 3.18 visar hur en händelse skapas för semesterbokningen. De enda fälten som fylls dynamiskt är start.datetime samt end.datetime, fälten beskriver över hur lång tid en händelse sträcker sig. Summary, location och description fylls statiskt och kommer alltså alltid ha samma värde. Här finns det definitivt rum för utveckling. Botten skulle kunna fråga användaren frågor för att fylla dessa fält, vilket hade gett händelsen lite mer substans.

References

Related documents

By measuring the delay, jitter and loss of the incoming data stream at the receiver, we can provide some indication on how suitable the network is for real-time voice

Låt oss därför för stunden bortse från bostadspriser och andra ekonomiska variabler som inkomster, räntor och andra kostnader för att bo och en- bart se till

Huvudskälet var att sänka produktionskostnaden genom att skapa förutsättningar för en god konkurrenssituation.. Genom delade entreprenader

Figur 8 visade att utsläppen av koldioxid har från sektorerna bo- städer och service tillsammans minskat med ca 20 % under åren 1995 till 2000 utan hänsyn tagen till inverkan av

2 Det bör också anges att Polismyndighetens skyldighet att lämna handräckning ska vara avgränsad till att skydda den begärande myndighetens personal mot våld eller. 1

Utredningen om producentansvar för textil lämnade i december 2020 över förslaget SOU 2020:72 Ett producentansvar för textil till regeringen.. Utredningens uppdrag har varit

Även om det finns en klar risk att aktörer som vid enstaka tillfällen säljer små mängder textil till Sverige inte kommer att ta sitt producentansvar står dessa för en så liten

Workshops with all actors, manufacturer interviews, user interviews, dealer interviews Manufacturer focus group, manufacturer interviews, dealer interviews, user interviews