This is a simple program that retrieves the information from an explanation graph and uses RosaeNLG and Pug templates to generate text.
Install NodeJs
Clone the repository and install dependecies
git clone https://github.com/radu1690/Explanations.git
npm install
You can run the program with:
node explanations.js <template> <graph>
Template is the location of the pug template while graph is a graph in csv format (with "\t" as delimiter). Example:
node explanations.js templates/english/argument.pug graphs/exp_graph_1_en.csv
You can specify the language, English or Italian (the default is English), like in the following example:
node explanations.js templates/italian/feedback.pug graphs/exp_graph_1_it.csv italian
You can generate a visual reppresentation of a graph with Graphviz.
Install requirements:
!apt-get install graphviz graphviz-dev
!pip install pygraphviz
The graph must be in a csv file with \t
delimiter.
Run with:
python graphviz.py <graph>
Example:
!python graphviz.py graphs/exp_graph_1_en.csv
will generate a pdf file named exp_graph_1_en.pdf with the reppresentation of the graph.
The graphs are stored in csv file (with \t delimiter) where each row contains a triple in the form of "subject - predicate - object": subject is the parent node, object is the child node and predicate is the arc label.
In every graph the following must be true:
- the subject of the first row is the head node of the graph
- the graph does not contain cycles
- a child node has only one parent node
For all the features in Pug templates you can check the Pug main website.
A complete tutorial with advanced features of RosaeNLG can be found here.
To insert some plain text you can use the pipe character (|
) followed by the text you want to write:
|Hello world!
will output: Hello world!
Spaces between different plain texts (except only punctuation) are automatically inserted, so:
|Hello
|world
|!
will still output: Hello world!
The object passed to RosaeNLG (after the graph has been processed) is an explanation.
To print a field, you write #[+value(explanation.field)]
or !{explanation.field}
. For example, the value of explanation.entity.enLabel is "red meat":
|You ate #[+value(explanation.entity.enLabel)].
will output: You ate red meat.
#[+value(explanation.field)]
will throw an error if the field is undefined while !{explanation.field}
will print an empty string.
If-else statements are used like in the following example where entity.enLabel=meat and constraint=less:
if explanation.constraint == 'less'
|You ate too much,
|enough
else
|You did not eat enough,
|more
|#[+value(explanation.entity.enLabel)]!
will output: You ate too much, enough meat!
Note that to use an explanation field in an if-else statement you must not use the #[+value()]
or the !{}
notation.
You can write javascript code in a template by starting the line with the "-
" character,for example here i declare two variables and then I use them in the template:
- let nutrient = "cheese"
- let food = "pie"
|the !{food} contains a lot of !{nutrient}
This will output The pie contains a lot of cheese
You can do loop with the eachz
operator from RosaeNLG:
-let data = ["fruits", "vegetables", "meat"]
eachz element in data
|!{data}
will output: fruits vegetables meat
The eachz
operator can accept some parameters which are useful in Natural Language Generation. Example:
-let data = ["fruits", "vegetables", "meat"]
|I bought
eachz element in data with {separator: ",", last_separator: "and", end: "."}
|!{element}
will output: I bought fruits, vegetables and meat.
You can use javascript functions directly in templates. You can either use libraries or create you own functions.
We added Pluralize and Random functions.
Pluralize is a library which can pluralize and singularize any given word. Use pluralize(<word>)
or pluralize.singular(<word>)
in a template to either pluralize or singularize a word. Use pluralize.isSingular()
and pluralize.isPlural()
to check if a word is either singular or plural. Example:
if pluralize.isSingular(explanation.entity)
|contains
else
|contain
This will output contains
if the entity field is singular or contain
if the entity field is plural.
Random is a custom function which returns a random element of an array (if the argument is an array) or the argument if it is not an array.
- let nutrient = random(explanation.entity.negative)
- let consequence = random(nutrient.cons_en)
Here is the example of how I added the Random function.
First you declare your function in explanations.js:
function randomElement(items){
if(Array.isArray(items)){
return items[Math.floor(Math.random()*items.length)]
}else{
return items
}
}
Then you pass it to RosaeNLG in graph2Object.main function (again in Explanations.js):
graph2Object.main(dir_explanationGraph)
.then(data =>{
var output = rosaenlgPug.renderFile(dir_template, {
language: rosae_language,
explanation: data,
pluralize: pluralize, //pluralize function
random: randomElement //random function
});
console.log(output)
})
Now you can call the function from your pug template:
- let nutrient = random(explanation.entity.negative)