Skills are basically a set of rules which respond to the user’s queries through any client app. All the skills are defined in the SUSI Skill Data repo where the user’s queries are matched with the already present skills and the server responds accordingly. Apps like Alexa, Google Assistant have an interface to view skills with a set of sample queries that can be used therefore, we are adding the same skill display UI in the SUSI iOS app.
Implementation
All the skills are arranged into categories or groups, so we first need to fetch all those groups followed by fetching skills from each group. For listing all the groups, we use the endpoint below:
http://api.susi.ai/cms/getGroups.json
Which returns all the groups in the groups object like below:
{ "session": {"identity": { "type": "host", "name": "67.214.191.117", "anonymous": true }}, "accepted": true, "groups": [ "Social", "News", "Food and Drink", "Travel and Transportation", "Connected Car", "Movies and TV", "Problem Solving", "Knowledge", "Business and Finance", "Productivity", "Games, Trivia and Accessories", "Lifestyle", "Health and Fitness", "Music and Audio", "Shopping", "Communication", "Novelty and Humour", "Utilities", "Sports", "Weather" ], "message": "Success: Fetched group list" }
After the groups have been fetched, we need to get the skills for each group. Here, we use the endpoint below:
http://api.susi.ai/cms/getSkillList.json?group=GROUP_NAME
Since, we have a number of groups, we need to make the above API call as many times as the group count is. A sample call would look like:
http://api.susi.ai/cms/getSkillList.json?group=News
which would fetch all the skills in the News group.
{ "accepted": true, "model": "general", "group": "News", "language": "en", "skills": {"news": { "image": "images/news.png", "author_url": "https://github.com/AliAyub007", "examples": [ "News", "latest news", "most viewed articles in science today", "most viewed articles in science in the last week", "most viewed articles in science in the last month", "most shared articles in science today", "can you tell me last week's most shared articles in science", "do you know most shared articles in arts in the last month", "most emailed articles today in arts", "most emailed articles in science in the last week", "can you tell me most emailed articles in science in the last month", "articles in science", "show me articles", "most emailed articles", "most shared articles", "tell me news in tech world" ], "developer_privacy_policy": null, "author": "Ali Ayub Khan", "skill_name": "NEWS", "dynamic_content": true, "terms_of_use": null, "descriptions": "A skill to give news.", "skill_rating": null }}, "message": "Success: Fetched skill list", "session": {"identity": { "type": "host", "name": "23.94.137.239", "anonymous": true }} }
Each such json object gives us the following values:
- Model
- Group
- Language
- Image Path
- Author’s URL
- Author’s Name
- A list of sample queries
- Skill Name
- Licence and terms of use
- Rating
- Description
Implementation in SUSI iOS
The UI for listing skills is a little complex as it consists of a UITableView where each UITableViewCell consists of a UILabel(group name) and a UICollectionVIew (horizontal scroll).
Let’s see the step by step process to implement the skill listing.
- First, we need to fetch all the groups available using the endpoint above.
// get all groups func getAllGroups() { Client.sharedInstance.getAllGroups { (groups, success, message) in DispatchQueue.main.async { if success { self.groups = groups self.tableView.reloadData() } else { print(message ?? "error") } } } }
- After the response from the above call is obtained, the groups object containing all the groups is returned to the controller which the group name to set the UILabel.
var groupName: String? { didSet { backgroundColor = Color.grey.lighten3 groupNameLabel.text = groupName } }
- After the label is set, each cell makes another API call to populate the collection view, since these calls are concurrent, the collection view populates as soon as the response is fetched.
- The response from the above API call is used to create an array of Skill Model objects which is used to parse the response and to effectively use the data to display.
if let skills = response[Client.SkillListing.skills] as? [String : AnyObject], let model = response[Client.SkillListing.model] as? String, let group = response[Client.SkillListing.group] as? String, let language = response[Client.SkillListing.language] as? String, skills.count > 0 { let skillData = Skill.getAllSkill(skills, model, group, language) completion(skillData, true, nil) return }
static func getAllSkill(_ skills: [String : AnyObject], _ model: String, _ group: String, _ language: String) -> [Skill] { var skillData = [Skill]() for skill in skills { let newSkill = Skill(dictionary: skill.value as! [String : AnyObject]) newSkill.imagePath = getImagePath(model, group, language, newSkill.imagePath) skillData.append(newSkill) } return skillData }
- At last, the skill object for the collection view is used to populate it as below:
var skill: Skill? { didSet { if let skill = skill { if let url = URL(string: skill.imagePath) { imageView.kf.setImage(with: url) } exampleQueryLabel.text = "\(skill.examples.first?.debugDescription ?? "")" skillNameLabel.text = skill.skillName skillDescription.text = skill.skillDescription } } }
Here, we make use of the didSet method to populate the collection view. We have used Kingfisher to display the images.
That’s all for the scope of this tutorial. We learned how to fetch the skill groups followed by fetching the skills and displaying the skill data using the skill model object.
Below is the final UI we see after implementation.