Code Monkey home page Code Monkey logo

covid-bot's Introduction


title: VT Covid Bot Documentation permalink: /

COVID FAQ & ChatBot

The Vermont Department of Health has a knowledge base that is published via a chatbot and faq page in response to the COVID-19 pandemic

Docs

Published via gh-pages, jekyll, and cayman theme at:

VermontDepartmentofHealth.github.io/covid-bot/

Repo Structure

1. Application Insights Query

Query written in Kusto/KQL to get info from logs in App Insights

2. Bot Service

.NET Core API written in C# that connects to the knowledge base.

3. FAQ Site

NodeJS static site generator written using Eleventy that templates the knowledge base into FAQ.

4. Knowledge Base API

Postman collection to call methods in the Knowledge Base API

5. kb-node-client library

Provides a NodeJS client wrapper around the Cognitive Services APIs for QnaMaker

6. md-diff library

A diffing implementation for comparing & returning markdown text deltas

7. QnA Maker

QnA Maker front end to create, maintain, test, and publish the Knowledge Base

8. WebChat Client

Front end chat client that calls the bot service, either as an iFrame or JS initialization.

Testing

For testing purposes, please use the following links to not interfere with our production telemetry

Acronyms

VDH ~ Vermont Department of Health

FAQs ~ Frequently Asked Questions

KB ~ Knowledge Base

AI ~ Application Insights

QnA ~ Question and Answer


Resources

Forums

covid-bot's People

Contributors

gracedemler avatar jmathias3 avatar jmathias33 avatar kylemit avatar sandraleblanc avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

covid-bot's Issues

add analytics to FAQ site

State already uses Google Analytics on HealthVermont.gov - see if we can extend that instance or if we need to create our own

Add popover for web chat client

Add persistent chat icon to the page that expands to client when clicked

Simple implementation

function popupFunction() {
    var x = document.getElementById('chatFrame');
    if (x.style.visibility == 'hidden') {
        x.style.visibility = 'visible';
    }
    else {
        x.style.visibility = 'hidden';
    }
}

build automated deployment using KB API

Either Node or C#

Can use node client wrapper @ads-vdh/qnamaker-api

Current Workflow:

  • Publish KB on Test
  • Export via Excel on Test
  • Import via Excel on Prod
  • Publish KB on Prod

Problems

  • Manual process
  • Destroy question IDs
    • Never synchronized on test/prod
    • Prod IDs keep getting replaced
    • Test IDs are brittle if we need to do a restore/backup (otherwise appropriately revisioned via QnA Maker)

Any wholesale replacement .replace() method or excel import will re-write IDs

Only way to persist IDs is directly making modifications in QnA Maker or calling .update() method

Update Method

  • add
  • update
  • delete

Restore on TEST (only as a backup to QnA Maker)

  1. current test .download()
  2. modified faq - local file with changes forked from the test faq
  3. look for any changes within each id
    • if we have changes, send update instruction
  4. look for any IDs in current, not in previous
    • if we have additions, send add instruction
  5. look for any IDs in previous, not in current
    • if we have deletes, send delete instruction

Publish to PROD - simple

  1. testClient
    • alterations.get()
    • knowledgebase.donwload()
  2. prodClient
    • alterations.replace()
    • knowledgebase.replace() // wholesale replace
    • knowledgebase.publish()

Update on PROD - with ID matching (hard)

  1. previous test/faqs.json
  2. current test/faqs.json
  3. look for any changes within each id
    • if we have changes, send update instruction
      • take test id that was updated, find production id to update (hard)
  4. look for any IDs in current, not in previous
    • if we have additions, send add instruction
      • test test question that was added, add brand new question (ID yet to generated) (hard)
  5. look for any IDs in previous, not in current
    • if we have deletes, send delete instruction
      • take test id that was deleted, find production id to delete (hard)

Test -> Production id lookup

  1. Possibly off name of question, but brittle if name changes
  2. Possibly off independently persisted test-to-prod lookup

check for common QnA maker issues

Check for the following things:

  • Answer starts with bold text (presumably the original question)
  • QnA has category metadata tag
  • The category tag is part of parent list (topics.json)
  • URL's are fully qualified (begin with http)
  • URL's are valid (return 200 status code)

automate deployment of FAQ site

Targets

  • Test
  • Prod

Events

  • Commit on Main -> Prod
  • On KB Publish -> Test
  • Button Click -> Test/Prod

Current State

  • Build Locally
  • Move Files

Hosting Options

  • on network
  • cloud
    • netlify
    • azure static sites
    • gh-pages

Challenges

  • git commits
  • authentication

Actions

  • publish
  • deploy-kb
  • fetch
  • archive
  • lint
  • list

Todo

  1. Create Azure Static Sites bucket

    1. Create Storage Account
    2. Create Static Web Site
    • Blob Containers > $web
    1. Upload via Azure Storage Explorer

      https://sovcovidbotteststorage.z13.web.core.windows.net/
      https://apps-test.health.vermont.gov/COVIDFAQ/

  2. Repoint proxy to azure static sites

  3. GH Action to build and deploy site to Azure

  4. Click a button -> run a command -> return info

enhance historical changes

  • build historical file (initial)
    • extract all previous versions of a file from git (with date stamp as name) [manual|script]
  • display last update date at question level
  • provide diffing for any changes over last [3|4|5]? days
  • refactor how we archive questions (ongoing)
    • add changes to revisions history as soon as they appear if there's a delta

Possible archive format:

[
    {
        "id": 4534,
        "revs": [
            {
                "date": "2020-07-13",
                "question": "What are the symptoms of CoronaVirus",
                "answer": "People with COVID-19 have had a wide range of symptoms reported"
            },
            {
                "date": "2020-07-14",
                "question": "What are the symptoms of COVID-19?",
                "answer": "People with COVID-19 have had a wide range of symptoms reported"
            }
        ]
    }
]

send alternative response to very long questions

Send alternative response if word count is over a particular length (i.e. >75) - something like this:

Sorry, I'm just an automated bot. I can't easily address long or complex questions. Please try asking me a more general question or try calling calling 2-1-1 to talk to a real live person

New Config Values:

  • LongQuestionWordCountThreshold
  • LongQuestionResponse

Acceptance Criteria:

  • incoming message should still be logged
  • only return custom response

allow gzip compression

There is an issue with our reverse proxy when we have outbound rules. URL Rewrite will complain if the response is compressed because it can't inspect and alter traffic. We need to either eliminate outbound rules or filter the active ones to make sure they only try to fire when they already have a match on the resource path.

Add card footer action

Instead of adding follow up prompt - "this did not answer my question" - automatically add card submit action

Adaptive Card Visualizer
Add card actions to a bot

This could possibly be attached to logging that information directly

An advanced feature would be to submit user info for someone to follow up - but this process workflow would have to be run by communications first

show revision history in FAQ

be able to compare deltas and show insert / delete text from previous day or over time

We can use some semantic demarcating edits tags:

A couple potential vehicles:

  1. Build daily site output with the date timestamped and keep built version. Possibly add revision controls. This allows for exploring previous days, but no succinct diff.
  2. During update data - move existing data to faqs-prev.json and new data to faqs-cur.json. Then when building site, grab both data sets (IDs must match) and build updated markdown with diffs

track conversation history

Stack Overflow Thread: Looking for a unique “Conversation ID” in the App Insights for QnA Maker

We currently have a kql query in app insights that joins on a partial ID match

// answered and unanswered
let startDate = todatetime("2020-03-25T16:30:00");
// bad convo ids
let wrongIDs = traces
| where customDimensions.Question contains "This did NOT answer my question" 
| project extract("^[a-z0-9]{7}", 0, itemId);
// get all q/a pairs
traces
| extend input = tostring(customDimensions.Question),
        answer = tostring(customDimensions.Answer),
        scoreInt = toint(round(todouble(customDimensions.Score))),
        convoId = extract("^[a-z0-9]{7}", 0, itemId)
| where message contains "GenerateAnswer"
    and input  !contains "This did NOT answer my question"
    and timestamp > startDate
| extend score = iif(convoId in (wrongIDs), -1, scoreInt), // separate bad vs good
         EST = datetime_add("hour", -4, timestamp)         // convert UTC to EST
| order by timestamp desc 
| project itemId,
          input,
          faq = extract("^\\*\\*(.*)\\*\\*", 1, answer),
          type = case(score == -1, "wrong",
                      score == 0, "no answer",
                      "answered"),
          score,
          timestamp = format_datetime(EST, "MM/dd/yyyy hh:mm tt")

But we should confirm if this is the best approach or potentially customize the build

add synonyms to faq-site filter

We can download QnA Maker Alterations using the Alterations API

Then pass into mark.js options object which takes a synonyms property:

An object with synonyms. The key will be a synonym for the value and the value for the key. Example: "synonyms": {"one": "1"} will add the synonym "1" for "one" and vice versa

add structured data to FAQ site

Add Google's Structured Data tags for FAQ data

faq example

Data should look something like this:

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": " What are the symptoms of COVID-19?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "People with COVID-19 have had a wide range of symptoms reported – ranging from mild symptoms to severe illness. Symptoms may appear 2 to 14 days after exposure to the virus. Not everyone infected with the COVID-19 virus has symptoms. People with these symptoms may have COVID-19:"
      }
    }, {
      "@type": "Question",
      "name": " Can I take ibuprofen for COVID-19 symptoms?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Some early news reports suggested that non-steroidal anti-inflammatory drugs (NSAIDs), such as ibuprofen, could worsen coronavirus disease. However, the Food and Drug Administration (FDA) has said it is not aware of any scientific evidence connecting the use of NSAIDs with worsening COVID-19 symptoms at this time. The FDA is investigating this issue further."
      }
    }
  ]
}

convert faq and tools to typescript

update node modules to be built and consume typescript

this should fix the fact that when passing an instance of the kb-node-client to a function, we lose intellisense because we can't explicitly type the incoming parameters (without duplicating a lot of work in jsdoc comments).

Customize Web Chat Client

Features

  • Hide attachment icon next to question box
  • Wrap Follow up Prompt Text
  • Add VDH Logo

Deployment

  • Add direct address to just embeddable bot built with script
  • Add Demo of iframe to direct chatbot embed

Hide Attachment Icon

From this post on How to disable attachment in botframework, we can do by switching to the JS renderer instead of using an iFrame like this:

window.WebChat.renderWebChat({
  directLine: window.WebChat.createDirectLine({ token }),
  styleOptions: {
    hideUploadButton: true
  }
}, document.getElementById('webchat'));

Wrap Follow Up Prompt

.ac-actionSet .ac-pushButton>div {
    overflow: visible !important;
    text-overflow: initial !important;
    white-space: normal !important;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.