Adding report skills feature in SUSI iOS

SUSI.AI is having a various type of Skills that improving the user experience. Skills are powering the SUSI.AI personal chat assistant. SUSI skills have a nice feedback system. We have three different feedback way for SUSI skills, 5-star rating system, posting feedback, and reporting skills. 5-Star Rating - rate skills from 1 (lowest) to 5 (highest) star Posting Feedback - user can post feedback about particular skill Report Skill - user can report skill if he/she found it inappropriate In this post, we will see how reporting skills feature work in SUSI iOS and how it is implemented. You can learn about 5-star rating here and posting feedback feature here. Adding report skill button - let reportSkillButton: UIButton = { let button = UIButton(type: .system) button.contentHorizontalAlignment = .left button.setTitle("Report Skill", for: .normal) button.setTitleColor(UIColor.iOSGray(), for: .normal) button.titleLabel?.font = UIFont.systemFont(ofSize: 16) button.translatesAutoresizingMaskIntoConstraints = false return button }() In above, we have set translatesAutoresizingMaskIntoConstraints property for false. By default, the property is set to true for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to false. If this property’s value is true, the system creates a set of constraints that duplicate the behavior specified by the view’s autoresizing mask. Setting up report skill button - We are setting constraints programmatically as we created button programmatically and set translatesAutoresizingMaskIntoConstraints to false. Also, setting a target to the button. if let delegate = UIApplication.shared.delegate as? AppDelegate, let _ = delegate.currentUser { view.addSubview(reportSkillButton) reportSkillButton.widthAnchor.constraint(equalToConstant: 140).isActive = true reportSkillButton.heightAnchor.constraint(equalToConstant: 32).isActive = true reportSkillButton.leftAnchor.constraint(equalTo: contentType.leftAnchor).isActive = true reportSkillButton.topAnchor.constraint(equalTo: contentType.bottomAnchor, constant: 8).isActive = true reportSkillButton.addTarget(self, action: #selector(reportSkillAction), for: .touchUpInside) } In the above method, we can see that we are only showing button if user is logged-in. Only a logged-in user can report the skill. To check if user is logged in or not, we are using the AppDelegate shared instance where we save the logged-in user globally when the user signs in. When user clicks the Report Skill button, a popup is open up with a text field for feedback message like below: This is how UI look like! When user clicks the Report action after typing feedback message, we are using the following endpoint: https://api.susi.ai/cms/reportSkill.json With the following parameters - ModelGroupSkillLanguageAccess TokenFeedback Here is how we are handling the API call within our app - func reportSkill(feedbackMessage: String) { if let delegate = UIApplication.shared.delegate as? AppDelegate, let user = delegate.currentUser { let params = [ Client.SkillListing.model: skill?.model as AnyObject, Client.SkillListing.group: skill?.group as AnyObject, Client.SkillListing.skill: skill?.skillKeyName as AnyObject, Client.SkillListing.language: Locale.current.languageCode as AnyObject, Client.SkillListing.accessToken: user.accessToken as AnyObject, Client.SkillListing.feedback: feedbackMessage as AnyObject ] Client.sharedInstance.reportSkill(params) { (success, error) in DispatchQueue.main.async { if success { self.view.makeToast("Skill reported successfully") } else if let error = error { self.view.makeToast(error) } } } } } On successfully reported skill, we show a toast with ‘Skill reported successfully’ message and if there is error reporting the skills, we present the toast with error as a message. Resources - SUSI Skills: https://skills.susi.ai/Apple’s documentations on translatesAutoresizingMaskIntoConstraintsAllowing user to…

Continue ReadingAdding report skills feature in SUSI iOS

Displaying Skills Feedback on SUSI.AI Android App

SUSI.AI has a feedback system where the user can post feedback for a skill using Android, iOS, and web clients. In skill details screen, the feedback posted by different users is displayed. This blog shows how the feedback from different users can be displayed in the skill details screen under feedback section. Three of the items from the feedback list are displayed in the skill details screen. To see the entire list of feedback, the user can tap the ‘See All Reviews’ option at the bottom of the list. The API endpoint that has been used to get skill feedback from the server is https://api.susi.ai/cms/getSkillFeedback.json The following query params are attached to the above URL to get the specific feedback list : Model Group Language Skill Name The list received is an array of `Feedback` objects, which hold three values : Feedback String (feedback) - Feedback string posted by a user Email (email) - Email address of the user who posted the feedback Time Stamp - Time of posting feedback To display feedback, use the RecyclerView. There can be three possible cases: Case - 1: Size of the feedback list is greater than three In this case, set the size of the list to three explicitly in the FeedbackAdapter so that only three view holders are inflated. Inflate the fourth view holder with “See All Reviews” text view and make it clickable if the size of the received feedback list is greater than three. Also, when the user taps “See All Reviews”, launch an explicit intent to open the Feedback Activity. Set the AllReviewsAdapter for this activity. The size of the list will not be altered here because this activity must show all feedback. Case - 2: Size of the feedback list is less than or equal to three In this case simply display the feedback list in the SkillDetailsFragment and there is no need to launch any intent here. Also, “See All Reviews” will not be displayed here. Case - 3: Size of the feedback list is zero In this case simply display a message that says no feedback has been submitted yet.Here is an example of how a “See All Reviews” screen looks like : Implementation First of all, define an XML layout for a feedback item and then create a data class for storing the query params. data class FetchFeedbackQuery( val model: String, val group: String, val language: String, val skill: String ) Now, make the GET request using Retrofit from the model (M in MVP). override fun fetchFeedback(query: FetchFeedbackQuery, listener: ISkillDetailsModel.OnFetchFeedbackFinishedListener) { fetchFeedbackResponseCall = ClientBuilder.fetchFeedbackCall(query) fetchFeedbackResponseCall.enqueue(object : Callback<GetSkillFeedbackResponse> { override fun onResponse(call: Call<GetSkillFeedbackResponse>, response: Response<GetSkillFeedbackResponse>) { listener.onFetchFeedbackModelSuccess(response) } override fun onFailure(call: Call<GetSkillFeedbackResponse>, t: Throwable) { Timber.e(t) listener.onFetchFeedbackError(t) } }) } override fun cancelFetchFeedback() { fetchFeedbackResponseCall.cancel() } The feedback list received in the JSON response can now be used to display the user reviews with the help of custom adapters, keeping in mind the three cases already discussed above. Resources Check out the GetSkillFeedbackService.java to know more about…

Continue ReadingDisplaying Skills Feedback on SUSI.AI Android App

Displaying Avatar of Users using Gravatar on SUSI.AI Android App

This blog post shows how the avatar image of the user is displayed in the feedback section using the Gravatar service on SUSI.AI Android app. A Gravatar is a Globally Recognized Avatar. Your Gravatar is an image that follows you from site to site appearing beside your name when you do things like comment or post on a blog. So, it was decided to integrate the service to SUSI.AI, so that it helps to  identify the user via the avatar image too. Implementation The aim is to use the user’s email address to get his/her avatar. For this purpose, Gravatar exposes a publicly available avatar of the user, which can be accessed via following steps : Creating the Hash of the email Sending the image request to Gravatar For the purpose of creating the MD5 hash of the email, use the MessageDigest class. The function takes an algorithm such as SHA-1, MD5, etc. as input and returns a MessageDigest object that implements the specified digest algorithm. Perform a final update on the digest using the specified array of bytes, which then completes the digest computation. That is, this method first calls update(input), passing the input array to the update method, then calls digest(). fun toMd5Hash(email: String?): String? { try { val md5 = MessageDigest.getInstance("MD5") val md5HashBytes: Array<Byte> = md5.digest(email?.toByteArray()).toTypedArray() return byteArrayToString(md5HashBytes) } catch (e: Exception) { return null } }   Convert the byte array to String, which is the requires MD5 hash of the email string. fun byteArrayToString(array: Array<Byte>): String { val result = StringBuilder(array.size * 2) for (byte: Byte in array) { val toAppend: String = String.format("%x", byte).replace(" ", "0") result.append(toAppend) } return result.toString() }   Now, a URL is generated using the hash. This is the URL that will be used to fetch the avatar. The URL format is https://www.gravatar.com/avatar/HASH, where HASH is the hash of the email of the user. In case, the hash is invalid, Gravatar returns a placeholder avatar. Also, append ‘.jpg’ to the URL to maintain image format consistency in the app. Finally, load this URL using Picasso and set it in the appropriate view holder. fun setAvatar(context: Context, email: String?, imageView: ImageView) { val imageUrl: String = GRAVATAR_URL + toMd5Hash(email) + ".jpg" Picasso.with(context) .load(imageUrl) .fit().centerCrop() .error(R.drawable.ic_susi) .transform(CircleTransform()) .into(imageView) }   You can now see the avatar image of the users in the feedback section. 😀 Resources MessageDigest | Android Developers https://developer.android.com/reference/java/security/MessageDigest  

Continue ReadingDisplaying Avatar of Users using Gravatar on SUSI.AI Android App

Displaying Skills Feedback on SUSI iOS

SUSI allows the user to rate the SUSI Skills with the five-star rating system. SUSI offer a good feedback system where the user can post feedback to any skill by using iOS, Android, and Web clients. In Skill Detail, there is a skill feedback text field where the user can write feedback about SUSI Skill. We display the users posted feedbacks on Skill Detail screen. In this post, we will see how the displaying skills feedback feature implemented on SUSI iOS. Implementation - We are displaying three feedback on Skill Detail screen, to see all feedback, there is a “See All Review” option, by clicking user is directed to a new screen where he/she can see all feedback related to particular skill. We use the endpoint below for getting skill feedback from server side – https://api.susi.ai/cms/getSkillFeedback.json With the following params: Model Group Language Skill Name The API endpoint above return the all the feedback array related to particular susi skill. We store feedbacks in an array of Feedback object, which holds three value: Feedback String - Feedback string posted by the user Email - Email address of feedback poster user Time Stamp - Time of posting feedback class Feedback: NSObject { var feedbackString: String = "" var email: String = "" var timeStamp: String = "" ... } To display feedbacks, we are using UITableView with two prototype cells, one for feedbacks and one for “See All Review” option. There can be different cases eg. when the total number of feedback for skill is less than three or three. When the feedback count is three or less than three, there is no need to show “See All Review” option. Also, tableView height is different for different feedback count. For varying tableView height, we have created an outlet for tableView height constraints and vary accordingly. @IBOutlet weak var feedbackTableHeighConstraint: NSLayoutConstraint! Now, let’s see how the number of cells, height for cells and different cells presented according to feedback count with UITableViewDelegate and UITableViewDataSource methods. Handling number of tableView rows - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { guard let feedbacks = feedbacks, feedbacks.count > 0 else { feedbackTableHeighConstraint.constant = 0.0 return 0 } if feedbacks.count < 4 { feedbackTableHeighConstraint.constant = CGFloat(72 * feedbacks.count) return feedbacks.count } else { feedbackTableHeighConstraint.constant = 260.0 return 4 } } Where feedbacks is the array of Feedback object which holds the feedbacks we are getting from the server side for a skill. var feedbacks: [Feedback]? In the above method, we see that how we are handling the number of cells case. Now let’s see how to handle which cells to be present on basis of the number of cells case - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let feedbacks = feedbacks, feedbacks.count > 0 else { feedbackTableHeighConstraint.constant = 0.0 return UITableViewCell() } if feedbacks.count < 4 { if let cell = tableView.dequeueReusableCell(withIdentifier: "feedbackDisplayCell", for: indexPath) as? FeedbackDisplayCell { cell.feedback = feedbacks[indexPath.row - Int(indexPath.row/2)] return cell } } else…

Continue ReadingDisplaying Skills Feedback on SUSI iOS

Post feedback for SUSI Skills in SUSI iOS

SUSI iOS, web and Android clients allow the user to rate the SUSI Skills in a 5-star rating system. Users can write about how much particular skill is helpful for them or if improvements are needed. Users can rate skills from one to five star as well. Here we will see how to submit feedback for SUSI skills and how it is implemented on SUSI iOS. How to submit feedback - Go to Skill Listing Screen < Skill Detail Screen Scroll to the feedback section Write feedback about SUSI skill Click on POST button to post the skill feedback An anonymous user can not submit skill feedback. You must have to logged-in in order to post skill feedback. If you are not logged-in and click POST button to post skill feedback, an alert is presented with Login option, by clicking Login, the user is directed to Login screen where the user can log in and later can post skill feedback. Implementation of posting skill feedback - Google’s Material textfield is used for skill feedback text field. We have assigned TextField class from Material target to skill feedback text field to make it very interactive and give better user experience. Skill feedback text field in the normal state - Skill feedback text field in the active state - When the user clicks POST after writing skill feedback, we check if the user is logged-in or not. if let delegate = UIApplication.shared.delegate as? AppDelegate, let user = delegate.currentUser { ... } We have saved the logged-in user globally using AppDelegate shared method during login and using it here. The AppDelegate is sort of like the entry point for the application. It implements UIApplicationDelegate and contains methods that are called when application launches, when is going to the background (i.e. when the user hit the home key), when it’s opened back up, and more. The AppDelegate object is stored as a property on the UIApplication class and is accessible from anywhere in swift classes. Case 1: If the user is not logged-in, we show a popup to the user with the login option By clicking Login, the user is directed to Login screen where the user can log in and later can post skill feedback. Case 2: If the user is already logged-in, we use the endpoint below for posting skill feedback - http://api.susi.ai/cms/feedbackSkill.json ModelWith following parameters - Group Skill Feedback Access token Client.sharedInstance.postSkillFeedback(postFeedbackParam) { (feedback, success, responseMessage) in DispatchQueue.main.async { if success { self.skillFeedbackTextField.text = "" self.skillFeedbackTextField.resignFirstResponder() self.view.makeToast(responseMessage) } else { self.view.makeToast(responseMessage) } } } In return response, we get feedback posted by the user - { feedback: "Helpful", session: { ... }, accepted: true, message: "Skill feedback updated" }   Resources - Material Design Guidelines for iOS Apple’s documentation on UIApplicationDelegate API Apple’s documentation on UIApplication API ChrisRisner’s article on Singletons and AppDelegate

Continue ReadingPost feedback for SUSI Skills in SUSI iOS

Implementing Feedback Feature in SUSI Android App

Recently, on SUSI Server, a new servlet was added which is used to rate SUSI Skills either positive or negative. The server stores the rating of a particular skill in a JSON file. These ratings help in improving answers provided by SUSI. So, the server part is done and it was required to implement this in the SUSI Android App. In this blog, I will cover the topic of implementation of the Rating or Feedback feature in SUSI Android App. This will including all the cases when feedback should be sent, when it should not be sent, when to send positive feedback, when to send negative feedback, etc. API Information For rating a SUSI Skill, we have to call on  /cms/rateSkill.json providing 5 parameters which are: model: The model of SUSI Skill. (String) group: The Group under the model in which that particular skill resides. (String) language: The language of skill. (String) skill: This is skill name. (String) rating: This can be two strings, either “positive” or “negative”. String) Basically, in the SUSI Skill Data repo (in which all the skills are stored), models, groups language etc are part of folder structure. So, if a skill is located here https://github.com/fossasia/susi_skill_data/blob/master/models/general/Knowledge/en/news.txt This would mean model = general group = Knowledge language = en skill = news rating = positive/negative Implementation in SUSI Android App      So, when the like button on a particular skill is clicked, a positive call is made and when the dislike button is clicked, a negative call is made. Let’s see example when the thumbs up button or like button is clicked. There can be three cases possible: None of Like button or dislike button is clicked already: In this case, initially, both like and dislike button will be transparent/hollow. So, when like button is clicked, the like button will be colored blue and a call will be made with positive feedback. Like button is already clicked: In this case, like button is already clicked. So, it will already be blue. So, when user clicks again on positive button, it should get back to normal/hollow indicating rating which was sent is cancelled and a a call will be made with negative feedback thus cancelling or neutralizing the earlier, positive feedback. Dislike button is already clicked: In this case, the dislike button is already blue, indicating a negative call is already made. So, now when the like button is clicked, we need to cancel the earlier negative feedback call and sending another negative feedback call. Thus, sending two negative feedback calls. And after that coloring dislike button as blue. Look at the code below. It is self explanatory. There are three if-else conditions covering all the above mentioned three cases. thumbsUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { thumbsUp.setImageResource(R.drawable.thumbs_up_solid); if(!model.isPositiveRated() && !model.isNegativeRated()) { rateSusiSkill(Constant.POSITIVE, model.getSkillLocation(), context); setRating(true, true); } else if(!model.isPositiveRated() && model.isNegativeRated()) { setRating(false, false); thumbsDown.setImageResource(R.drawable.thumbs_down_outline); rateSusiSkill(Constant.POSITIVE, model.getSkillLocation(), context); sleep(500); rateSusiSkill(Constant.POSITIVE, model.getSkillLocation(), context); setRating(true, true); } else if (model.isPositiveRated() && !model.isNegativeRated()) { rateSusiSkill(Constant.NEGATIVE, model.getSkillLocation(), context);…

Continue ReadingImplementing Feedback Feature in SUSI Android App

Implementing the Feedback Functionality in SUSI Web Chat

SUSI AI now has a feedback feature where it collects user’s feedback for every response to learn and improve itself. The first step towards guided learning is building a dataset through a feedback mechanism which can be used to learn from and improvise the skill selection mechanism responsible for answering the user queries. The flow behind the feedback mechanism is : For every SUSI response show thumbs up and thumbs down buttons. For the older messages, the feedback thumbs are disabled and only display the feedback already given. The user cannot change the feedback already given. For the latest SUSI response the user can change his feedback by clicking on thumbs up if he likes the response, else on thumbs down, until he gives a new query. When the new query is given by the user, the feedback recorded for the previous response is sent to the server. Let’s visit SUSI Web Chat and try this out. We can find the feedback thumbs for the response messages. The user cannot change the feedback he has already given for previous messages. For the latest message the user can toggle feedback until he sends the next query. How is this implemented? We first design the UI for feedback thumbs using Material UI SVG Icons. We need a separate component for the feedback UI because we need to store the state of feedback as positive or negative because we are allowing the user to change his feedback for the latest response until a new query is sent. And whenever the user clicks on a thumb, we update the state of the component as positive or negative accordingly. import ThumbUp from 'material-ui/svg-icons/action/thumb-up'; import ThumbDown from 'material-ui/svg-icons/action/thumb-down'; feedbackButtons = ( <span className='feedback' style={feedbackStyle}> <ThumbUp onClick={this.rateSkill.bind(this,'positive')} style={feedbackIndicator} color={positiveFeedbackColor}/> <ThumbDown onClick={this.rateSkill.bind(this,'negative')} style={feedbackIndicator} color={negativeFeedbackColor}/> </span> ); The next step is to store the response in Message Store using saveFeedback Action. This will help us later to send the feedback to the server by querying it from the Message Store. The Action calls the Dispatcher with FEEDBACK_RECEIVED ActionType which is collected in the MessageStore and the feedback is updated in the Message Store. let feedback = this.state.skill; if(!(Object.keys(feedback).length === 0 && feedback.constructor === Object)){ feedback.rating = rating; this.props.message.feedback.rating = rating; Actions.saveFeedback(feedback); } case ActionTypes.FEEDBACK_RECEIVED: { _feedback = action.feedback; MessageStore.emitChange(); break; } The final step is to send the feedback to the server. The server endpoint to store feedback for a skill requires other parameters apart from feedback to identify the skill. The server response contains an attribute `skills` which gives the path of the skill used to answer that query. From that path we need to parse : Model : Highest level of abstraction for categorising skills Group : Different groups under a model Language : Language of the skill Skill : Name of the skill For example, for the query `what is the capital of germany` , the skills object is "skills": ["/susi_skill_data/models/general/smalltalk/en/English-Standalone-aiml2susi.txt"] So, for this skill, Model : general Group : smalltalk Language : en Skill :…

Continue ReadingImplementing the Feedback Functionality in SUSI Web Chat

How to Implement Feedback System in SUSI iOS

The SUSI iOS app provides responses for various queries but the response is always not accurate. To improve the response, we make use of the feedback system, which is the first step towards implementing Machine Learning on the SUSI Server. The way this works is that for every query, we present the user with an option to upvote or downvote the response and based on that a positive or negative feedback is saved on the server. In this blog, I will explain how this feedback system was implemented in the SUSI iOS app. Steps to implement: We start by adding the UI which is two buttons, one with a thumbs up and the other with a thumbs down image. textBubbleView.addSubview(thumbUpIcon) textBubbleView.addSubview(thumbDownIcon) textBubbleView.addConstraintsWithFormat(format: "H:[v0]-4-[v1(14)]-2-[v2(14)]-8-|", views: timeLabel, thumbUpIcon, thumbDownIcon) textBubbleView.addConstraintsWithFormat(format: "V:[v0(14)]-2-|", views: thumbUpIcon) textBubbleView.addConstraintsWithFormat(format: "V:[v0(14)]-2-|", views: thumbDownIcon) thumbUpIcon.isUserInteractionEnabled = true thumbDownIcon.isUserInteractionEnabled = true Here, we add the subviews and assign constraints so that these buttons align to the bottom right next to each other. Also, we enable the user interaction for these buttons. We know that the user can rate the response by pressing either of the buttons added above. To do that we make an API call to the endpoint below: BASE_URL+'/cms/rateSkill.json?'+'model='+model+'&group='+group+'&skill='+skill+’&language’+language+’&rating=’+rating Here, the BASE_URL is the url of the server, the other three params model, group, language and skill are retrieved by parsing the skill location parameter we get with the response. The rating is positive or negative based on which button was pressed by the user. The skill param in the response looks like this: skills: [ "/susi_skill_data/models/general/entertainment/en/quotes.txt" ] Let’s write the method that makes the API call and responds to the UI that it was successful. if let accepted = response[ControllerConstants.accepted] as? Bool { if accepted { completion(true, nil) return } completion(false, ResponseMessages.ServerError) return } Here after receiving a response from the server, we check if the `accepted` variable is true or not. Based on that, we pass `true` or `false` to the completion handler. Below the response we actually receive by making the request. { session: { identity: { type: "host", name: "23.105.140.146", anonymous: true } }, accepted: true, message: "Skill ratings updated" } Finally, let’s update the UI after the request has been successful. if sender == thumbUpIcon { thumbDownIcon.tintColor = UIColor(white: 0.1, alpha: 0.7) thumbUpIcon.isUserInteractionEnabled = false thumbDownIcon.isUserInteractionEnabled = true feedback = "positive" } else { thumbUpIcon.tintColor = UIColor(white: 0.1, alpha: 0.7) thumbDownIcon.isUserInteractionEnabled = false thumbUpIcon.isUserInteractionEnabled = true feedback = "negative" } sender.tintColor = UIColor.hexStringToUIColor(hex: "#2196F3") Here, we check the sender (the thumbs up or down button) and based on that pass the rating (positive or negative) and update the color of the button. Below is the app in action with the feedback system. Resources: Tutorial on Raywanderlich discusses the way custom collection view cells are created Another tutorial on creating custom cells Alamofire Docs: explains usage of Alamofire to make API calls Material.io icons: source of the icons used

Continue ReadingHow to Implement Feedback System in SUSI iOS

Getting Response Feedback In SUSI.AI Web Chat

The SUSI.AI Web Chat provides responses for various queries, but the quality of responses it not always the best possible. Machine learning and deep learning algorithms will help us to solve this step by step. In order to implement machine learning, we need feedback mechanisms. The first step in this direction is to provide users with a way to give feedback to responses with a “thumbs up” or “thumbs down”. In this blog, I explain how we fetch the feedback of responses from the server. On asking a query like tell me a quote, Susi responses with following message: Now the user can rate the response by pressing thumbs up or thumbs down button. We store this response on the server. For getting this count of feedback we use the following endpoint: BASE_URL+'/cms/getSkillRating.json?'+'model='+model+'&group='+group+'&skill='+skill; Here: BASE_URL: Base URL of our server: http://api.susi.ai/ model: Model of the skill from which response is fetched. For example “general”. group: The group of the skill from which response is fetched. For example “entertainment”. skill: name of the skill from which response is fetched. For example “quotes”. We make an ajax call to the server to fetch the data: $.ajax({ url: getFeedbackEndPoint, dataType: 'jsonp', crossDomain: true, timeout: 3000, async: false, success: function (data) { console.log(getFeedbackEndPoint) console.log(data); if(data.accepted) { let positiveCount = data.skill_rating.positive; let negativeCount = data.skill_rating.negative; receivedMessage.positiveFeedback = positiveCount; receivedMessage.negativeFeedback = negativeCount; } } In the success function, we receive the data, which is in jsonp format. We parse this to get the desired result and store it in variable positiveCount and negativeCount. An example of data response is : In the client, we can get value corresponding to positive and negative key as follows : let positiveCount = data.skill_rating.positive; let negativeCount = data.skill_rating.negative; This way we can fetch the positive and negative counts corresponding to a particular response. This data can be used in many ways, for example: It can be used to display the number of positive and negative count next to the thumbs: It can be used in machine learning algorithms to improve the response that SUSI.AI provides. Resources: Ajax’s guide on MDN: https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started Testing Link: http://chat.susi.ai/

Continue ReadingGetting Response Feedback In SUSI.AI Web Chat