What the FAQ are you talking about?

As you may have noticed I like the Microsoft Cognitive Services a lot. There is quite a nice, preview, service called QnA maker, which takes your QnA items on e.g. a FAQ page and applies some Machine Learning to it. The great thing is that you can very easily attach a bot that can answer frequently asked questions to that knowledge base. You can also create a bot with the botbuilder samples or just use the API to generate an answer.

You can have QnA maker scan your FAQ page and retrieve the QnA pairs from it, but where’s the fun in that…

So I created a module that will create, update, delete your knowledge bases right from within the CMS.  I’m not going to deep dive into the code, it’s pretty straight forward, but here is how it works.

I assume you have an overview page that displays your FAQ items, the FAQ items being blocks.

First add a [QnaOverviewPage] attribute to your class. Add a string property to hold the knowledge base ID and mark it with [QnaKnowledgebaseId]. Mark the ContentArea with [QnaContainer]. You can add a string property for the name, if you don’t want to use the page name, for the knowledge base and mark it with [QnaKnowledgebaseName].

Second add a [QnaItem] attribute to your QnA block. Mark the question with [QnaQuestion] and the answer with [QnaAnswer].

When publishing your overview page it creates a knowledge base for you, if there isn’t one yet. It gets the QnA items on that page and adds them to the knowledge base. Moving the overview page to the trash deletes the knowledge base and empties the id property.

In short, there are a bunch of content events that take care of the interaction with your knowledge base.

The tricky part was figuring out if an item should be added or deleted from the knowledge base. For this I needed the previous version of the content and check if a block was added or removed. I created an extension method for it in the core package.

public static IContent PreviousVersion(this ContentReference contentReference)
{
    if (ContentReference.IsNullOrEmpty(contentReference))
    {
        return null;
    }

    try
    {
        ContentVersion previousVersion =    ContentVersionRepository.List(contentReference)
                    .OrderByDescending(x => x.Saved).FirstOrDefault(
                        version => version.IsMasterLanguageBranch
                                   && version.Status == VersionStatus.PreviouslyPublished);

        if (previousVersion == null)
        {
            return null;
        }

        IContent previousContent;
        return ContentRepository.TryGet(contentLink: previousVersion.ContentLink, settings: LanguageSelector.AutoDetect(true), content: out previousContent)
                           ? previousContent
                           : null;
    }
    catch (ActivationException activationException)
    {
        LogException(exception: activationException);
        return null;
    }
    catch (ArgumentNullException argumentNullException)
    {
        LogException(exception: argumentNullException);
        return null;
    }
}

The method is also used for checking if the question has changed for an item, as it needs to be deleted in that case and re-added with the new question.

You can share QnA items on different overview pages. Changes to a QnA item will be done on all knowledge bases it is used on.

Available in the core package is also a base template you can implement if you are not using a contentarea with blocks for your FAQ. There are extension methods for checking if content is an overview page or a QnA item, extracting the QnA pairs from the content, etc. Hopefully this will make it easier to implement your own implementation of you are not using blocks.

The complete project is on GitHub and the packages will be available on the Episerver NuGet feed in a while, if they get approved of course.

3 thoughts on “What the FAQ are you talking about?

Leave a comment