google-actions-server
google-actions-server copied to clipboard
A Node.js server for your Google Actions
GAS: Google Assistant Server
A Node.js server for your Google Assistant (and Google Home).
![](https://cdn-images-1.medium.com/max/2000/1*51-QcjdjlRiy4_ya2NjA2g.png)
Get it from NPM
npm i -S @manekinekko/google-actions-server
Get it from Yarn
$ yarn add @manekinekko/google-actions-server
How to use it
See the GAS Starter for more details.
GAS API
Here is the simplest guide in order to use GAS:
import { ActionServer } from '@manekinekko/google-actions-server';
const agent = new ActionServer();
agent.welcome((assistant) => {
agent.ask('Welcome Home. How can I help');
});
agent.intent(ActionServer.intent.action.TEXT, (assistant) => {
// reads the user's request
const userInput = assistant.getRawInput();
})
// start listening for commands (on port 8080)
agent.listen();
Intents
Available intents are:
ActionServer.intent.action.MAIN
This intent is triggered when users invoke your action by name, such as "talk to <YOUR ACTION NAME HERE>". This intent si required for every action package.
ActionServer.intent.action.TEXT
This intent is triggered when users speak input and you receive the input as a request to your fulfillment endpoint.
ActionServer.intent.action.PERMISSION
Triggered if Google Assistant needs to ask the user for more permissions (not implemented yet by GAS)
ActionServer
ActionServer(port = 8080)
Create an HTTP server and set it to listen on port port
(default: 8080).
Agent
Calling new ActionServer()
will return an Agent
instance, which exposes the following API:
agent.intent(name, callback)
Register a callback
with an intent of type ActionServer.intent.action.*
. When invoked, the callback
function receives an instance of ActionsSdkAssistant. For instance:
agent.welcome(ActionServer.intent.action.TEXT, (assistant) => {
// assistant
});
agent.welcome(callback)
Register a callback
with the ActionServer.intent.action.MAIN intent. This is the same as:
agent.intent(ActionServer.intent.action.MAIN, (assistant) => {
// assistant
});
Register a callback
with the ActionServer.intent.action.MAIN intent. This is the same as:
agent.listen()
Starts the GAS server on port 8080
(the default port). This method must be called after you have registered all of your intents.
agent.ask(message)
A convenient method that abstracts away the assistant.ask()
configuration. Typically, with assistant.ask()
you have to:
const inputPrompt = assistant.buildInputPrompt(isSsml, message, noInputs);
assistant.data = previousState;
assistant.ask(inputPrompt);
With agent.ask()
, you can just pass it the message:
agent.ask(message);
Of course, you can still call assistant.ask()
if you want to provide a configuration.
setGreetings(greetings)
A convenient method to set a list of greeting messages that you will play randomly to the user.
getRandomGreeting()
A convenient method to get a random greeting message set using agent.setGreetings()
.
randomGreeting()
A convenient method that will trigger a random greeting message for you.
setConversationMessages(conversationMessages)
A convenient method to set a list of random conversations asking the user for another query. For instant: How can I help?
or Do you have another request?
.
getRandomConversationMessage()
A convenient method to get a random conversation message set using agent.setConversationMessages()
.
agent.train(dataSetKey, data, fields = ['data']))
This method is used to provide a set of data that will be used by agent.matchUserRequest()
. This could be the data that will be used by the assistant to interact with the user, or a set of Hot Words such as:
this.agent.train('hot_words', [
'what time is it?',
'tell me the time',
`what's the time`,
//...
]);
Here is another use case, let's say you want to provide a decision list:
const decisionList = [
{
'scenario': 'I have one existing Observable, and I want to change each emitted value to be a constant value',
'operator': 'mapTo'
},
{
'scenario': 'I have one existing Observable, and I want to change each emitted value to be a value calculated through a formula',
'operator': 'map'
},
...
];
You would then provide it to GAS like so:
const fields = ['operator', 'scenario'];
this.agent.train('decision_list', decisionList, fields);
Please note that the fields
option has been provided since the items inside this decision list are stored in key/value pairs.
IMPORTANT: the first field (in the sample above: operator
) will be used as the reference field: the field that will be returned by agent.matchUserRequest()
.
matchUserRequest(dataSetKey, rawInput, responseCallback, lookupOptions = {})
NOTE: GAS uses elasticlunr that performs the Full-Text Search technique to retrieve the matched documents.
Use this method to match the user's input with a set of data provided in agent.train()
.
For instance, let's say you have the decisionList
list from the example above; in order to find a matched document you would call agent.matchUserRequest()
like so:
// get the user's input
const rawInput = assistant.getRawInput();
// provide a lookup configuration (see below)
const lookupOptions = {...};
// the callback that will be called
const responseCallback = (foundDocuments, rawInput) => { ... };
// run the search operation
const matchedDocuments = this.agent.matchUserRequest('decision_list', rawInput, responseCallback, lookupOptions);
The matchedDocuments
would then contain the matched documents based on the rawInput
string. In some case you may get false-positives, documents that are not relevant to the intended search question.
In this case, you may provide a lookupOptions
object in order to configure/tweak the search operation.
NOTE: if no documents are found, an empty array is returned.
threshold
You can provide the threshold
property to filter out the false-positives. threshold
can be either a Number or a Function.
Using a number:
const lookupOptions = {
threshold: 0.6
};
When using a function, it will be provided with the current entry from the data set. You can access the score
property on that entry:
const lookupOptions = {
threshold: entry => {
return entry.score > 0.6;
}
};
fields
The fields property is a elasticlunr configuration query. For instance, we could provide the following configuration for the example from above:
const lookupOptions = {
fields: {
scenario: {
boost: 2,
bool: 'AND',
expand: true
},
operator: {
boost: 1
}
}
};
See elasticlunr configuration query for more details.
fetch(url, responseCallback, useCache = true)
A convenient method to fetch a remote document. Useful if you want to get more information from a remote website. For instance:
agent.fetch(url, (error, content) => {
if (error) {
console.error(error);
}
else {
console.log(content);
}
});
Disclaimer
The current implementation is still a POC. It's obviously missing lots of features. Please open issues to discuss any feature you want to be added, submit suggestions, or anything else... All contributions are welcome ;)