Conversation Logging feature enables you to register interactions between user and conversational agent (bot), bringing option to obfuscate sensitive data (both input and output). JAICF provides several abstractions and default implementations to solve conversation logging issue.

val templateBot = BotEngine(
    model = MainScenario.model,
    activators = arrayOf(RegexActivator),
    conversationLoggers = arrayOf(
        Slf4jConversationLogger(),
        JaicpConversationLogger(accessToken)
    )
)

How does it work?

Once JAICF receives a BotRequest, it creates a LoggingContext internal object that collects information about request’s input, selected activation (state and activation context) and all reactions generated by your dialogue scenario. When request processing is finished, JAICF fires the logging of the collected data.

val reactionsLogger = object : ConversationLogger(logObfuscators = emptyList()) {
    override fun doLog(loggingContext: LoggingContext) {
        println("Our reactions are: ${loggingContext.reactions}")
    }
}

Reaction

A reaction object is a result of performing channel’s reaction. Every function of the base Reactions (say, image, buttons, go and changeState) creates and registers the resulting Reaction to the current logging context.

state("Hello") {
    activators {
        intent("/start")
    }
    action {
        reactions.say("Hello there!") // Creates SayReaction and stores it to the LoggingContext
    }
}

ConversationLogger

It’s the main abstraction for an object, that registers interactions between user and bot. Implementations of this abstraction should override only single method doLog, having LoggingContext as argument that contains necessary information regarding user’s query processing.

val historyTellingLogger = object : ConversationLogger(logObfuscators = emptyList()) {
    override fun doLog(loggingContext: LoggingContext) {
        println("""
            I was resting in state ${loggingContext.firstState}, then someone sent me ${loggingContext.input}.
            I decided to let ${loggingContext.activationContext?.activation?.state} handle this query,
            and it all messed up and I reacted with ${loggingContext.reactions}.
        """.trimIndent())
    }
}

ConversationLogger expects a list of log obfuscators as a property. Log obfuscators obfuscates LoggingContext data before doLog method is called. Thus doLog method always receives an obfuscated LoggingContext.

ConversationLogObfuscator

This abstraction enables you to hide sensitive data before it’s logged.

val numberObfuscator = object : ConversationLogObfuscator {
    override fun obfuscateInput(loggingContext: LoggingContext) = loggingContext.input.map { char ->
        if (char.isDigit()) '*'
        else char
    }.joinToString("")
}

Once request is processed and all reactions are created, JAICF obfuscates BotRequest input and Reactions.

Ready to use implementations

You may take a look at Slf4jConversationLogger or JaicpConversationLogger implementations before creating a new custom one, or use existing ones.

Slf4J

Slf4jConversationLogger utilises Slf4J logging engine that can be enabled by placing logback.xml to the resources folder of your project. Please learn more about Logback and Slf4J.

JAICP

JaicpConversationLogger automates logging of users’ inputs and reactions to the JAICP logging system.

CAILA NER obfuscator

There is also a built-in implementation of ConversationLogObfuscator for CAILA NLU - CailaNamedEntityObfuscator that either hides all found entities in request, or hides only entities from list given.