Forrige påske flyttet Knowit Oslo til splitter nye lokaler i Sundtkvartalet, Lakkegata 53. Her deler vi kantina med blant annet IBM, Skanska og Mattilsynet. Sundt Chef er en bot for Slack som gir deg lunsjmenyen på Sundtkvartalet. Boten bruker Googles Dialogflow for å kunne tilby et “conversational interface”, og Google Cloud Functions for “serverless” funksjoner som laster ned HTML, trekker ut lunsjmenyer og lager meldinger formatert for Slack.
Overview
Slack App
Slack-appen Chef er tilgjengelig i Knowit Objectnet workspace, og har følgende funksjonalitet:
Dialogflow
Dialogflow (tidligere api.ai) tilbyr et web-grensesnitt for å bygge og teste “conversational agents”. Disse er basert på en natural language processing (NLP) engine som bruker en hybridløsning; en kombinasjon av machine learning og forhåndsdefinerte regler for klassifikasjon av brukerinput.
Slack Integration
Dialogflow har et brukergrensesnitt som gjør det enkelt å sette opp integrasjoner mot mange populære eksterne tjenester (bl. a. Slack). Dokumentasjonen tar deg stegvis gjennom prosessen med å opprette en Slack App og sette opp integrasjonen mot Dialogflow. Det er også mulig å få satt opp integrasjoner fra Dialogflow mot tjenester som bruker talestyring (som f. eks. Google Assistant, Alexa og Cortana).
Intent
En intent i Dialogflow er det som mapper brukerens input til handlingen som skal utføres. En intent bygges opp ved å legge inn noen eksempler på brukerinput, og i de fleste tilfeller må også deler av disse tekstene linkes til en eller flere entities. Entities brukes for å ekstrahere parameterverdier fra brukerens input.
sundt-chef er en relativt enkel agent som, med unntak av smalltalk og default fallback intent, kun trenger én intent med én entity. Jeg lagde en MenuForDay Intent og la inn eksempler på brukerinput som spør om lunsjmenyen for en gitt dag. Det eneste parameteret som trengs å trekkes ut fra denne inputen er dato/dag. I og med at dato er et veldig vanlig parameter har Dialogflow en forhåndsbygd entity, en såkalt System Entity, for datoer som kan brukes her. Denne mapper brukerens input, f. eks. “today” eller “the day after tomorrow”, til en dato i ISO-format.
Fulfillment Webhook
Dialogflow agenten er satt opp til å bruke en webhook for “fulfillment” dersom den detekterer en MenuForDay intent. Denne peker på en Google Cloud Function som tar imot requesten fra Dialogflow, og responderer med lunsjmenyen for forespurt dag.
Google Cloud Functions (+App Engine)
Google Cloud Functions er Googles FaaS-løsning som lar utviklere lage “serverless” JavaScript funksjoner som kjører i et Node.js-miljø.
For sundt-chef er det laget funksjoner som brukes som webhooks i Dialogflow- og Slack-integrasjonene. I tillegg til dette, er det også laget serverless API funksjoner som gjør det mulig for andre å hente ut lunsjmenyene i JSON-format.
Data Extraction
Selve menyen hentes fra Eurest sine nettsider (http://sundtkvartalet.eurest.no/ukens-meny/). Dette er server-side rendret HTML, og i og med at det ikke tilbys noen endepunkter for å hente ut menyen i et mer strukturert format, må siden “scrapes” for å hente ut dataen.
Cheerio implementerer et subset av jQuery, og kan brukes for parsing av HTML og DOM-traversering på server-siden. Cheerio gjorde det enkelt å trekke ut lunsjmenyen:
Caching
Jeg la merke til at menyen til tider var utilgjengelig på nettsiden til Eurest. Nettsiden brukte også av og til lang tid på å respondere. I kombinasjon med en mulig “cold start” av funksjonen på GCP kunne dette føre til at det enkelte ganger tok mer enn 5 sekunder fra requesten ble sendt (fra Dialogflow) til en respons ble mottatt. Jeg tok derfor i bruk en Memcached Cloud bucket hos Redis Labs som resulterte i redusert responstid, høyere tilgjengelighet, og sannsynligvis også jevnere fordelt trafikk mot Eurest sine nettsider.
Cron Jobs
I motsetning til AWS Lambda, har ikke Google Cloud Functions (som fortsatt er i beta) støtte for scheduled tasks/cron jobs. Jeg var derfor nødt til å legge på en liten App Engine shim for å utføre tidsplanlagte handlinger. Jeg valgte å skrive denne i Python fordi det krevde lite “boilerplate” kode.
Denne applikasjonen har to cron jobs:
Se kode og dokumentasjon på GitHub:
https://github.com/sivapalan/sundt-chef