The goal is to build a computer that can be more effective in understanding and interacting in natural language, but not necessarily the same way humans do it.
David Ferrucci
Watson è diventato famoso per la sua partecipazione a Jeopardy!, come abbiamo visto in questo articolo “Watson: alla ricerca di una nuova sfida”, battendo i due più grandi giocatori di sempre: Ken Jennings e Brad Rutter.
Jennings, durante la stagione 2004-2005, ha avuto la serie di vittorie più lunga di tutto lo show con ben 74 partite di fila. Invece Rutter ha vinto più soldi di qualsiasi altro giocatore di Jeopardy! con quasi $3,3 milioni di dollari.
Avvia Watson Assistant
Watson Assistant raggruppa la knowledge base del nostro chatbot sotto forma di una o più skills, che contengono le risorse necessarie per comprendere la richiesta dell’utente (NLU) e restituire la risposta migliore (Dialog).
Quando l’utente scrive al chatbot, Watson Assistant attiva l’NLU per riconoscere l’intent e e le entiries estratte dalla frase dell’utente. Dopo questa analisi, vengono controllati i nodi del flusso di dialogo.
Step 1- IBM cloud account
Watson Assistant fa parte del catalogo dei servizi IBM Cloud e per iniziare dobbiamo crearci un’account tramite questo link.
Dopo aver eseguito il login, ci rechiamo nell’elenco delle risorse e cerchiamo come servizio a cui siamo interessati Watson Assistant.
Step 2 – Create Assistant
Assistant raggruppa la basi di conoscenza del nostro chatbot sotto forma di skills andando così a dare all’assistente una o più abilità (skills) per essere in grado di gestire i diversi scenari con l’utente.
Ogni Assistant deve avere minimo una skill, nella quale decideremo quali saranno gli intents e le entities che potrebbero essere contenute nelle richieste dell’utente.
In questo articolo “Coffee Chatbot: annotazione rapida del dominio” avevamo già iniziato ad immaginare di dover realizzare un chatbot per la bottega del caffè annotando i primi intents ed entities quindi daremo il nome di Coffee al nostro Assistant.
Step 3 – Create Dialog Skill
Infine progettiamo una finestra di dialogo in cui specifichiamo le risposte in base all’intenzione e alle entità dell’utente.
Scegliamo il nome della skill (1) e dobbiamo fare molta attenzione a scegliere la lingua (3) corretta, perchè sarà la lingua di default del chatbot.
La descrizione (2) non è un campo aobbligatorio, ma come come best practice è meglio scrivere qualcosa di significativo in modo da poterla identificare facilmente. Dopo aver definito i campi, facciamo clic sul pulsante “Create dialog skill”.
Linguaggio naturale
Watson Asssistant per comprendere il linguaggio naturale, con cui l’utente esprime le sue richieste, dev’essere in grado di classificare gli intenti, riconoscere le entities, rilevare la irrilevanza di una richiesta e controllarne anche l’ortografia.
Quando sono in Colombia Rituales (Circular 74 # 39B-22) è uno dei miei caffè preferiti a Medellìn per lavorare da remoto perchè silenzioso e tranquillo. In questo articolo avevamo già iniziato ad annotare i primi intents ed entities.
Watson utilizza l’hashtag (#) per l’annotazione degli intents e il segno at (@) per le entities. Avevamo indentificato l’intent #orderCoffee per le richieste generiche di caffè:
mi faresti un caffè gentilmente un caffè avrei voglia di un caffè
e identificato due entities @types, @sizes per le richieste come:
vorrei un [@types cappuccino] in una tazza [@sizes media]
#Intents
L’intent è l’obiettivo espresso nella richiesta del nostro utente, come richiedere l’acquisto di un caffè: #orderCoffee
Affinché Watson riconosca gli intents dobbiamo fornire un numero sufficiente di esempi di richieste:
- mi faresti gentilmente un caffè - mi faresti un macchiato - potrei avere un caffè americano per favore - ho voglia di un caffè liscio - vorrei ordinare un caffè normale - mi faresti un caffé freddo - avrei voglia di un caffè stretto
@Entities
Le entities rappresentano gli oggetti del mondo reale, per gli sviluppatori l’idea che più ci si avvicina è quella di oggetto della programmazione orientata agli oggetti (OOP).
Una volta estratte le entities dalla richiesta dell’utente, possiamo scegliere dalla finestra del Dialog l’azione da intraprendere per soddisfare l’intent.
Quando creiamo una nuova entity il fuzzy matching è attivo di default, ma possiamo disabilitarlo quando vogliamo.
Questa feature migliora la capacità del chatbot di estrarre le entities nonostante la presenza di errori di ortografia o lievi differenze sintattiche. Ad esempio, se non abbiamo inserito il plurale di cappuccino @type:cappuccino nei sinonimi, ma l’utente digita cappuccini verrà ugualmente riconosciuto.
potrei avere un caffè americano in una tazza media
Se prendiamo l’utterance “potrei avere un caffè americano in una tazza media” oltre all’intent #orderCoffee dobbiamo creare un’entity per la tipologia del caffè @type.
affogato, americano, cappuccino, doppio, espresso, panna, ristretto, schiuma, turco cappuccino secco, capuccino umido, cortado,
Inoltre dobbiamo creare una entity @coffeeCupSizes per la misura del caffè richiesto dal cliente.
piccolo, medio, grande
System entities
Watson fornisce una serie di entities di sistema da utilizzare per popolare rapidamente la skill in casi come date, nomi di persone o luoghi.
L’entity @sys-number rileva i numeri scritti in numero o in parole restituendo un valore numerico.
vorrei ordinare due cappuccini vorrei ordinare 2 cappuccini
Python Datamodels
Adesso non ci resta che scrivere il codice in Python per fare la nostra prima richiesta a Watson, iniziamo con ottenere i dati dell’API facendo click sui settings dell’Assistant che abbiamo chiamato Coffee.
I dati che andremo ad utilizzare sarano:
- Assistant id
- Assistant url
- API key
Request
import requests import json from models.watson_response import WatsonResponse class WatsonRequest(object): def __init__(self, assistant_id): self.assistant_id = assistant_id self.assistant_url = "" self.api_key = "" self.version = "2020-04-01" def prediction(self, utterance): headers = { 'Content-Type': 'application/json', } data = { "input": { "text": utterance } } assistant_url = f"{self.assistant_url}/v2/assistants/{self.assistant_id}/ message?version={self.version}" res = requests.post(assistant_url, headers=headers, data=json.dumps(data), auth=('apikey', self.api_key)) data = json.loads(res.text) wr = WatsonResponse(data) res = { "text": wr.text, "intents": wr.intents, "entities": wr.entities } return res
Response
class WatsonResponse(object): def __init__(self, properties=None): self.entities = list() if properties is not None and len(properties) > 0: for key in properties.keys(): self.custom_properties(properties[key], key) def custom_properties(self, value, prop): if prop == 'output': self.intents = value['intents'][0]['intent'] if len(value['entities']) > 0: entities = value['entities'] for entity in entities: e = { "entity": entity['entity'], "value": entity['value'] } self.entities.append(e) self.text = value['generic'][0]['text']
Testing
Non avendo ancora configurato il Dialog di Watson per la gestione delle risposte il nostro chatbot risponderà alla richiesta di un caffé macchiato di non aver capito.
assistant_id = "" wr = WatsonRequest(assistant_id) r = wr.prediction("vorrei un caffé macchiato")
Dalla risposta possiamo vedere che viene riconosciuto correttamente l’intent legato alla richiesta di un caffé (#orderCoffee) e che ne vogliamo solo uno (@sys.number) e che sia un macchiato (@type).
{ "text":"Non ho capito. Puoi riformulare la frase?", "intents":"orderCoffee", "entities":[ { "entity":"sys-number", "value":"1" }, { "entity":"type", "value":"macchiato" } ] }
Sitografia
[1] Oliver Ivanoski, Beyond Coding: Watson Assistant Entities — Part 1, A Quick Overview, Medium, 2019
[2] Oliver Ivanoski, Beyond Coding: Watson Assistant Entities — Part 3, System Entities, Medium, 2019
[3] Oliver Ivanoski, Beyond Coding: Watson Assistant Entities — Part 4, New System Entities, Medium, 2019
[4] Oliver Ivanoski, Beyond Coding: Watson Assistant Multiple Conditioned Responses, Medium, 2019
Documentazione ufficiale
[1] Apidocs