Un Turno di Botler - RetiSpA/botler GitHub Wiki
Un Turno di Botler
Cos'è un turno? Un turno è semplicemente l'invio di un messaggio da parte dell'utente. Il Bot Framework v4 ha semplificato molto questo aspetto implementativo, fornendo metodi di alto livello, ad ogni arrivo di un messaggio il bot chiama il seguente metodo:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
await TurnController.TurnHandlerAsync(turnContext, cancellationToken);
}
Il TurnController si occupa di gestire tutte le possibili ActivityTypes di un messaggio, vediamo ora l'entry point di questa classe:
public async Task TurnHandlerAsync(ITurnContext turn, CancellationToken cancellationToken = default(CancellationToken))
{
currentTurn = turn;
currentActivity = turn.Activity;
switch (currentActivity.Type)
{
case ActivityTypes.Message:
await StartMessageActivityAsync(cancellationToken: cancellationToken);
break;
case ActivityTypes.ConversationUpdate:
await StartConversationUpdateActivityAsync(cancellationToken: cancellationToken);
break;
case ActivityTypes.Event:
await StartEventActivityAsync(cancellationToken: cancellationToken);
break;
}
}
- Un ActivityTypes.Message è un generico messaggio ricevuto dall'utente
- Un ActivityTypes.ConversationUpdate avviene all'inizio di una converazione o al suo restart, e qui che il bot manderà il suo messaggio di benvenuto
- Un ActivityTypes.Event sono tipologie presenti molto nella chat tipo Teams
Gestione di un Activity di tipo Message
Questa come possiamo immaginare è la parte principale del ChatBot, poichè è ovvio che la maggior parte dei messaggi sarà di questo tipo, ma vediamo come è gestita questa Activity
private async Task StartMessageActivityAsync(CancellationToken cancellationToken = default(CancellationToken))
{
// Chiamamo le API di LUIS e creaimo un instanza con le informazioni utili provvenienti da LUIS.
LuisServiceResult luisServiceResult = await LuisServiceResultBuilder.CreateLuisServiceResult(currentTurn, _services,
cancellationToken);
// Controlliamo che nel messaggio non ci sia un intent di Interruzione della conversazione (Saluto, Richiesta info
e.g)
if (await InterruptionRecognizer.InterruptionHandledAsync(luisServiceResult, currentTurn))
{
await _accessors.SaveStateAsync(currentTurn); // Salva lo stato nel MemoryStorage Locale
return;
}
// Qui controlliamo invece se nel messaggio ci sia un un comando rapido da eseguire
if (await CommandRecognizer.ExecutedCommandFromLuisResultAsync(luisServiceResult, _accessors, currentTurn))
{
await _accessors.SaveStateAsync(currentTurn);
return;
}
// L'ultimo controllo riguarda il QnA: controlla se non ci sia una domanda a cui rispondere
if (await QnAController.AnsweredTurnUserQuestionAsync(currentTurn, _accessors, _services))
{
await _accessors.SaveStateAsync(currentTurn);
return;
}
// Se tutti questi controlli ritornano 'false' si prosegue con la creazione di una risposta più complessa
// basata su LUIS e il contesto della conversazione
await CreateScenarioResponseWithLuisAsync(luisServiceResult);
}
Continiuamo con l'ultimo metodo chiamato da questa Activity
private async Task CreateScenarioResponseWithLuisAsync(LuisServiceResult luisServiceResult)
{
IScenario currentScenario = await ScenarioRecognizer.ExtractCurrentScenarioAsync(luisServiceResult, _accessors,
currentTurn);
// * Gestisce lo scenario in base al suo contesto * //
await currentScenario.HandleScenarioStateAsync(currentTurn, _accessors, luisServiceResult);
// * Salva lo stato di questo turno nel cosmbosDB * //
await BotStateBuilder.BuildAndSaveBotStateContextContext(currentTurn, _accessors, luisServiceResult, currentScenario);
// * Salva lo stato nel MemoryStorage * //
await _accessors.SaveStateAsync(currentTurn);
}
Uno Scenario ha in se un insieme di Dialoghi che potrà eseguire, dividere i dialoghi in base agli scenari, facilità molto la logica e la loro gestione.
In altre pagine saranno disponibili ulteriori dettagli sull'interfaccia IScenario e il BotStateContext