Adding Speech Component in Loklak Search

Speech recognition service for voice search is already embedded in Loklak. Now the idea is to use this service and create a new separate component for voice recognition with an interactive and user friendly interface. This blog will cover every single portion of an Angular’s redux based component from writing actions and reducers to the use of created component in other required components. Creating Action and Reducer Function The main idea to create an Action is to control the flow of use of Speech Component in Loklak Search. The Speech Component will be called on and off based on this Action. Here, the first step is to create speech.ts file in actions folder with the following code: import { Action } from '@ngrx/store'; export const ActionTypes = {    MODE_CHANGE: '[Speech] Change', }; export class SearchAction implements Action {    type = ActionTypes.MODE_CHANGE;    constructor(public payload: any) {} } export type Actions    = SearchAction;   In the above segment, only one action (MODE_CHANGE) has been created which is like a boolean value which is being returned as true or false i.e. whether the speech component is currently in use or not. This is a basic format to be followed in creating an Action which is being followed in Loklak Search. The next step would be to create speech.ts file in reducers folder with the following code: import { Action } from '@ngrx/store'; import * as speech from '../actions/speech'; export const MODE_CHANGE = 'MODE_CHANGE'; export interface State { speechStatus: boolean; } export const initialState: State = { speechStatus: false }; export function reducer(state: State = initialState, action: speech.Actions): State { switch (action.type) { case speech.ActionTypes.MODE_CHANGE: { const response = action.payload; return Object.assign({}, state, {speechStatus: response}); } default: { return state; } } } export const getspeechStatus = (state: State) => state.speechStatus;   It follows the format of reducer functions created in Loklak Search. Here, the main key point is the state creation and type of value it is storing i.e. State is containing a speechStatus of type boolean. Defining an initial state with speechStatus value false (Considering initially the Speech Component will not be in use). The reducer function a new state by toggling the input state based on the type of Action created above and it returns the input state by default. At last wrapping the state as a function and returning the state’s speechStatus value. Third and last step in this section would be to create a selector for the above reducer function in the root reducer index file. Import and add speech from speech reducer file into the general state in root reducer file. And at last export the created selector function for speech reducer. import * as fromSpeech from './speech'; export interface State { ... speech: fromSpeech.State; } export const getSpeechState = (state: State) => state.speech; export const getspeechStatus = createSelector( getSpeechState, fromSpeech.getspeechStatus); Creating Speech Component Now comes the main part to create and define the functioning of Speech Component. For creating the basic Speech Component, following command is used:…

Continue ReadingAdding Speech Component in Loklak Search

Adding ‘Voice Search’ Feature in Loklak Search

It is beneficial to have a voice search feature embedded in a search engine like loklak.org based on PWA (Progressive Web Application) architecture. This will allow users to make query using voice on phone or computer. For integrating voice search, JavaScript Web Speech API (also known as webkitSpeechRecognition) is used which allows us to add speech recognition feature in any website or a web application. Integration Process For using webkitSpeechRecognition, a separate typescript service is being created along with its relevant unit test speech.service.ts speech.service.spec.ts The main idea to implement the voice search was To create an injectable speech service. Write methods for starting and stopping voice record in it. Import and inject the created speech service into root app module. Use the created speech service into required HomeComponent and FeedHeaderComponent. Structure of Speech Service The speech service mainly consists of two methods record() method which accepts lang as string input which specifies the language code for speech recording and returns a string Observable.    record(lang: string): Observable<string> {            return Observable.create(observe => {                  const webkitSpeechRecognition }: IWindow = <IWindow>window;                  this.recognition = new webkitSpeechRecognition();                  this.recognition.continuous = true;                  this.recognition.interimResults = true;                  this.recognition.onresult = take => this.zone.run(()                             observe.next(take .results.item (take.results. length - 1). item(0). transcript);                  this.recognition .onerror = err => observe .error(err);                  this.recognition.onend = () => observe .complete();                  this.recognition.lang = lang;                  this.recognition.start( );         });      }   Using observe.complete() allows speech recognition action to stop when the user stops speaking. stoprecord() method which is used to stop the current instance of recording.  stoprecord() {        if (this.recognition) {            this.recognition.stop();        }    }   stop() method is used to stop the current instance of speech recognition. Using Speech Service in required Component In Loklak Search, the speech service have been included in two main components i.e. HomeComponent and FeedHeaderComponent. The basic idea of using the created speech service in these components is same. In the TypeScript (not spec.ts) file of the two components, firstly import the SpeechService and create its object in constructor. constructor( private speech: SpeechService ) { }   Secondly, define a speechRecognition() method and use the created instance or object of SpeechService in it to record speech and set the query as the recorded speech input. Here, default language has been set up as ‘en_US’ i.e. English.  stoprecord() {        if (this.recognition) {            this.recognition.stop();        }    }   After user clicks on speech icon, this method will be called and the recorded speech will be set as the query and there will be router navigation to the /search page where the result will be displayed. Resources George Ornbo (2014). Shapeshed: The HTML5 Speech Recognition API Glen Shires, Hans Wennborg (2012). W3C: Web Speech API Specification

Continue ReadingAdding ‘Voice Search’ Feature in Loklak Search

Implementation of Text-To-Speech Feature In Susper

Susper has been given a voice search feature through which it provides the user a better experience of search. We introduced to enhance the speech recognition by adding Speech Synthesis or Text-To-Speech feature. The speech synthesis feature should only work when a voice search is attempted. The idea was to create speech synthesis similar to market leader. Here is the link to YouTube video showing the demo of the feature: Video link In the video, it will show demo : If a manual search is used then the feature should not work. If voice search is used then the feature should work. For implementing this feature, we used Speech Synthesis API which is provided with Google Chrome browser 33 and above versions. window.speechSynthesis.speak(‘Hello world!’); can be used to check whether the browser supports this feature or not. First, we created an interface: interface IWindow extends Window {   SpeechSynthesisUtterance: any;   speechSynthesis: any; };   Then under @Injectable we created a class for the SpeechSynthesisService. export class SpeechSynthesisService {   utterence: any;  constructor(private zone: NgZone) { }  speak(text: string): void {   const { SpeechSynthesisUtterance }: IWindow = <IWindow>window;   const { speechSynthesis }: IWindow = <IWindow>window;  this.utterence = new SpeechSynthesisUtterance();   this.utterence.text = text; // utters text   this.utterence.lang = 'en-US'; // default language   this.utterence.volume = 1; // it can be set between 0 and 1   this.utterence.rate = 1; // it can be set between 0 and 1   this.utterence.pitch = 1; // it can be set between 0 and 1  (window as any).speechSynthesis.speak(this.utterence); }// to pause the queue of utterence pause(): void {   const { speechSynthesis }: IWindow = <IWindow>window; const { SpeechSynthesisUtterance }: IWindow = <IWindow>window;  this.utterence = new SpeechSynthesisUtterance();   (window as any).speechSynthesis.pause();  } }   The above code will implement the feature Text-To-Speech. The source code for the implementation can be found here: https://github.com/fossasia/susper.com/blob/master/src/app/speech-synthesis.service.ts We call speech synthesis only when voice search mode is activated. Here we used redux to check whether the mode is ‘speech’ or not. When the mode is ‘speech’ then it should utter the description inside the infobox. We did the following changes in infobox.component.ts: import { SpeechSynthesisService } from ‘../speech-synthesis.service’; speechMode: any; constructor(private synthesis: SpeechSynthesisService) { } this.query$ = store.select(fromRoot.getwholequery); this.query$.subscribe(query => {   this.keyword = query.query;   this.speechMode = query.mode; });   And we added a conditional statement to check whether mode is ‘speech’ or not. // conditional statement // to check if mode is ‘speech’ or not if (this.speechMode === ‘speech’) {   this.startSpeaking(this.results[0].description); } startSpeaking(description) {   this.synthesis.speak(description);   this.synthesis.pause(); } The source code for the implementation can be found here: https://github.com/fossasia/susper.com/commit/3624d504c4687c227016b4fea229c680ad80a613 Resources Getting started with the Speech Synthesis API. Web Apps that talk - Introduction to Speech Synthesis API.      

Continue ReadingImplementation of Text-To-Speech Feature In Susper

Implementing Voice Search In Susper (in Chrome only)

Last week @mariobehling opened up an issue to implement voice search in Susper. Google Chrome provides an API to integrate Speech recognition feature with any website. More about API can be read here: https://shapeshed.com/html5-speech-recognition-api/ The explanation might be in Javascript but it has been written following syntax of Angular 4 and Typescript. So, I created a speech-service including files: speech-service.ts speech-service.spec.ts Code for speech-service.ts: This is the code which will control the working of voice search. import { Injectable, NgZone } from '@angular/core'; import { Observable } from 'rxjs/Rx'; interface IWindow extends Window {   webkitSpeechRecognition: any; } @Injectable() export class SpeechService { constructor(private zone: NgZone) { } record(lang: string): Observable<string> {   return Observable.create(observe => {     const { webkitSpeechRecognition }: IWindow = <IWindow>window;     const recognition = new webkitSpeechRecognition();     recognition.continuous = true;     recognition.interimResults = true;     recognition.onresult = take => this.zone.run(() => observe.next(take.results.item(take.results.length - 1).item(0).transcript) );     recognition.onerror = err =>observe.error(err);     recognition.onend = () => observe.complete();     recognition.lang = lang;     recognition.start(); }); } } You can find more details about API following the link which I have provided above in starting. Here recognition.onend() => observe.complete() works as an important role here. Many developers forget to use it when working on voice search feature. It works like: whenever a user stops speaking, it will automatically understand that voice action has now been completed and the search can be attempted. And for this: speechRecognition() {   this.speech.record('en_US').subscribe(voice => this.onquery(voice)); } We have used speechRecognition() function. onquery() function is called when a query is entered in a search bar. Default language has been set up as 'en_US' i.e English. We also created an interface to link it with the API which Google Chrome provides for adding voice search feature on any website. I have also used a separate module by name NgZone. Now, what is NgZone? It is used as an injectable service for executing working inside or outside of the Angular zone. I won't go into detail about this module much here. More about it can be found on angular-docs website. We have also, implemented a microphone icon on search bar similar to Google. This is how Susper's homepage looks like now: This feature only works in Google Chrome browser and for Firefox it doesn't. So, for Firefox browser there was no need to show 'microphone' icon since voice search does not work Firefox. What we did simply use CSS code like this: @-moz-document url-prefix() {   .microphone {     display: none;   } } @-moz-document url-prefix() is used to target elements for Firefox browser only. Hence using, this feature we made it possible to hide microphone icon from Firefox and make it appear in Chrome. For first time users: To use voice search feature click on the microphone feature which will trigger speechRecognition() function and will ask you permission to allow your laptop/desktop microphone to detect your voice. Once allowing it, we're done! Now the user can easily, use voice search feature on Susper to search for a random thing.

Continue ReadingImplementing Voice Search In Susper (in Chrome only)