A skill is a set of intents. One text file represents one skill, it may contain several intents which all belong together. All the skills are stored in Susi Skill Data repository and the schema is Models -> Groups -> Languages -> Skill -> Intents. Using this, one can access any skill based on four tuples parameters model, group, language, skill. Susi skill CMS is an editor to write and edit skill easily. It follows an API-centric approach where the Susi server acts as API server and a web front-end act as the client for the API and provides the user interface.
::name <Skill_name> ::author <author_name> ::author_url <author_url> ::description <description> ::dynamic_content <Yes/No> ::developer_privacy_policy <link> ::image <image_url> ::terms_of_use <link> #Intent User query1|query2|quer3.... !example:<The question that should be shown in public skill displays> !expect:<The answer expected for the above example> Answer for the user query
To give more information of a Skill above metadata was added to the text file. Where dynamic content, represents if the skill answer changes based on user inputs. And image is the path to image of the skill, stored in skill data repository. Let’s check how this is implemented in Susi Server.
public static JSONObject readEzDSkill(BufferedReader br) throws JSONException { if (line.startsWith("::")) { int thenpos=-1; if (line.startsWith("::name") && (thenpos = line.indexOf(' ')) > 0) { skillName = line.substring(thenpos + 1).trim(); if(skillName.length() > 0) json.put("skill_name",skillName); } if (line.startsWith("::author") && (thenpos = line.indexOf(' ')) > 0) { authorName = line.substring(thenpos + 1).trim(); if(authorName.length() > 0) json.put("author",authorName); } if (line.startsWith("::author_url") && (thenpos = line.indexOf(' ')) > 0) { authorURL = line.substring(thenpos + 1).trim(); if(authorURL.length() > 0) json.put("author_url",authorURL); } lastLine = ""; example = ""; expect = ""; description = ""; image = ""; continue readloop; }
Susi Skill class provides parser methods for sets of intents, given as text files. It reads the skill line by line. For differentiating skill metadata with skill code we have use (::) operator. If a line starts with ::, method knows it’s skill metadata, and process it respectively. It takes out the respective substring and puts in json to be later processed by SusiMind class.
private final Map<String, String> skillNames; private final Map<String, String> authors; private final Map<String, String> authorsUrl; private final Map<String, String> devloperPrivacyPolicies; private final Map<String, String> termsOfUse; private final Map<String,Boolean> dynamicContent; if(json.has("description")) this.skillDescriptions.put(intent.getSkill(), json.getString("description")); // skill image if(json.has("image")) this.skillImage.put(intent.getSkill(), json.getString("image")); // adding skill meta data if(json.has("skill_name")) this.skillNames.put(intent.getSkill(), json.getString("skill_name")); if(json.has("author")) this.authors.put(intent.getSkill(), json.getString("author"));
The SusiMind class process this json and stores the metadata in a map of skill path and data.This map is used by GetSkillMetadataService class to to list the skill metadata for all the skills given its model, group and language and skill. For adding the servlet we need to inherit the service class from AbstractAPIHandler and implement APIhandler interface.In Susi Server an abstract class AbstractAPIHandler extending HttpServelets and implementing API handler interface is provided.
@Override public String getAPIPath() { return "/cms/getSkillMetadata.json"; }
The getAPIPath() methods sets the API endpoint path, it gets appended to base path which is 127.0.0.1:4000/cms/getSkillMetadata.json for local host. The getMinimalBaseRole method tells the minimum Userrole required to access this servlet it can also be ADMIN, USER. In our case it is Anonymous. A User need not to log in to access this endpoint.
In Serviceimpl method,
for (Map.Entry<String, String> entry : DAO.susi.getSkillDescriptions().entrySet()) { String path = entry.getKey(); if ((path.indexOf("/" + model + "/") > 0) && (path.indexOf("/" + group + "/") > 0) && (path.indexOf("/" + language + "/") > 0) && (path.indexOf("/" + skill + ".txt") > 0)) { skillMetadata.put("descriptions", entry.getValue()); } } JSONObject json = new JSONObject(true); json.put("skill_metadata", skillMetadata); json.put("accepted", true); json.put("message", "Success: Fetched Skill's Metadata"); return new ServiceResponse(json);
We can get the required parameters through call.get() method where first parameter is the key for which we want to get the value and second parameter is the default value. If the path contains the desired language, group and model and skill, we return it as a response containing the respective field. The endpoint can be tested http://127.0.0.1:4000/cms/getSkillMetadata.json?group=general&model=entertainment&language=en&skill=cat and you will get the following response.
This is how getSKillMetadata service works. To add the metadata to the skill visit susi_skill_data, the storage place for susi skills. For more information and complete code take a look at Susi server and join gitter chat channel for discussions.
Resources
- Read more about Servets – https://www.tutorialspoint.com/servlets/
- The source code –https://github.com/fossasia/susi_server/blob/development/src/ai/susi/server/api/cms/
- Read about servlet interface – https://www.javatpoint.com/Servlet-interface