Implementing Version Control System for SUSI Skill CMS

SUSI Skill CMS now has a version control system where users can browse through all the previous revisions of a skill and roll back to a selected version. Users can modify existing skills and push the changes. So a skill could have been edited many times by the same or different users and so have many revisions. The version control functionalities help users to : Browse through all the revisions of a selected skill View the content of a selected revision Compare any two selected revisions highlighting the changes Option to edit and rollback to a selected revision. Let us visit SUSI Skill CMS and try it out. Select a skill Click on versions button A table populated with previous revisions is displayed Clicking on a single revision opens the content of that version Selecting 2 versions and clicking on compare selected versions loads the content of the 2 selected revisions and shows the differences between the two. Clicking on Undo loads the selected revision and the latest version of that skill, highlighting the differences and also an editor loaded with the code of the selected revision to make changes and save to roll back. How was this implemented? Firstly, to get the previous revisions of a selected skill, we need the skills meta data including model, group, language and skill name which is used to make an ajax call to the server using the endpoint : http://api.susi.ai/cms/getSkillHistory.json?model=MODEL&group=GROUP&language=LANGUAGE&skill=SKILL_NAME We create a new component SkillVersion and pass the skill meta data in the pathname while accessing that component. The path where SkillVersion component is loaded is /:category/:skill/versions/:lang . We parse this data from the path and set our state with skill meta data. In componentDidMount we use this data to make the ajax call to the server to get all previous version data and update our state. A sample response from getSkillHistory endpoint looks like : { "session": { "identity": { "type": "", "name": "", "anonymous": } }, "commits": [ { "commitRev": "", "author_mail": "AUTHOR_MAIL_ID", "author": "AUTOR_NAME", "commitID": "COMMIT_ID", "commit_message": "COMMIT_MESSAGE", "commitName": "COMMIT_NAME", "commitDate": "COMMIT_DATE" }, ], "accepted": TRUE/FALSE } We now populate the table with the obtained revision history. We used Material UI Table for tabulating the data. The first 2 columns of the table have radio buttons to select any 2 revisions. The left side radio buttons are for selecting the older versions and the right side radio buttons to select the more recent versions. We keep track of the selected versions through onCheck function of the radio buttons and updating state accordingly. if(side === 'right'){ if(!(index >= currLeft)){ rightChecks.fill(false); rightChecks[index] = true; currRight = index; } } else if(side === 'left'){ if(!(index <= currRight)){ leftChecks.fill(false); leftChecks[index] = true; currLeft = index; } } this.setState({ currLeftChecked: currLeft, currRightChecked: currRight, leftChecks: leftChecks, rightChecks: rightChecks, }); Once 2 versions are selected and we click on compare selected versions button, we get the currently selected versions stored from getCheckedCommits function and we are redirected to /:category/:skill/compare/:lang/:oldid/:recentid where we pass the selected 2…

Continue ReadingImplementing Version Control System for SUSI Skill CMS

Making Skill Display Cards Identical in SUSI.AI Skill CMS

SUSI.AI Skill CMS shows all the skills of SUSI.AI. The cards used to display all the skills follow flexbox structure and adjust their height according to content. This lead to cards of different sizes and this needed to be fixed. This needed to fix as the cards looked like this: The cards display following things: Image related to skill An example query related to skill in double quotes Name of skill Short description of skill Now to get all these, we make an ajax call to the following endpoint: http://api.susi.ai/cms/getSkillList.json?model='+ this.state.modelValue + '&group=' + this.state.groupValue + '&language=' + this.state.languageValue Explanation: this.state.modelValue: This is the model of the skill, stored in state of component this.state.groupValue: This represents the group to which skill belongs to. For example Knowledge, Communication, Music, and Audio, etc. this.state.languageValue: This represents the ISO language code of language in which skill is defined Now the response is in JSONP format and it looks like: Now we parse the response to get the information needed and return the following Card(Material UI Component): <Link key={el} to={{ pathname: '/' + self.state.groupValue + '/' + el + '/' + self.state.languageValue, state: { url: url, element: el, name: el, modelValue: self.state.modelValue, groupValue: self.state.groupValue, languageValue: self.state.languageValue, } }}> <Card style={styles.row} key={el}> <div style={styles.right} key={el}> {image ? <div style={styles.imageContainer}> <img alt={skill_name} src={image} style={styles.image} /> </div> : <CircleImage name={el} size='48' />} <div style={styles.titleStyle}>{examples}</div> </div> <div style={styles.details}> <h3 style={styles.name}>{skill_name}</h3> <p style={styles.description}>{description}</p> </div> </Card> </Link> Now the information that leads to non-uniformity in these cards is the skill description. Now to solve this we decided to put a certain limit to the description length and if that limit is crossed, then we will show the following dots: “...”. The height and width of the cards were fixed according to screen size and we modified the description as follows: if (skill.descriptions) { if (skill.descriptions.length > 120) { description = skill.descriptions.substring(0, 119) + '...'; } else { description = skill.descriptions; } } This way no content was being cut and all the skill cards looks identical: Resources: JavaScript Substring function: https://www.w3schools.com/jsref/jsref_substring.asp Ajax guide on MDN: https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started Material UI Card: http://www.material-ui.com/#/components/card CSS Flexbox tutorial : https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Continue ReadingMaking Skill Display Cards Identical in SUSI.AI Skill CMS

Implementing Author’s Skill Page in SUSI.AI CMS

SUSI.AI Skill CMS is improving every day and we keep adding new features to it. Recently a feature was added to display all the skills by an author. This feature only showed the list of skills. The user might want to visit the skill page to see the description so we linked the skills on the list to skill page. The list looked like this: We need to link skill name and image to respective skill page. Now since this is react based app, we do not have different URL for different skills due to SPA. The description, images and other relevant details of skills were being passed as props. We needed to have routes through which we can directly access the skill. This was done by implementing child routes for Skill CMS. Earlier the description, images, and other relevant data was being passed as props from the BrowseSkill component, but now we need to derive this from the URL: let baseUrl = 'http://api.susi.ai/cms/getSkillMetadata.json'; let modelValue = "general"; this.name = this.props.location.pathname.split('/')[2]; this.groupValue = this.props.location.pathname.split('/')[1]; this.languageValue = this.props.location.pathname.split('/')[3]; url = baseUrl + '?model=' + modelValue + '&group=' + this.groupValue + '&language=' + this.languageValue + '&skill=' + this.name; We now make an ajax call to this URL for fetching the data: $.ajax({ url: url, jsonpCallback: 'pc', dataType: 'jsonp', jsonp: 'callback', crossDomain: true, success: function (data) { self.updateData(data.skill_metadata) } }); This updates the skill page with the description, image, author and other relevant details of the skills. Now all left to do is link the skills on the list to their respective links. This is done by following code: We define skillURL as: let skillURL = 'http://skills.susi.ai/' + parse[6] + '/' + parse[8].split('.')[0] + '/' + parse[7]; Here parse is an array which contains model, group and ISO language code of the skill. We updated the Image and text component as: <a href={skillURL} > <Img style={imageStyle} src={[ image1, image2 ]} unloader={<CircleImage name={name} size="40"/>} /> </a> <a href={skillURL} className="effect-underline" > {name} </a> Now after proper styling, we had the following looking skill list by author: Resources Ajax guide: https://developer.mozilla.org/en/docs/AJAX Javascript split function: https://www.w3schools.com/jsref/jsref_split.asp Gettings skills by an author in SUSI.AI Skill CMS: https://blog.fossasia.org/getting-skills-by-an-author-in-susi-ai-skill-cms/ Using CSS hover effects: http://www.codeitpretty.com/2013/06/how-to-use-css-hover-effects.html

Continue ReadingImplementing Author’s Skill Page in SUSI.AI CMS

Implementing Internationalization with Weblate Integration on SUSI Web Chat

SUSI Web Chat supports different browser languages on the Chat UI. The content used to render the date/time formats and the text is translated to the preferred language based on the language selected in the Language Settings. To test it out on SUSI Web Chat,  Head over to http://chat.susi.ai Go to settings from the right dropdown. Set your preferred language inside Language Settings. Save and see the SUSI Chat render in the preferred language. To achieve Internationalization, a number of important steps are to be followed - The best approach to follow would be to use po/pot files and get the translated string from the files. The format of the files can be used as follows. This is a JSON Structure for Javascript Projects. (File : de.json) { "About":"About", "Chat":"Chat", "Skills":"Skills", "Settings":"Settings", "Login":"Login", "Logout":"Logout", "Themes": "Themes", }   2. After creating the valid po/pot files in the right formats, we create a component which shall translate our text in the selected language and will import that particular string from that po file. To make it easier in Javascript we are using the JSON files that we created here. 3. Our Translate.react.js component is a special component which shall return us only a <span> text which shall get the User’s preferred language from the store and import that particular po/pot file and match the key as text which is being passed to it and give us the translated text. The following code snippet explains the above sentences more precisely. changeLanguage = (text) => { this.setState({ text:text }) } // Here 'de' is the JSON file which we imported into this component componentDidMount() { let defaultPrefLanguage = this.state.defaultPrefLanguage; var arrDe = Object.keys(de); let text = this.state.text; if(defaultPrefLanguage!=='en-US'){ for (let key=0;key<arrDe.length;key++) { if (arrDe[key]===text) { this.changeLanguage(de[arrDe[key]]); } } } } render() { return <span>{this.state.text}</span> } 4. The next step is to bind all the text throughout our components into this <Translate text=” ”/> component which shall send us back the translated content. So any string in any component can be replaced with the following. <Translate text="About" /> Here the text “About” is being sent over to the Translate.react.js component and it is getting us the German translation of the string About from the file de.json. 5. We then render the Translated content in our Chat UI. (File: Translate.react.js)          About Weblate Weblate is a Web based translation tool with git integration supporting wide range of file formats and making it easy for translators to contribute. The translations should be kept within the same repository as source code and translation process should closely follow development. To know more about Weblate go to this link. Integrating SUSI Web Chat with Weblate First, we deploy Weblate on our localhost using the installation guide given in these docs. I used the pip installation guide for Weblate as mentioned in this link. After doing that we copy weblate/settings_example.py to weblate/settings.py. Then we configure settings.py and use the following command to migrate the settings. ./manage.py migrate Next step is to create…

Continue ReadingImplementing Internationalization with Weblate Integration on SUSI Web Chat

Auto Deployment of SUSI Web Chat on gh-pages with Travis-CI

SUSI Web Chat uses Travis CI with a custom build script to deploy itself on gh-pages after every pull request is merged into the project. The build system auto updates the latest changes hosted on chat.susi.ai. In this blog, we will see how to automatically deploy the repository on gh pages. To proceed with auto deploy on gh-pages branch, We first need to setup Travis for the project. Register on https://travis-ci.org/ and turn on the Travis for this repository. Next, we add .travis.yml in the root directory of the project. # Set system config sudo: required dist: trusty language: node_js # Specifying node version node_js: - 6 # Running the test script for the project script: - npm test # Running the deploy script by specifying the location of the script, here ‘deploy.sh’ deploy: provider: script script: "./deploy.sh" # We proceed with the cache if there are no changes in the node_modules cache: directories: - node_modules branches: only: - master To find the code go to https://github.com/fossasia/chat.susi.ai/blob/master/.travis.yml The Travis configuration files will ensure that the project is building for every change made, using npm test command, in our case, it will only consider changes made on the master branch. If one wants to watch other branches one can add the respective branch name in travis configurations. After checking for build passing we need to automatically push the changes made for which we will use a bash script. #!/bin/bash SOURCE_BRANCH="master" TARGET_BRANCH="gh-pages" # Pull requests and commits to other branches shouldn't try to deploy. if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then echo "Skipping deploy; The request or commit is not on master" exit 0 fi # Save some useful information REPO=`git config remote.origin.url` SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:} SHA=`git rev-parse --verify HEAD` ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy_key.enc -out ../deploy_key -d chmod 600 ../deploy_key eval `ssh-agent -s` ssh-add ../deploy_key # Cloning the repository to repo/ directory, # Creating gh-pages branch if it doesn't exists else moving to that branch git clone $REPO repo cd repo git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH cd .. # Setting up the username and email. git config user.name "Travis CI" git config user.email "$COMMIT_AUTHOR_EMAIL" # Cleaning up the old repo's gh-pages branch except CNAME file and 404.html find repo/* ! -name "CNAME" ! -name "404.html" -maxdepth 1 -exec rm -rf {} \; 2> /dev/null cd repo git add --all git commit -m "Travis CI Clean Deploy : ${SHA}" git checkout $SOURCE_BRANCH # Actual building and setup of current push or PR. npm install npm run build mv build ../build/ git checkout $TARGET_BRANCH rm -rf node_modules/ mv ../build/* . cp index.html 404.html # Staging the new build for commit; and then committing the latest build git add -A git commit --amend --no-edit --allow-empty # Deploying only if the build has changed if [ -z `git diff --name-only HEAD HEAD~1` ]; then echo "No Changes in the Build; exiting" exit 0 else # There are changes in the Build; push the…

Continue ReadingAuto Deployment of SUSI Web Chat on gh-pages with Travis-CI

Implementing Skill Detail Section in SUSI Android App

SUSI Skills are rules that are defined in SUSI Skill Data repo which are basically the responses SUSI gives to the user queries. When a user queries something from the SUSI Android app, a query to SUSI Server is made which further fetches response from SUSI Skill Data and gives the response to the app. Similarly, when we need to list all skills, an API call is made to server to list all skills. The server then checks the SUSI Skill Data repo for the skills and then return all the required information to the app. Then the app displays all the information about the skill to user. User then can view details of each skill and then interact on the chat interface to use that skill. This process is similar to what SUSI Skill CMS does. The CMS is a skill wiki like interface to view all skills and then edit them. Though the app can not be currently used to edit the skills but it can be used to view them and try them on the chat interface. API Information For listing SUSI Skill groups, we have to call on /cms/getGroups.json This will give you all groups in SUSI model in which skills are present. Current response: { "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }}, "accepted": true, "groups": [ "Small Talk", "Entertainment", "Problem Solving", "Knowledge", "Assistants", "Shopping" ], "message": "Success: Fetched group list" } So, the groups object gives all the groups in which SUSI Skills are located. Next comes, fetching of skills. For that the endpoint is /cms/getGroups.json?group=GROUP_NAME Since we want all skills to be fetched, we call this api for every group. So, for example we will be calling http://api.susi.ai/cms/getSkillList.json?group=Entertainment for getting all skills in group “Entertainment”. Similarly for other groups as well. Sample response of skill: { "accepted": true, "model": "general", "group": "Shopping", "language": "en", "skills": {"amazon_shopping": { "image": "images/amazon_shopping.png", "author_url": "https://github.com/meriki", "examples": ["Buy a dress"], "developer_privacy_policy": null, "author": "Y S Ramya", "skill_name": "Shop At Amazon", "dynamic_content": true, "terms_of_use": null, "descriptions": "Searches items on Amazon.com for shopping", "skill_rating": null }}, "message": "Success: Fetched skill list", "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }} } It gives all details about skills: image author_url examples developer_privacy_policy author skill_name dynamic_content terms_of_use descriptions skill_rating Implementation in SUSI Android App Skill Detail Section UI of Google Assistant Skill Detail Section UI of SUSI SKill CMS Skill Detail Section UI of SUSI Android App The UI of skill detail section in SUSI Android App is the mixture of UI of Skill detail section in Google Assistant ap and SUSI Skill CMS. It displays details of skills in a beautiful manner with horizontal recyclerview used to display the examples. So, we have to display following details about the skill in Skill Detail Section: Skill Name Author Name Skill Image Try it Button Description Examples Rating Content type (Dynamic/Static) Terms of Use Developer’s Privacy policy Let’s see the implementation. 1. Whenever a skill Card View is clicked, showSkillDetailFragment()…

Continue ReadingImplementing Skill Detail Section in SUSI Android App

Link Preview Service from SUSI Server

 SUSI Webchat, SUSI Android app, SUSI iOS app are various SUSI clients which depend on response from SUSI Server. The most common response of SUSI Server is in form of links. Clients usually need to show the preview of the links to the user. This preview may include featured image, description and the title of the link.  Clients show this information by using various 3rd party APIs and libraries. We planned to create an API endpoint for this on SUSI Server to give the preview of the link. This service is called LinkPreviewService. String url = post.get("url", ""); if(url==null || url.isEmpty()){ jsonObject.put("message","URL Not given"); jsonObject.put("accepted",false); return new ServiceResponse(jsonObject); } This API Endpoint accept only 1 get parameter which is the URL whose preview is to be shown. Here we also check if no parameter or wrong URL parameter was sent. If that was the the case then we return an error message to the user. SourceContent sourceContent = TextCrawler.scrape(url,3); if (sourceContent.getImages() != null) jsonObject.put("image", sourceContent.getImages().get(0)); if (sourceContent.getDescription() != null) jsonObject.put("descriptionShort", sourceContent.getDescription()); if(sourceContent.getTitle()!=null)jsonObject.put("title", sourceContent.getTitle()); jsonObject.put("accepted",true); return new ServiceResponse(jsonObject); } The TextCrawler function accept two parameters. One is the url of the website which is to be scraped for the preview data and the other is depth. To get the images, description and title there are methods built in. Here we just call those methods and set them in our JSON Object. private String htmlDecode(String content) { return Jsoup.parse(content).text(); } Text Crawler is based on Jsoup. Jsoup is a java library that is used to scrape HTML pages. To get anything from Jsoup we need to decode the content of HTML to Text. public List<String> getImages(Document document, int imageQuantity) { Elements media = document.select("[src]"); while(var5.hasNext()) { Element srcElement = (Element)var5.next(); if(srcElement.tagName().equals("img")) { ((List)matches).add(srcElement.attr("abs:src")); } }  The getImages method takes the HTML document from the JSoup and find the image tags in that. We have given the imageQuantity parameter in the function, so accordingly it returns the src attribute of the first n images it find. This API Endpoint can be seen working on http://127.0.0.1:4000/susi/linkPreview.json?url=<ANY URL> A real working example of this endpoint would be http://api.susi.ai/susi/linkPreview.json?url=https://techcrunch.com/2017/07/23/dear-tech-dudes-stop-being-such-idiots-about-women/ Resources: Web Crawlers: https://www.promptcloud.com/data-scraping-vs-data-crawling/ JSoup: https://jsoup.org/ JSoup Api Docs: https://jsoup.org/apidocs/ Parsing HTML with JSoup: http://www.baeldung.com/java-with-jsoup

Continue ReadingLink Preview Service from SUSI Server

Fetching Images for RSS Responses in SUSI Web Chat

Initially, SUSI Web Chat rendered RSS action type responses like this: The response from the server initially only contained Title Description Link We needed to improvise the web search & RSS results display and also add images for the results. The web search & RSS results are now rendered as : How was this implemented? SUSI AI uses Yacy to fetchRSSs feeds. Firstly the server using the console process to return the RSS feeds from Yacy needs to be configured to return images too. "yacy":{ "example":"http://127.0.0.1:4000/susi/console.json?q=%22SELECT%20title,%20link%20FROM%20yacy%20WHERE%20query=%27java%27;%22", "url":"http://yacy.searchlab.eu/solr/select?wt=yjson&q=", "test":"java", "parser":"json", "path":"$.channels[0].items", "license":"" } In a console process, we provide the URL needed to fetch data from, the query parameter needed to be passed to the URL and the path to look for the answer in the API response. url = <url>   - the URL to the remote JSON service which will be used to retrieve information. It must contain a $query$ string. test = <parameter> - the parameter that will replace the $query$ string inside the given URL. It is required to test the service. Here the URL used is : http://yacy.searchlab.eu/solr/select?wt=yjson&q=QUERY To include images in RSS action responses, we need to parse the images also from the Yacy response. For this, we need to add `image` in the selection rule while calling the console process "process":[ { "type":"console", "expression":"SELECT title,description,link FROM yacy WHERE query='$1$';" } ] Now the response from the server for RSS action type will also include `image` along with title, description, and link. An example response for the query `Google` : { "title": "Terms of Service | Google Analytics \u2013 Google", "description": "Read Google Analytics terms of service.", "link": "http://www.google.com/analytics/terms/", "image": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png", } However, the results at times, do not contain images because there are none stored in the index. This may happen if the result comes from p2p transmission within Yacy where no images are transmitted. So in cases where images are not returned by the server, we use the link preview service to preview the link and fetch the image. The endpoint for previewing the link is : BASE_URL+'/susi/linkPreview.json?url=URL' On the client side, we first search the response for data objects with images in API actions. And the amongst the remaining data objects in answers[0].data, we preview the link to fetch image keeping a check on the count. This needs to be performed for processing the history cognitions too.To preview the remaining links in a loop, we cannot make ajax calls directly in a loop. To handle this, nested ajax calls are made using the function previewURLForImage() where we loop through the remaining links and on the success we decrement the count and call previewURLForImage() on the next link and on error we try previewURLForImage() on the next link without decrementing the count. success: function (rssResponse) { if(rssResponse.accepted){ respData.image = rssResponse.image; respData.descriptionShort = rssResponse.descriptionShort; receivedMessage.rssResults.push(respData); } if(receivedMessage.rssResults.length === count || j === remainingDataIndices.length - 1){ let message = ChatMessageUtils.getSUSIMessageData(receivedMessage, currentThreadID); ChatAppDispatcher.dispatch({ type: ActionTypes.CREATE_SUSI_MESSAGE, message }); } else{ j+=1; previewURLForImage(receivedMessage,currentThreadID, BASE_URL,data,count,remainingDataIndices,j); } }, And we store…

Continue ReadingFetching Images for RSS Responses in SUSI Web Chat

Implementing Text To Speech Settings in SUSI WebChat

SUSI Web Chat has Text to Speech (TTS) Feature where it gives voice replies for user queries. The Text to Speech functionality was added using Speech Synthesis Feature of the Web Speech API. The Text to Speech Settings were added to customise the speech output by controlling features like : Language Rate Pitch Let us visit SUSI Web Chat and try it out. First, ensure that the settings have SpeechOutput or SpeechOutputAlways enabled. Then click on the Mic button and ask a query. SUSI responds to your query with a voice reply. To control the Speech Output, visit Text To Speech Settings in the /settings route. First, let us look at the language settings. The drop down list for Language is populated when the app is initialised. speechSynthesis.onvoiceschanged function is triggered when the app loads initially. There we call speechSynthesis.getVoices() to get the voice list of all the languages currently supported by that particular browser. We store this in MessageStore using ActionTypes.INIT_TTS_VOICES action type. window.speechSynthesis.onvoiceschanged = function () { if (!MessageStore.getTTSInitStatus()) { var speechSynthesisVoices = speechSynthesis.getVoices(); Actions.getTTSLangText(speechSynthesisVoices); Actions.initialiseTTSVoices(speechSynthesisVoices); } }; We also get the translated text for every language present in the voice list for the text - `This is an example of speech synthesis` using google translate API. This is called initially for all the languages and is stored as translatedText attribute in the voice list for each element. This is later used when the user wants to listen to an example of speech output for a selected language, rate and pitch. https://translate.googleapis.com/translate_a/single?client=gtx&sl=en-US&tl=TARGET_LANGUAGE_CODE&dt=t&q=TEXT_TO_BE_TRANSLATED When the user visits the Text To Speech Settings, then the voice list stored in the MessageStore is retrieved and the drop down menu for Language is populated. The default language is fetched from UserPreferencesStore and the default language is accordingly highlighted in the dropdown. The list is parsed and populated as a drop down using populateVoiceList() function. let voiceMenu = voices.map((voice,index) => { if(voice.translatedText === null){ voice.translatedText = this.speechSynthesisExample; } langCodes.push(voice.lang); return( <MenuItem value={voice.lang} key={index} primaryText={voice.name+' ('+voice.lang+')'} /> ); }); The language selected using this dropdown is only used as the language for the speech output when the server doesn’t specify the language in its response and the browser language is undefined. We then create sliders using Material UI for adjusting speech rate and pitch. <h4 style={{'marginBottom':'0px'}}><Translate text="Speech Rate"/></h4> <Slider min={0.5} max={2} value={this.state.rate} onChange={this.handleRate} /> The range for the sliders is : Rate : 0.5 - 2 Pitch : 0 - 2 The default value for both rate and pitch is 1. We create a controlled slider saving the values in state and using onChange function to record change in values. The Reset buttons can be used to reset the rate and pitch values respectively to their default values. Once the language, rate and pitch values have been selected we can click on `Play a short demonstration of speech synthesis`  to listen to a voice reply with the chosen settings. { this.state.playExample && ( <VoicePlayer play={this.state.play} text={voiceOutput.voiceText} rate={this.state.rate} pitch={this.state.pitch} lang={this.state.ttsLanguage} onStart={this.onStart} onEnd={this.onEnd} /> ) }…

Continue ReadingImplementing Text To Speech Settings in SUSI WebChat

Implementation of Set Different Language for Query in SUSI Android

SUSI.AI has many skills. Some of which are displaying web search of a certain query, provide a list of relevant information of a topic, displaying a map of the certain position and simple text message of any query. Previously SUSI.AI reply all query in English language but now one important feature is added in SUSI.AI and that feature is, reply query of the user in the language that user wants. But to get the reply in different language user has to send language code of that language along with query to SUSI Server. In this blog post, I will show you how it is implemented in SUSI Android app. Different language supported in SUSI Android Currently, different languages added in option in SUSI Android and their language code are: Language Language Code English en German de Spanish es French fr Italian it Default Default language of the device. Layout design I added an option for choosing the different language in settings. When the user clicks on Language option a dialog box pops up. I used listpreference to show the list of different languages. <ListPreference   android:title="@string/Language"   android:key="Lang_Select"   android:entries="@array/languagentries"   android:entryValues="@array/languagentry"> </ListPreference> “title” is used to show the title of setting, “entries” is used to show the list of entry to the user and “entryValue” is the value corresponding to each entry. I used listpreference because it has own UI so we don‘t have to develop our own UI for it and also it stores the string into the SharedPreferences so we don’t need to manage the values in SharedPreference. SharedPreference needed to set value in Language in settings so that once user close app and again open it setting will show same value otherwise it will show default value. We used an array of string to show the list of languages. <string-array name="languagentries">   <item>Default</item>   <item>English</item>   <item>German</item>   <item>Spanish</item>   <item>French</item>   <item>Italian</item> </string-array> SetLanguage implementation To set language user must choose Language option in setting. On clicking Language option a dialog box pop up with the list of different languages. When the user chooses a language then we save corresponding language code in preference with key “prefLanguage” so that we can use it later to send it to the server along with the query. It also uses to send language to the server to store user language on the server, so that user can use the same language in the different client. querylanguage.setOnPreferenceChangeListener { _, newValue ->   PrefManager.putString(Constant.LANGUAGE, newValue.toString())   if(!settingsPresenter.getAnonymity()) {       settingsPresenter.sendSetting(Constant.LANGUAGE, newValue.toString(), 1)   } } newValue.toString() is the value i.e language code of corresponding language. Now when we query anything from SUSI.AI we send language code along with query to the server. Default language is default language of the device. Before sending language to the server we check language is default language or any specific language. val language = if (PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT).equals(Constant.DEFAULT)) Locale.getDefault().language else PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT) And after that, we send the corresponding language along with query to the server. clientBuilder.susiApi.getSusiResponse(timezoneOffset, longitude, latitude, source, language, query) Reference Main site link of listpreference: https://developer.android.com/reference/android/preference/ListPreference.html Tutorial…

Continue ReadingImplementation of Set Different Language for Query in SUSI Android