The current common storage is a bad architecture choice (possible bugs in time-delayed transactions, in a multiuser scenario). It must be replaced asap, storing/retrieving data in/from sessions db.
A special warning concerns the synchronous/asynchronous behaviors of nodejs. Currently input and output state handlers are usual synchronous javascript functions. That's debatable.
⚠️ WARNING when NaifJs run as a server in a multi user channel, in case of delayed/promised/timeout functions (anything that will run out-of-time in a future (~promise), please remember to pass the session id to functions that will be activated with a time delay.
Currently the sessions are managed as in-memory key-value hash table (a javascript object), read from disk (a JSON file) at up time and saved to as JSON file at down time.
A better choice is to manage sessions with a real database (e.g. using REDIS, or LMDB, or any other key-value DB). Decoupling DB also allows to access sessions from multiple instances of a Naif (to do) web server.
NaifJs could supply a ready-made default response timeout handler, by example, asking every M seconds the last prompt P.
So far, timeout handlers are managed in a dedicated in-memory object. It's a debatable decision. Maybe would be part of the session object.
naif shell
command line program could be enabled by inline commands for debug purposes, maybe
- using a special prefix e.g.
/command
:command
, - On
return
keystroke (possible on CLI, not possible on Telegram)
to show, by example, these info:
- stateid
- the dialog flow stateids stack [state1 -> state2-> state3 -> etc.]
- dialog unit variables
- all session data
Similar improvements could be available for naif telegram
The idea is that each input and output nodes could be queried (for debugging / reporting purposes).
In terms of javascript, it means just adding attributes to a state function handler:
// someDialogUnit.js
function someInputState() { ... }
function someOutputState() { ... }
someInputState.type = 'input'
someInputState.description = 'bla bla bla...'
someOutputState.type = 'output'
someOutputState.description = 'blablabla blabla bla...'
Introspection "metadata" could be generated by a naif generate
JSON input configuration.
Think about how generate (in real-time) a graphic representation of the state machine path flow.
It could be useful to generate state machine code, starting from a graphical representation of a state machine.
How to create a dialogue javascript source code from a JSON file or better, a text script with a special indentation and meta-tags (like the .script). And viceversa.
By example: task completion, see promemoria, slot-filling, see conosciamoci, etc.
NaifJs is independent by any natural or artificial language. The dialog manager basically processes input texts and generate output texts or other media contents.
User sentences understanding (input text) is demanded to the pattern matching component (by default a regexp match). On the other hand any output text is hard-coded in the states logic.
A common case is to manage just a single language at a time. To have the same dialog in multiple languages, currently you have to duplicate code.
To give you an example of this duplication, in the examples directory, the original story_it demo application, in Italian language, has been duplicated and "localized" in English language, generating story_en equivalent.
To maintain the same unique code base, avoiding any duplication, one idea is to have a configuration file (a JSON file for each dialog-unit), containing patterns and literals:
// pseudocode
const PATTERNS = {
'HELLO': {
'it': /ciao|buongiorno|buonasera|buon pomeriggio|olà|salve/i
'en': /hi|hello|good morning|good afternoon|greetings|hey|hallo|hallo|ciao/i
// ...
},
'MY_NAME': {
'it': /^(mi chiamo |chiamami |sono |il mio nome è )?(?<firstName>[A-Z][a-z]{1,}(\\s[A-Z][a-z]{1,})*)/i
'en': /^(my name is |you can name me |I\'m )?(?<firstName>[A-Z][a-z]{1,}(\\s[A-Z][a-z]{1,})*)/i
// ...
},
// ...
}
const LITERALS = {
'HELLO': {
'it': 'Ciao!',
'en': 'Hello!',
'fr': 'Salut!',
'de': 'Hallo!',
// ...
},
'HOW_ARE_YOU': {
'it': 'Come và?',
'en': 'How are you?',
'fr': 'Comment ca va?',
// ...
},
// ...
}
const DEFAULT_LANGUAGE = 'it'
function say(ref, language=DEFALT_LANGUAGE) {
console.log(LITERALS[ref][language])
}
function pattern(ref, language=DEFALT_LANGUAGE) {
console.log(PATTERNS[ref][language])
}
// ... at run-time:
say('HELLO') // -> 'Ciao!'
pattern('HELLO') // -> /ciao|buongiorno|buonasera|buon pomeriggio|olà|salve/i
Implementation must be rethought. It could be supplied a JSON configuration reader, where rules (regexp patterns) and actions (functions to be activate in case of a pattern match) could be in a configuration file.
See: matching high number of different sentences (using regexp patterns parsing)
dialog-logs formatted by lib/log.js must be configurable.
New feature: the idea is to wrap NaifJs engine behind a HTTP/TCP server.
Session file must be substituted with a in-memory storage?
Universals are commands that are always available in any state of the application. Common universals (James Giangola, from book "Voice user interface design", pag. 72):
- For end-user:
- help
- repeat
- main-menu / start-over
- go back
- operator
- goodbye
- For developer/tester
- status
- vars
Currently dialog unit developer could implement some of these commands, programming them on each input state, explicitly.
The go back, for example, could be implemented explicitly with a inserting a next API
case ( match(/go back|.../) )
next(previousState)
break
To automatize the command, avoiding explicit programming, it need a stack of call flow states
It requires to store each response to the sessions DB.
This is tricky because the repeat request refers to ALL the last response,
maybe composed by multiple response
s...
- global timeout for the user session
- firstTime()
- lastTime()