# Autocomplete Documentation
Auto-complete is a way to give suggestions to the users while typing their utterances in the textbox.
Developers are given flexibility to control the auto-complete pattern through the use of grammar/operators such as:
1. Annotations `@punctuate`, `@once`, `@limit`
2. Operational Flows
`() (grouping)`, `| (branch)`, `* (zero or more)`, `+ (one or more)`
3. Entiy binding, Generator Entity, Filter Entity
4. Further Specifications by suggestion comparator and custom placeholder(prompt)
5. Sub pattern from Parser object
## Flow Control Operator
### ```|```: branch
```|``` forces the user to select one of the options specified by the operator
i.e. one of the option has be selected from `(opt1 | opt2| opt3)`.
### ```()```:grouping
`()`creates a capturing group for the operators to operate on.
#### Example
Pattern 1: `Get data from (file name_A |file name_B )*`
User:` Get data from `
Suggestion: `file name_A`, `file name_B`
Pattern 2: `Get data from file (name_A |name_B )*`
User: `Get data from file`
Suggestions: `name_A`, `name_B`
|Get data from file (name_A \|name_B )* |Get data from (file name_A \|file name_B )*|
| -------- | -------- |
| <img src="https://i.imgur.com/BZjbHSg.gif" width=.4 height=.4>| <img src="https://i.imgur.com/kzHJqYS.gif" width=.4 height=.4>|
<!-- > 'Get the columns ( A| B | C | D )*'
> Need more than one character?
-->
### ```*``` (zero or more): match some part repetitively
```*``` allows users to select the suggestions multiple times.
Note: Next suggestions are shown along with the current suggestions even before the user had selected any option.
### `+` (one or more): match some part repetitively
```+``` is similar to `*` operator. Hoever, it forces users to select at least one options.
Note: Next suggestion will not be shown unless the user had selected at least one option.
#### Example with *
Pattern: `Get the columns ( (col_A)@punctuate | (col_B)@punctuate )* from the table`
User 1st Input: `Get the columns`
Suggestions: `col_A`, `col_B`, `from the table`
User 2nd Input: `Col_A`
Suggestions: `Col_A`, `Col_B`, `from the table`
#### Example with +
Pattern:```Get the columns ( (col_A)@punctuate | (col_B)@punctuate )+ from the table```
User 1st input: `Get the columns`
Suggestions: `col_A`, `col_B`
User 2nd input:`col_A`
Suggestions: `col_A`, `col_B`, `from the table`
| Get the columns ( (col_A)@punctuate \| (col_B)@punctuate ) from the table| Get the columns ( (col_A)@punctuate \| (col_B)@punctuate )* from the table|Get the columns ( (col_A)@punctuate \| (col_B)@punctuate )+ from the table|
| -------- | -------- | -------- |
| <img src="https://i.imgur.com/ZbYepsy.gif" width=.4 height=.4>| <img src="https://i.imgur.com/j0GYdWb.gif" width=.4 height=.4>|<img src="https://i.imgur.com/xWKzCTj.gif" width=.4 height=.4>
## Annotations
### ```@punctuate```
`@punctuate` splits the auto-complete patterns. It is used to make sure that the suggestion does not get too long.
#### Example with @punctuate
Pattern: Load data @punctuate from the file
User: ```Load ```
Suggestions: ```data```
#### Example without @punctuate
Pattern: Load data from the file
User: ```Load ```
Suggestion:```data from the file```
| Load data from the file <filepath> | Load data @punctuate from the file <filepath> |
| -------- | -------- |
|<img src="https://i.imgur.com/KUlU9Ca.gif" width=.4 height=.4>| <img src="https://i.imgur.com/US81BVt.gif" width=.4 height=.4>
### ```@once```
`@once` makes sure that the specified suggestion is shown once. This is usually used with `*` or `+`
#### Example with @once
Patten: ```Test data from ( (file) @once| (url) @once)*```
User: `Test data from file`
Suggestions: `url`
#### Example without @once
Patten: ```Test data from ( file| url )*```
User: `Test data from file`
Suggestions: `url`, `file`
|Test data from ( (file) \| (url) )* | Test data from ( (file) @once \| (url) @once)*|
| -------- | -------- |
| <img src="https://i.imgur.com/8P7qwEn.gif" width=.4 height=.4>| <img src="https://i.imgur.com/ZhfFjMt.gif" width=.4 height=.4>
### ```@limit(num)```
`@limit` limits the number of suggestions shown to the user.
#### Example without limit
Pattern: `Test data from (file | url | directory)`
User: `Test`
Suggestion: `data from file`, `data from url`,`data from directory`
#### Example with limit
Pattern: `Test data from (file | url | directory)@limit(1)`
User: `Test`
Suggestion: `data from file`
Note that when you limit the number of suggestions to be selected, what is shown to the user depend on the order of the options the developer specify in the pattern. i.e) 'file' is suggested to the user since it specified first in our pattern.
|Test data from (file \| url \| directory) | Test data from (file \| url \| directory)@limit(1)|
| -------- | -------- |
| <img src="https://i.imgur.com/b5pKSaY.gif" width=.4 height=.4>| <img src="https://i.imgur.com/WrqQ6Tc.gif" width=.4 height=.4>
## Generator Entity and Entity binding
### Entity binding and Generator Entity
Variable `ctx` keeps track of the state of the current context. It is also possible to bind the entity to the ctx for later reference within the same utterance. This is useful for creating the suggestions dynamically.
#### Steps
1. Specify which auto-complete entity to generate suggestions by adding an entity name within `<>`. e.g.`<filename>`
2. Add a binding dictionary which maps the entity name to the entity generator function.
e.g. `{'filename': file_generator}`
3. To bind an entity value which was selected by the user to ctx, add `":<binding_name>"` next to the entity. The value of this binded entity can be retrieved by `ctx.get(<binding_name>)`
```python=
"Get data from the (file|directory):file_type <filename>",
{
'filename': get_names
}
```
4. Create a custom generator function or import it.
`ctx` is given as an input for generator function. This contains the current context (i.e. what the user had selected for the binded entity). Generator function then returns the list of suggestions.
```python=
def get_names(ctx):
file_type = ctx.get('file_type')
if file_type == 'file':
return ["file_A", 'file_B']
else:
return ["dir_A", "dir_B "]
```
#### Example
In the example above, we dynamically filter the suggestions for the users depending on which options the user had chosen.
User: `Get data from file`
Suggestions: `file_A`, `file_B`
User: `Get data from directory`
Suggestions: `dir_A`, `dir_B`
|User: Get data from file| User: Get data from directory
|-------|-------
||
Common use cases of generator function is to create suggestions for column names or file names. These generator functions are already provided in the `common_generators/dataset_metadata.py` and `common_generators/file_names.py`.
## Filter
Filter function restricts the user from proceding to next auto complete suggestions if the specified condition is not met.
### Steps
1. Add `{<filter_name>}` just before the sub pattern which you would like to filter.
Then, specify the filter function within the binding dictionary
Auto complete pattern with binindg dictionary
```python=
'Test data from (file|directory):type {filter_file_type} to complete the utterance',
{
'filter_file_type': filter_file_type
}
```
2. Write a filter function/import filter function
Filter function specifies the condition which has to be met before proceeding to the next auto-complete sub pattern.
It takes ctx as an input and returns True or False.
Custom filter function
```python=
def filter_file_type(ctx):
type = ctx.get("type")
return type == 'file'
```
#### Example
The code above produce the following example.
A user is able to complete the auto-complete pattern only if 'file' is selected.
User: `Test data from file`
Suggestion: `to complete the utterance`
User:`Test data from directory`
Suggestion: None
|User: Test data from file| User: Test data from directory
|-------|-------
||
## Further Specifications
### `prompt_generator`
By default, prompt/placeholder is the label specified within the angle bracket.
e.g. `<'filename'>`
We can also create a placeholder both statically and dynamically by using the prompt generator function. Prompt generator function has to be sepecified in the binding dictionary with `prompt_generator` as the key.
### `suggestion_comparator`
The order of the suggestions can also be specified by the custom comparator function.
Comparator function has to be sepecified in the binding dictionary with `suggestion_comparator` as the key.
#### Example
This placeholder is dynamically created based on the user selection in the previous binded entity. The order of the suggestions is specified to be in reverse order (case insensitive.)
User:` Get data from file`
Placeholder: `Please enter file name`
User: Get data `from directory`
Placeholder: ```please enter directory name```
*Auto Complete Pattern*
```python=
'Get data from the (file|directory):type <filename>',
{
'filename': {
'suggestion_generator': get_file_names,
'prompt_generator': prompt_generator,
'suggestion_comparator': lambda x, y: 1 if x.lower() < y.lower() else -1
}
}
```
*Custom prompt generator*
```python=
def prompt_generator(ctx):
return "Please enter " + ctx.get('type') + ' name'
```
|User: Get data from file| User: Get data from directory
|-------|-------
||
## Specifying Sub-pattern from Parser
Entity can correspond to not only function but also Parser. It is common to implement auto-complete pattern within Pattern object. However, it is also possible to create sub pattern within Parser.
See that example 1 and example 2 produce the same result.
#### Example 1
*Auto-complete Pattern*
```python=
autocomplete_pattern=[
'Get data from the (file|directory):type <filepath>',
{'filepath': get_file_names}
]
```
#### Example 2
*Auto-Complete Pattern*
```python=
entities={
'filepath': EndOfUtteranceEntity(
FileNameParser(),
"Where is the source file located?"
)},
autocomplete_pattern=[
'Get data from the (file|directory):type <filepath>'
]
```
*FileName Parser Class*
```python=
class FileNameParser(GreedyParser):
def _generate_autocomplete_pattern(self):
return AutoCompletePattern.create_from([
'<filepath>',
{'filepath': get_file_names}
])
```
## If autocomplete entity is missing, borrow from
```python=
pattern = Pattern(
'LOAD data from the file <data>',
addnl_ignore=['data', 'dataset'],
entities={
'data': EndOfUtteranceEntity(
FileParser(trunc_whitespace=True),
"What URL contains the data file that you want to load?"),
},
autocomplete_pattern=["Load data from the URL <data>"]
)
```
In such case, ```<data>``` directly binds to the sub-pattern of ```FileParser(trunc_whitespace=True)```.