Skip to content

Commit

Permalink
feat(nlu): added case sensitivity for entities
Browse files Browse the repository at this point in the history
  • Loading branch information
EFF committed Nov 11, 2019
1 parent 54fd13f commit 409acf3
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 15 deletions.
2 changes: 1 addition & 1 deletion modules/nlu/src/backend/engine2/engine2.ts
Expand Up @@ -57,7 +57,7 @@ export default class E2 implements Engine2 {
name: ent.name,
pattern: ent.pattern,
examples: [], // TODO add this to entityDef
ignoreCase: true, // TODO add this entityDef
matchCase: ent.matchCase,
sensitive: ent.sensitive
}))

Expand Down
2 changes: 1 addition & 1 deletion modules/nlu/src/backend/engine2/entity-extractor.ts
Expand Up @@ -174,7 +174,7 @@ export const extractPatternEntities = (
const input = utterance.toString()
// taken from pattern_extractor
return _.flatMap(pattern_entities, ent => {
const regex = new RegExp(ent.pattern!, 'i')
const regex = new RegExp(ent.pattern!, ent.matchCase ? '' : 'i')

return extractPattern(input, regex, []).map(res => ({
confidence: 1,
Expand Down
2 changes: 1 addition & 1 deletion modules/nlu/src/backend/typings.ts
Expand Up @@ -170,7 +170,7 @@ export type PatternEntity = Readonly<{
name: string
pattern: string
examples: string[]
ignoreCase: boolean
matchCase: boolean
sensitive: boolean
}>

Expand Down
1 change: 1 addition & 0 deletions modules/nlu/src/backend/validation.ts
Expand Up @@ -38,6 +38,7 @@ export const EntityDefCreateSchema = Joi.object().keys({
.valid(['system', 'pattern', 'list'])
.required(),
sensitive: Joi.boolean(),
matchCase: Joi.boolean(),
occurences: Joi.array()
.items(EntityDefOccurenceSchema)
.default([]),
Expand Down
15 changes: 3 additions & 12 deletions modules/nlu/src/views/full/entities/EntityEditor.jsx
@@ -1,9 +1,10 @@
import React from 'react'
import style from './style.scss'
import { ListGroupItem, Glyphicon, Label, FormControl, OverlayTrigger, Tooltip } from 'react-bootstrap'
import { ListGroupItem, Glyphicon, OverlayTrigger, Tooltip } from 'react-bootstrap'
import _ from 'lodash'
import { WithContext as ReactTags } from 'react-tag-input'
import classNames from 'classnames'
import { PatternEntityEditor } from './PatternEntity'

const DEFAULT_STATE = {
currentOccurence: undefined,
Expand Down Expand Up @@ -230,17 +231,7 @@ export default class EntityEditor extends React.Component {
</div>
{currentEntity && currentEntity.type === 'list' && this.renderOccurences()}
{currentEntity && currentEntity.type === 'pattern' && (
<div>
<FormControl
tabIndex="1"
autoFocus
type="text"
placeholder="Enter a valid pattern. Try: howdy[0-9]+"
value={this.state.pattern}
onChange={this.handlePatternChange}
/>
{!this.isPatternValid(this.state.pattern) && <Label bsStyle="danger">pattern invalid</Label>}
</div>
<PatternEntityEditor entity={currentEntity} updateEntity={_.debounce(this.props.onUpdate, 2500)} />
)}
</div>
)
Expand Down
Empty file.
103 changes: 103 additions & 0 deletions modules/nlu/src/views/full/entities/PatternEntity.tsx
@@ -0,0 +1,103 @@
import { Checkbox, FormGroup, H1, Icon, InputGroup, Position, Tag, TextArea, Tooltip } from '@blueprintjs/core'
import { NLU } from 'botpress/sdk'
import React, { useEffect, useState } from 'react'

import style from './style.scss'

interface Props {
entity: NLU.EntityDefinition
updateEntity: (entity: NLU.EntityDefinition) => void // promise ?
}

export const PatternEntityEditor: React.FC<Props> = props => {
const [matchCase, setMatchCase] = useState<boolean>(false)
const [sensitive, setSensitive] = useState<boolean>(props.entity.sensitive)
const [pattern, setPattern] = useState<string>(props.entity.pattern)
const [isValidPattern, setIsValidPattern] = useState<boolean>(true)

useEffect(() => {
try {
const re = new RegExp(pattern, matchCase ? '' : 'i')
setIsValidPattern(true)
const newEntity: NLU.EntityDefinition = {
...props.entity,
pattern,
sensitive,
matchCase
}
props.updateEntity(newEntity)
// TODO try to match on every examples with created pattern, don't forget exact start and exact end logic
} catch (e) {
setIsValidPattern(false)
}
}, [pattern, matchCase, sensitive]) // TODO add examples in watchers or maybe create a 2nd handler

return (
<div>
<H1>{props.entity.name}</H1>
<div className={style.entityEditorBody}>
<div className={style.dataPane}>
<FormGroup
label="Regular expression"
labelFor="pattern"
labelInfo={
isValidPattern ? null : (
<Tag intent="danger" minimal style={{ float: 'right' }}>
pattern invalid
</Tag>
)
}
>
<InputGroup
leftIcon={<Icon iconSize={20} className={style.regexInputDash} icon="slash" />}
rightElement={<Icon iconSize={20} className={style.regexInputDash} icon="slash" />}
type="text"
id="pattern"
placeholder="insert a valid pattern"
value={pattern}
intent={isValidPattern ? 'none' : 'danger'}
onChange={e => setPattern(e.target.value)}
/>
</FormGroup>
<FormGroup label="Matching examples" labelFor="examples">
<TextArea
id="examples"
fill
rows={6}
growVertically={true}
placeholder="Add examples that matchs your pattern. One by line."
/>
</FormGroup>
</div>
<div className={style.configPane}>
<Checkbox
checked={matchCase}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setMatchCase(e.target.checked)}
>
<span>Match case</span>&nbsp;
<Tooltip
content="Is your pattern case sensitive"
position={Position.RIGHT}
popoverClassName={style.configPopover}
>
<Icon icon="help" />
</Tooltip>
</Checkbox>
<Checkbox
checked={sensitive}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSensitive(e.target.checked)}
>
<span>Contains sensitive data</span>&nbsp;
<Tooltip
content="Sensitive information are replaced by * before being saved in the database"
position={Position.RIGHT}
popoverClassName={style.configPopover}
>
<Icon icon="help" />
</Tooltip>
</Checkbox>
</div>
</div>
</div>
)
}
26 changes: 26 additions & 0 deletions modules/nlu/src/views/full/entities/style.scss
Expand Up @@ -141,3 +141,29 @@
margin-left: 5px;
cursor: pointer;
}

.entityEditorBody {
display: flex;
& > div {
padding: 20px;
}
.dataPane {
flex-grow: 1;
}
.regexInputDash {
height: 30px;
display: flex;
align-items: center;
color: #e1e8ed !important; //to make sure intent doesn't override this
margin: 0;
padding: 0 10px;
}
.configPane {
width: 40%;
background-color: #fbfbfb;
}
}

.configPopover {
max-width: 250px;
}
5 changes: 5 additions & 0 deletions modules/nlu/src/views/full/entities/style.scss.d.ts
Expand Up @@ -2,14 +2,19 @@
// Please do not change this file!
interface CssExports {
'badge': string;
'configPane': string;
'configPopover': string;
'container': string;
'dataPane': string;
'deleteEntity': string;
'entity': string;
'entityEditorBody': string;
'header': string;
'occurence': string;
'occurenceDelete': string;
'occurenceInput': string;
'occurenceName': string;
'regexInputDash': string;
'removeSynonym': string;
'selectedentity': string;
}
Expand Down
1 change: 1 addition & 0 deletions src/bp/sdk/botpress.d.ts
Expand Up @@ -384,6 +384,7 @@ declare module 'botpress/sdk' {
name: string
type: EntityType
sensitive?: boolean
matchCase?: boolean
fuzzy?: boolean
occurences?: EntityDefOccurence[]
pattern?: string
Expand Down

0 comments on commit 409acf3

Please sign in to comment.