Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 100 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ A template server for business logic integration with the Clinc AI platform.
```
docker-compose up
```

# Start the server on Heroku
1. Create an app on Heroku.
2. In the `Settings` page of the heroku app, configure the app to use the default stack (currently `heroku-16`) and the python buildpack.
Expand All @@ -20,17 +19,28 @@ docker-compose up
5. Push to the github repo and deploy the heroku app. You can either configure the heroku app to automatically deploy on every push to a branch or manually deploy.
6. Configure in the Clinc Platform to connect to the heroku app. Refer to the documentation in the Clinc Platform for details.

# Business logic interface

## Request
# Business Logic Interface

A user can insert arbitrary Business Logic into a custom competency by using a webhook. In this section, we will discuss setting up a webhook, including how to use it to insert and edit the variables that are used for response generation.

Business Logic Setup
------------------------------
1. In the upper right corner, click on the drop-down menu that is labeled with the user's username.
1. In that drop-down, click on the *Settings* tab.
1. Once on the settings page, enter the webhook URL into the appropriate input box.
1. Check off the competencies that the user would like to invoke business logic for.

## Business Logic Request

On every request, Clinc will check (1) if the you have business logic set up, and (2) whether the current competency is enabled with business logic. If both conditions are true, it will call your business logic with a request similar to the following:
On every request, the platform will check (1) if the user has Business Logic set up, and (2) whether the current Competency is enabled with Business Logic. If both conditions are true, it will call the user's Business Logic with a request similar to the following:

```
POST /<BL-URL> HTTP/1.1
{
"lat": 42.2730207,

"qid": "6d090a7e-ba91-4b49-b9d5-441f179ccbbe",
"lat": 42.2730207,
"lon": -83.7517747,
"state": "transfer"
"dialog": "lore36ho5l4pi9mh2avwgqmu5mv6rpxz/98FJ",
Expand All @@ -40,8 +50,7 @@ POST /<BL-URL> HTTP/1.1
"slots": {
"_ACCOUNT_FROM_": {
"type": "string",
"required_matches": "GT 0",
"candidates": [
"values": [
{
"tokens": "John's checking account",
"resolved": -1
Expand All @@ -50,8 +59,7 @@ POST /<BL-URL> HTTP/1.1
},
"_ACCOUNT_TO_": {
"type": "string",
"required_matches": "GT 0",
"candidates": [
"values": [
{
"tokens": "credit card",
"resolved": -1
Expand All @@ -60,8 +68,7 @@ POST /<BL-URL> HTTP/1.1
},
"_TRANSFER_AMOUNT_": {
"type": "string",
"required_matches": "GT 0",
"candidates": [
"values": [
{
"tokens": "$400",
"resolved": -1
Expand All @@ -71,50 +78,49 @@ POST /<BL-URL> HTTP/1.1
}
}
```
### Explanation of business logic payload:

* `lat` : Latitude of the query origin
* `qid` : Query ID
* `lon` : Longitutde of the query origin
* `state` : The state that the classifier predicted for the current query
* `dialog` : The dialog token
* `device` : The device the query was made on
* `query` : The query that was made
* `time_offset` : The time zone offset from UTC
* `slots` : The slots that were extracted for the query
### Explanation of Business Logic payload keys:

The only mutable fields in the business logic payload are `slots` and `state`, which will be explained in more detail below
* `lat` : Latitude of the query origin.
* `qid` : Query ID.
* `lon` : Longitude of the query origin.
* `state` : The state that the classifier predicted for the current query.
* `dialog` : The dialog token.
* `device` : The device on which the query was made.
* `query` : The query that was made.
* `time_offset` : The time zone offset from UTC.
* `slots` : The slots that were extracted for the query.

The only mutable fields in the business logic payload are `slots` and `state`, which will be explained in more detail below.

### Explanation of `slot` dictionary:

* `required_matches` : The fulfillment criteria for matching a slot, and the supported operators include `EQ` (equal to), `GT` (greater than), `GE` (greater than or equal to), `LT` (less than), and `LE` (less than or equal to)
* `candidates` : A list of matching candidates extracted form the user query
* `type` : The type of the data in the slot. It can be `string`, `date`, `number`, or `money`
* `values` : A list of dictionaries, one for each instance of the slot extracted form the user query.
* `type` : The type of the data in the slot. The possible values `string`, `date`, `number`, or `money`.

### Explanation of `values` dictionary:

### Explanation of `candidate` dictionary:
* `tokens` : The original tokens that were extracted from the user query.
* `resolved` : Whether an extracted token has already been resolved. Slots extracted from a user's query for the first time will be sent with a `"resolved": -1`. There are three possible values that can be returned: `-1` for unresolved, `0` for unsure, and `1` for already resolved. These will be explained in more detail in the next section.

* `tokens` : The original tokens that were extracted from the user query
* `resolved` : Whether an extracted token has already been resolved. There are three possible values for this: `-1` for unresolved, `0` for unsure, and `1` for already resolved. These will be explained below in the next section
A response back to the platform should look similar to the following example:

A response back to Clinc should look similar to the following example:

```
HTTP/1.1 200 OK
{
"lat": 42.2730207,
"qid": "6d090a7e-ba91-4b49-b9d5-441f179ccbbe",
"lon": -83.7517747,
"classifier_state": "transfer"
"dialog": "lore36ho5l4pi9mh2avwgqmu5mv6rpxz/98FJ",
"device": "web",
"query": "I want to transfer $400 from John's checking account to my credit card account.
"time_offset": 300,
"state": "clean_hello_start"
"state": "transfer_confirm"
"slots": {
"_ACCOUNT_FROM_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "John's checking account",
"resolved": 1,
Expand All @@ -127,8 +133,7 @@ HTTP/1.1 200 OK
},
"_ACCOUNT_TO_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "credit card",
"resolved": 1,
Expand All @@ -141,8 +146,7 @@ HTTP/1.1 200 OK
},
"_TRANSFER_AMOUNT_": {
"type": "money",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "$400",
"resolved": 1,
Expand All @@ -155,10 +159,10 @@ HTTP/1.1 200 OK
}
```

### Explanation of new `candidate` keys:
### Explanation of `values` keys:

* `value` : This is the new value you would like to pass back to the AI
* Every other key besides `tokens`, `resolved`, and `value` can be used to pass arbitrary parameters back to the AI. In the example we just shown, currency was set by the business logic.
* `value` : [required] This is the new value the user would like to pass from the business logic back to the platform.
* Besides `tokens`, `resolved` and `value`, arbitrary key-value pairs can be added to the dictionary by the business logic, to pass more information to the platform. In the example shown, currency was set by the business logic.

### Examples of `resolved` statuses in `slot` responses:

Expand All @@ -168,8 +172,7 @@ If the slot is valid and you want to keep it, set `"resolved": 1`, and return it
"slots": {
"_ACCOUNT_FROM_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "John's checking account",
"resolved": 1,
Expand All @@ -183,37 +186,52 @@ If the slot is valid and you want to keep it, set `"resolved": 1`, and return it
}
```

If there are multiple possible values, and you would like the AI to try to determine which is the best match, you can send a `"resolved": 0`, along with an array of possible values for the `values` key:
If there are multiple possible values, and you would like the AI to try to determine which is the best match, you can send a `"resolved": 0`, along with a list of possible values inside of a `candidates` key, along with a slot mapping configuration in a `mappings` key, in the top level of the dictionary for that slot. This will perform a slot mapping on that slot to determine the best possible match in `candidates` for the value of the slot.

```
"slots": {
"_ACCOUNT_TO_": {
"required_matches": "EQ 1",
"type": "string",
"candidates": [
{
"value": "College Savings Account",
"account_id": "155243",
"balance": "4521.10",
"currency": "USD"
},
{
"value": "Sapphire Credit Card Account",
"account_id": "7725485",
"balance": "332.21",
"currency": "USD"
},
{
"value": "401K Account",
"account_id": "792311",
"balance": "12554.23",
"currency": "USD"
}
],
"mappings": [
{
"children": [
{
"threshold": 0.45,
"type": "phrase_embedder",
},
{
"type": "constant",
"value": "MAPPING NOT FOUND"
}
],
"type": "first_match"
}
],
"values": [
{
"type": "string",
"tokens": "credit card",
"resolved": 0,
"value": [
{
"value": "College Savings Account",
"account_id": "155243",
"balance": "4521.10",
"currency": "USD"
},
{
"value": "Sapphire Credit Card Account",
"account_id": "7725485",
"balance": "332.21",
"currency": "USD"
},
{
"value": "401K Account",
"account_id": "792311",
"balance": "12554.23",
"currency": "USD"
}
]
"resolved": 0
}
]
}
Expand All @@ -226,8 +244,7 @@ If an identified slot doesn't quite match, or is incorrect, a `"resolved": -1` w
"slots": {
"_ACCOUNT_TO_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "credit card",
"resolved": -1,
Expand All @@ -238,25 +255,25 @@ If an identified slot doesn't quite match, or is incorrect, a `"resolved": -1` w
}
```

Adding your own slots:
A user adding their own slots:

To add your own slots that can be used in the Jinja response templates, simply add a new key into the `slots` dictionary with a similar structure. An example with the added slot `TRANSFER_FEE` can be found below:
To add your own slots that can be used in the Jinja response templates, simply add a new key into the `slots` dictionary with a structure similar to the other slots. An example with the added slot `TRANSFER_FEE` can be found below:

```
HTTP/1.1 200 OK
{
"query": "I want to transfer $400 from John's checking account to my credit card account.
"lat": 42.2730207,
"qid": "6d090a7e-ba91-4b49-b9d5-441f179ccbbe",
"lon": -83.7517747,
"dialog": "lore36ho5l4pi9mh2avwgqmu5mv6rpxz/98FJ",
"device": "web",
"query": "I want to transfer $400 from John's checking account to my credit card account.
"time_offset": 300,
"dialog": "2F38jGAsDds9ijcxzvkj/98FJ",
"device": "LaunchPad",
"state": "transfer_confirm",
"state": "transfer_confirm"
"slots": {
"_ACCOUNT_FROM_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "John's checking account",
"resolved": 1,
Expand All @@ -269,8 +286,7 @@ HTTP/1.1 200 OK
}
"_ACCOUNT_TO_": {
"type": "string",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "credit card",
"resolved": 1,
Expand All @@ -283,8 +299,7 @@ HTTP/1.1 200 OK
},
"_TRANSFER_AMOUNT_": {
"type": "money",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "$400",
"resolved": 1,
Expand All @@ -295,8 +310,7 @@ HTTP/1.1 200 OK
},
"_TRANSFER_FEE_": {
"type": "money",
"required_matches": "EQ 1",
"candidates": [
"values": [
{
"tokens": "$5.00",
"resolved": 1,
Expand All @@ -309,11 +323,13 @@ HTTP/1.1 200 OK
}
```

Upon a successful response from a business logic server, the new set of variables will be directly passed into your response templates, allowing you to customize your responses with the new slots introduced in the business logic.

### Business Logic Transitions
Upon a successful response from a Business Logic server, the new set of variables will be directly passed into the user's response templates, allowing them to customize their responses with the new slots introduced in the Business Logic.

Business Logic Transitions
------------------------------

Business logic transitions can be made by overwriting the `state` key in the business logic payload. There must be an existing business logic transition between the state you were previously in, and the state you are trying to transition to. These transitions can be added/removed from competencies with the `Edit` button on a competency's main Spotlight page. A good way to check if your business logic transition exists between the states you expect it to is to look for it on the State Graph.
Business Logic transitions can be made by overwriting the `state` key in the Business Logic payload. There must be an existing Business Logic transition between the state the user was previously in, and the state to which they are trying to transition. These transitions can be configured via the state graph editor for the relevant competency.

# Adding your own business logic

Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ version: '2'

services:
web:
build: .
# build: .
image: business-logic
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
Expand Down
Loading