Using Vector Images in SUSI Android

Android designed to run across many devices with different screen sizes and display resolutions. One of the things that confuse many new Android developers is how to support multiple screen sizes. For making  SUSI Android app more user-friendly and interactive we used a lot of images in the form of drawable resources. Most of these drawables are in the form of PNG (Portable Network Graphic) and to support multiple screen size we have to include separate images of varied dimensions because we can’t scale PNG images without losing quality. Other disadvantages of using PNG images are PNG images take large disk space. PNG images have fixed colour and dimensions which cannot be changed. To overcome these shortcomings of PNG image we decided to use vector images in SUSI Android. Advantages of using vector image are It is smaller in size as compared to PNG i.e it takes less disk space than PNG. It can be scaled without losing quality. So we need to include only a single image for all screen size. Disadvantages of using vector image are Reconstruction of vector data may take considerably longer than that contained in a bitmap file of equivalent complexity because each image element must be drawn individually and in sequence. Vector image can’t be used to display complex photographs. If the object consists of a large number of small elements then file size grow very fast. Vector produce smaller size file than bitmap only for simple stuff. When it comes to creating a photographic quality vector where colour information is paramount and may vary on a pixel-by-pixel basis, the file can be much larger than its bitmap version, that’s why vector image is only suitable for small images like logo designs, icons etc. In this blog post, I will show you how we used vector images in SUSI Android. How to create vector image using Asset Studio tool Asset Studio is inbuilt Android Studio tool which we use to create a vector image from default material icon or local SVG images. To use vector asset in Android Studio Go to File> New > Vector Asset Vector Asset Studio Tool Window is prompted Create vector image from default material icon or local SVG image. Asset Studio will add icon in drawable. It can be used anywhere in the project. Vector images in SUSI Android In SUSI Android all drawable images like search, mic, arrow, check etc are vector images,  even the logo of the app is a vector image. This vector image is the result of code you can find here. Now I will describe some special attributes used here fillColor: It defines the colour of the image. So the colour of your image depends on the colour you provide in fillColor. We used white color(#ffffff) as fillColor that’s why the image is white in colour. strokeColour: It defines the colour of boundary of the image. pathData: Shape of your image depends on pathData. Different commands used in pathData are M: It is used to define…

Continue ReadingUsing Vector Images in SUSI Android

How to Receive Carousels from SUSI Skype Bot

A good UI primarily focuses on attracting large numbers of users and any good UI designer aims to achieve user satisfaction with a user-friendly design. In this blog, we will learn how to show carousels SUSI Skype bot to make UI better and easy to use. We can show web search result from SUSI in form of text responses in Skype bot but it doesn’t follow design rule as it is not a good approach to show more text in constricted space. Users seem such a layout as less attractive. In SUSI webchat, RSS type response is returned as carousels and is viewable as: We can implement RSS type response with code given below for (var i = 0; i < metadata.count; i++) {         msg = "";         msg = text to be sent here;         session.say(msg, msg); } If we implement RSS response using this code then we get a very constricted response because of more text. You can see it in the screenshot below: To make RSS type response better we will implement carousels. Carousels are actually horizontal tiles to show rich content. We will use this code:            for (var i = 0; i < 4; i++) {                msg = "text here";                title  = "title here";                cards[i] = new builder.HeroCard(session)                    .title(title) .text(msg)            }            var reply = new builder.Message(session) .attachmentLayout(builder.AttachmentLayout.carousel)                .attachments(cards);            session.send(reply); In above code, we are using a hero card which is a rich card containing title and message which are then attached as an attachment to the message. After implementing carousels for RSS response it looks like this Resources Bot Builder SDK documentation: https://docs.botframework.com/en-us/node/builder/chat-reference/modules/_botbuilder_d_.html Rich Card examples: https://github.com/Microsoft/BotBuilder-Samples/blob/master/Node/cards-RichCards/app.js

Continue ReadingHow to Receive Carousels from SUSI Skype Bot

How to Debug SUSI Bots Deployment on Google Container Engine Using Kubernetes

You can learn how to deploy SUSI bots on to Google container engine using Kubernetes from this tutorial. In this blog, we will learn how to debug SUSI bots deployment to keep them running continuously. Whenever we create a deployment on Google container using Kubernetes a pod is created in which our deployment keeps running. Whenever we deploy bots to any platform to check if it is working right or not we refer to logs of that bot. To get logs first we will get pod for our deployment with this kubectl get pods --namespace={your-namespace-of-deployment-here} This will show us the pod for our deployment like this Copy the name of this pod and enter this command to get logs kubectl get logs {your-pod-here} --namespace={your-namespace-of-deployment-here} This will show us the logs of our deployment. In Google cloud console you will not get running logs. You will get logs of the everything that has happened before you requested for logs. Now if there is some error in logs and you need to restart the deployment but in Kubernetes you can not restart your pod directly but to restart pod we will need to enter the following command kubectl replace --force -f {path-to-your-deployment-config-file} If everything goes well you will get to see the following with your deployment name in it After deployment, if you want to see the services and deployment in detail follow the approach given below To get services write this command kubectl get service --namespace={your-namespace-of-deployment-here} When you will get service it will look like If you don’t get your external IP then check your service config file and after fixing it make a new deployment after deleting previous one. To check deployment in detail write following command kubectl describe deployments --namespace={your-namespace-of-deployment-here} This will show us details about deployment like this You can now easily solve issues with deployments now. Resources Debugging Kubernetes service locally using telepresence: https://www.telepresence.io/tutorials/kubernetes.html Debug Services: https://kubernetes.io/docs/tasks/debug-application-cluster/debug-service/ Troubleshooting Kuberetes: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/getting_started_with_kubernetes/troubleshooting_kubernetes  

Continue ReadingHow to Debug SUSI Bots Deployment on Google Container Engine Using Kubernetes

Shift from Java to Kotlin in SUSI Android

Previously SUSI Android was written in JAVA. But recently Google announced that it will officially support Kotlin on Android as a first class language so we decided to shift from Java to Kotlin. Kotlin runs on Java Virtual Machine and hence we can use Kotlin for Android app development. Kotlin is new programming language developed by JetBrains, which also developed IntelliJ-the IDE that Android Studio is based on. So Android Studio has excellent support for Kotlin. Advantages of Kotlin over Java Kotlin is a null safe language. It changes all the instances used in the code to non nullable type thus it ensures that the developers don't get any nullPointerException. Good Android Studio support. Kotlin tool is included with Android Studio 3.0 by default. But for Android Studio 2.x we need to install the required plugin for Kotlin. Kotlin also provides support for Lambda function and other high order functions. One of Kotlin’s greatest strengths as a potential alternative to Java is interoperability between Java and Kotlin. You can even have Java and Kotlin code existing side by side in the same project. Kotlin provides the way to declare Extension function similar to that of C# and Gosu. We can use this function in the same way as we use the member functions of our class. After seeing the above points it is now clear that Kotlin is much more effective than Java. In this blog post, I will show you how ForgotPasswordActivity is shifted from JAVA to Kotlin in SUSI Android. How to install Kotlin plugin in Android Studio 2.x We are using Android Studio 2.3.0 in our android project. To use Kotlin in Android Studio 2.x we need to install Kotlin plugin. Steps to include Kotlin plugin in Android Studio 2.x are: Go to File After that select Settings Then select Plugin Option from the left sidebar. After that click on Browse repositories. Search for Kotlin and install it. Once it is installed successfully, restart Android Studio. Now configure Kotlin in Android Studio. Shift  SUSI Android from JAVA to Kotlin Kotlin is compatible with JAVA. Thus it allows us to change the code bit by bit instead of all at once. In SUSI Android app we implemented MVP architecture with Kotlin. We converted the code by one activity each time from JAVA to Kotlin. I converted the ForgotPassword of SUSI Android from JAVA to Kotlin with MVP architecture. I will discuss only shifting of SUSI Android from JAVA to Kotlin and not about MVP architecture implementation. First thing is how to extend parent class. In JAVA we need to use extend keyword public class ForgotPasswordActivity extends AppCompatActivity but in Kotlin parent class is extended like class ForgotPasswordActivity : AppCompatActivity () Second is no need to bind view in Kotlin. In JAVA we bind view using Butter Knife. @BindView(R.id.forgot_email) protected TextInputLayout email; and email.setError(getString(R.string.email_invalid_title)); but in Kotlin we can directly use view using id. forgot_email.error = getString(R.string.email_invalid_title) Another important thing is that instead of using setError and getError we can…

Continue ReadingShift from Java to Kotlin in SUSI Android

Implementing Change Password Feature in SUSI Android App using Custom Dialogs

Recently a new servlet was implemented on the SUSI Server about changing the password of the logged in user. This feature comes in handy to avoid unauthorized usage of the SUSI Account. Almost all the online platforms have this feature to change the password to avoid notorious user to unethical use someone else’s account. In SUSI Android app this new API was used with a nice UI to change the password of the user. The process is very simple and easy to grasp. This blog will try to cover the API information and implementation of the Change Password feature in the android client. API Information For changing the password of SUSI Account of the user, we have to call on  /aaa/changepassword.json We have to provide three parameters along with this api call: changepassword:  Email of user (type string) using which user is logged in. password:  Old password (type string with min length of 6) of the user. newpassword: New password (type string with min length of 6) of the user. access_token: An encrypted access_token indicating user is logged in. Sample Response (Success) { "session": {"identity": { "type": "email", "name": "YOUR_EMAIL_ADDRESS", "anonymous": false }}, "accepted": true, "message": "Your password has been changed!" } Error Response (Failure). This happens when user is not logged in: HTTP ERROR 401 Problem accessing /aaa/changepassword.json. Reason: Base user role not sufficient. Your base user role is 'ANONYMOUS', your user role is 'anonymous' Implementation in SUSI Android App The change password option is located in Settings Activity and displayed only when user is logged in. So, if a logged in user wants to change the password of his/her SUSI AI account, he/she can simply go to the Settings and click on the option. Clicking on the options open up a dialog box with 3 input layouts for: Current Password New Password Confirm New Password So, user can simply add these three inputs and click “Ok”. This will change the password of their account. Let’s see some code explanation. When user clicks on the “reset password” option from the settings, the showResetPasswordAlert() method is called which displays the dialog. And when user clicks on the “OK” button the resetPassword method() in the presenter is called passing input from the three input layout as parameters. settingsPresenter.resetPassword(password.editText?.text.toString(), newPassword.editText?.text.toString(), conPassword.editText?.text.toString()) fun showResetPasswordAlert() { val builder = AlertDialog.Builder(activity) val resetPasswordView = activity.layoutInflater.inflate(R.layout.alert_reset_password, null) password = resetPasswordView.findViewById(R.id.password) as TextInputLayout newPassword = resetPasswordView.findViewById(R.id.newpassword) as TextInputLayout conPassword = resetPasswordView.findViewById(R.id.confirmpassword) as TextInputLayout builder.setView(resetPasswordView) builder.setTitle(Constant.CHANGE_PASSWORD) .setCancelable(false) .setNegativeButton(Constant.CANCEL, null) .setPositiveButton(getString(R.string.ok), null) resetPasswordAlert = builder.create() resetPasswordAlert.show() setupPasswordWatcher() resetPasswordAlert.getButton(AlertDialog.BUTTON_POSITIVE)?.setOnClickListener { settingsPresenter.resetPassword(password.editText?.text.toString(), newPassword.editText?.text.toString(), conPassword.editText?.text.toString()) } } In the resetPassword method, all details about the passwords are checked like: If passwords are not empty. If passwords’ lengths are greater than 6. If new password and confirmation new password matches     When all the conditions are satisfied and all the inputs are valid, resetPassword() in model is called which makes network call to change password of the user. settingModel.resetPassword(password,newPassword,this) override fun resetPassword(password: String, newPassword: String, conPassword: String) { if (password.isEmpty()) { settingView?.invalidCredentials(true,…

Continue ReadingImplementing Change Password Feature in SUSI Android App using Custom Dialogs

Full-Screen Speech Input Implementation in SUSI Android App

SUSI Android has some very good features and one of them is, it can take input in speech format from user i.e if the user says anything then it can detect it and convert it to text. This feature is implemented in SUSI Android app using Android’s built-in speech-to-text functionality. You can implement Android’s built-in speech-to-text functionality using either only RecognizerIntent class or SpeechRecognizerIntent class, RecognitionListner interface and RecognizerIntent class. Using former method has some disadvantages: During speech input, it shows a dialog box (as shown here) and it breaks the connection between user and app. We can’t show partial result i.e text to the user but using the later method we can show it. We used  SpeechRecognizerIntent class, RecognitionListner interface and RecognizerIntent class to implement Android’s built-in speech-to-text functionality in SUSI Android and you know the reason for that. In this blog post, I will show you how I implemented this feature in SUSI Android with new UI. Layout design You can give speech input to SUSI Android either by clicking mic button or using ‘Hi SUSI’ hotword. When you click on mic button or use ‘Hi SUSI’ hotword, you can see a screen where you will give speech input. Two important part of this layout are: <TextView   android:id="@+id/txtchat"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   …  /> TextView: It used to show the partial result of speech input i.e it will show converted text (partial) of your speech. <org.fossasia.susi.ai.speechinputanimation.SpeechProgressView   android:id="@+id/speechprogress"   android:layout_width="match_parent"   android:layout_height="50dp"   android:layout_margin="8dp"   android:layout_gravity="center"/> SpeechProgressView: It is a custom view which use to show the animation when the user gives speech input. When the user starts speaking, the animation starts. This custom view contains five bars and these five bars animate according to user input. Full-screen speech input implementation When the user clicks on mic button or uses ‘Hi SUSI’ hotword, a screen comes where the user can give speech input. As already mentioned I used SpeechRecognizerIntent class, RecognitionListner interface and RecognizerIntent class to implement speech-to-text functionality in SUSI Android. RecognizerIntent class starts an intent and asks for speech input val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,     RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "com.domain.app") intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true) and send it through the speech recognizer. It does it through ACTION_RECOGNIZE_SPEECH. SpeechRecognizer class provides access to the speech recognition service. This service allows access to the speech recognizer and recognition related event occurs RecognitionListner receive notification from SpeechRecognizer class. recognizer = SpeechRecognizer       .createSpeechRecognizer(activity.applicationContext) val listener = object : RecognitionListener {  //implement all override methods } When the user starts speaking, the height of bars changes according to change in sound level. When sound level changes, onRmsChanged method get called where we are calling onRmsChanged method of SpeechProgressView class which is responsible for animating bars according to change in sound level. override fun onRmsChanged(rmsdB: Float) {   if (speechprogress != null)       speechprogress.onRmsChanged(rmsdB) } When user finished speaking onEndOfSpeech method get called where we call onEndOfSpeech method of SpeechProgressView class which is responsible for rotating animation. Rotation is used to show that SUSI Android has finished listening and now it is processing your input. override…

Continue ReadingFull-Screen Speech Input Implementation in SUSI Android App

Making GUI for SUSI Linux with PyGTK

SUSI Linux app provides access to SUSI on Linux distributions on desktop as well as hardware devices like Raspberry Pi. It started off as a headless client but we decided to add a minimalist GUI to SUSI Linux for performing login and configuring settings. Since, SUSI Linux is a Python App, it was desirable to use a GUI Framework compatible with Python. Many popular GUI frameworks now provide bindings for Python. Some popular available choices are: wxPython: wxPython is a Python GUI framework based on wxWidgets, a cross-platform GUI library written in C++. In addition to the standard dialogs, it includes a 2D path drawing API, dockable windows, support for many file formats and both text-editing and word-processing widgets. wxPython though mainly support Python 2 as programming language. PyQT: Qt is a multi-licensed cross-platform framework written in C++. Qt needs a commercial licence for use but if application is completely Open Source, community license can be used. Qt is an excellent choice for GUIs and many applications are based on it. PyGTK / PyGObject: PyGObject is a Python module that lets you write GUI applications in GTK+. It provides bindings to GObject, a cross platform C library. GTK+ applications are natively supported in most distros and you do not need to install any other development tools for developing with PyGTK. Comparing all these frameworks, PyGTK was found to meet our needs very well. To make UIs in PyGTK, you have a WYSIWYG (What you see is what you get) editor called Glade. Though you can design whole UI programmatically, it is always convenient to use an editor like Glade to simplify the creation and styling of widgets. To create a UI, you need to install Glade in your specific distribution. After that open glade, and add a Top Level container Window or AppWindow to your app. Once that is done, you may pick from the available Layout Managers. We are using BoxLayout Manager in SUSI Linux GUIs. Once that is done, add your widgets to the Application Window using Drag and Drop. Properties of widgets are available on the right panel. Edit your widget properties to give them meaningful IDs so we can address them later in our code. GTK also provides Signals for signaling about a events associated with the widgets. Open the Signals tab in the Widget properties pane. Then, you need to write name of the signal handler for the events associated with Widgets. A signal handler is a function that is fired upon the occurrence of the associated event. For example, we have signals like text_changed in Text Entry boxes, and clicked for Button. After completing the design of GUI, we can address the .glade file of the UI we just created in the Python code. We can do this using the following snippet. import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk builder = Gtk.Builder() builder.add_from_file("glade_files/signin.glade") You can reference each widget from the Glade file using its ID like below. email_field = builder.get_object("email_field") Now, to handle all the declared signals in…

Continue ReadingMaking GUI for SUSI Linux with PyGTK

Modifying SUSI Skills using SUSI Skill CMS

SUSI Skill CMS is a complete solution right from creating a skill to modifying the skill. The skills in SUSI are well synced with the remote repository and can be completely modified using the Edit Skill feature of SUSI Skill CMS. Here’s how to Modify a Skill. Sign Up/Login to the website using your credentials in skills.susi.ai Choose the SKill which you want to edit and click on the pencil icon. The following screen allows editing the skill. One can change the Group, Language, Skill Name, Image and the content as well. After making the changes the commit message can be added to Save the changes. To achieve the above steps we require the following API Endpoints of the SUSI Server. http://api.susi.ai/cms/getSkillMetadata.json - This gives us the meta data which populates the various Skill Content, Image, Author etc. http://api.susi.ai/cms/getAllLanguages.json - This gives us all the languages of a Skill Group. http://api.susi.ai/cms/getGroups.json - This gives us all the list of Skill Groups whether Knowledge, Entertainment, Smalltalk etc. Now since we have all the APIs in place we make the following AJAX calls to update the Skill Process. Since we are detecting changes in all the fields (Group Value, Skill Name, Language Value, Image Value, Commit Message, Content changes and the format of the content), the AJAX call can only be sent when there is a change in the PR and there is no null or undefined value in them. For that, we make various form validations. They are as follows. We first detect whether the User is in a logged in state. if (!cookies.get('loggedIn')) { notification.open({ message: 'Not logged In', description: 'Please login and then try to create/edit a skill', icon: <Icon type="close-circle" style={{ color: '#f44336' }} />, }); } We check whether the image uploaded matches the format of the Skill image to be stored which is ::image images/imageName.png if (!new RegExp(/images\/\w+\.\w+/g).test(this.state.imageUrl)) { notification.open({ message: 'Error Processing your Request', description: 'image must be in format of images/imageName.jpg', icon: <Icon type="close-circle" style={{ color: '#f44336' }} />, }); } We check if the commit message is not null and notify the user if he forgot to add a message. if (this.state.commitMessage === null) { notification.open({ message: 'Please make some changes to save the Skill', icon: <Icon type="close-circle" style={{ color: '#f44336' }} />, }); } We also check whether the old values of the skill are completely similar to the new ones, in this case, we do not send the request. if (toldValues===newValues { notification.open({ message: 'Please make some changes to save the Skill', icon: <Icon type="close-circle" style={{ color: '#f44336' }} />, }); } To check out the complete code, go to this link. Next, if the above validations are successful, we send a POST request to the server and show the notification to the user accordingly, whether the changes to the Skill Data have been updated or not. Here’s the AJAX call snippet. // create a form object let form = new FormData();        /* Append the following fields from…

Continue ReadingModifying SUSI Skills using SUSI Skill CMS

Deleting SUSI Skills from Server

SUSI Skill CMS is a web application to create and edit skills. In this blog post I will be covering how we made the skill deleting feature in Skill CMS from the SUSI Server. The deletion of skill was to be made in such a way that user can click a button to delete the skill. As soon as they click the delete button the skill is deleted it is removed from the directory of SUSI Skills. But admins have an option to recover the deleted skill before completion of 30 days of deleting the skill. First we will accept all the request parameters from the GET request. String model_name = call.get("model", "general"); String group_name = call.get("group", "Knowledge"); String language_name = call.get("language", "en"); String skill_name = call.get("skill", "wikipedia"); In this we get the model name, category, language name, skill name and the commit ID. The above 4 parameters are used to make a file path that is used to find the location of the skill in the Susi Skill Data repository. if(!DAO.deleted_skill_dir.exists()){ DAO.deleted_skill_dir.mkdirs(); } We need to move the skill to a directory called deleted_skills_dir. So we check if the directory exists or not. If it not exists then we create a directory for the deleted skills. if (skill.exists()) { File file = new File(DAO.deleted_skill_dir.getPath()+path); file.getParentFile().mkdirs(); if(skill.renameTo(file)){ Boolean changed = new File(DAO.deleted_skill_dir.getPath()+path).setLastModified(System.currentTimeMillis()); } This is the part where the real deletion happens. We get the path of the skill and rename that to a new path which is in the directory of deleted skills. Also here change the last modified time of the skill as the current time. This time is used to check if the skill deleted is older than 30 days or not. try (Git git = DAO.getGit()) { DAO.pushCommit(git, "Deleted " + skill_name, rights.getIdentity().isEmail() ? rights.getIdentity().getName() : "anonymous@"); json.put("accepted", true); json.put("message", "Deleted " + skill_name); } catch (IOException | GitAPIException e) { Finally we add the changes to Git. DAO.pushCommit pushes to commit to the Susi Skill Data repository. If the user is logged in we get the email of the user and set that email as the commit author. Else we set the username “anonymous@”. Then in the caretaker class there is a method deleteOldFiles that checks for all the files whose last modified time was older than 30 days. If there is any file whose last modified time was older than 30 days then it quietly delete the files. public void deleteOldFiles() { Collection<File> filesToDelete = FileUtils.listFiles(new File(DAO.deleted_skill_dir.getPath()), new (DateTime.now().withTimeAtStartOfDay().minusDays(30).toDate()), TrueFileFilter.TRUE); // include sub dirs for (File file : filesToDelete) { boolean success = FileUtils.deleteQuietly(file); if (!success) { System.out.print("Deleted skill older than 30 days."); } } } To test this API endpoint, we need to call http://localhost:4000/cms/deleteSkill.txt?model=general&group=Knowledge&language=en&skill=<skill_name> Resources JGit Documentation: https://eclipse.org/jgit/documentation/ Commons IO: https://commons.apache.org/proper/commons-io/ Age Filter: https://commons.apache.org/proper/commons-io/javadocs/api-1.4/org/apache/commons/io/filefilter/AgeFileFilter.html JGit User Guide: http://wiki.eclipse.org/JGit/User_Guide JGit Repository access: http://www.codeaffine.com/2014/09/22/access-git-repository-with-jgit/

Continue ReadingDeleting SUSI Skills from Server