Author: harshit98

Susper is being improved every day. Following every best practice in the organization, each pull request includes a working demo link of the fix. Currently, the demo link for Susper can be generated by using GitHub pages by running these simple commands – ng build and npm run deploy. Sometimes this process on slow-internet connectivity takes up to 30 mins to generate a working demo link of the fix.

Surge is the technology which publishes or generates the static web-page demo link, which makes it easier for the developer to deploy their web-app. There are a lot of benefits of using surge over generating demo link using GitHub pages:

As soon as the pull request passes Travis CI, the deployment link is generated. It has been set up as such, no extra terminal commands will be required.

A lot of work has been done on making Susper, a wonderful search-engine and still more work have to be done on it. To become a good competitor in the market, one should make their website UI design such that:

It should be eye-catching for the users on the first-time visit to the website.

It should be easy to use with simple UI features rather than having more complex UI features.

We have been more oriented towards the material design. We have used Bootstrap technology for designing UI. Earlier, we proposed an idea of creating a UI using Angular Material v2 but it was dropped due to time limitations and other issue priorities.

To make Susper a better competitor in the market, we made sure it should be responsive as well on the following devices:

Mobile screen devices:

320px – Smaller screen size.

375px – Medium screen size.

425px – Larger screen size.

Tablets:

768px – default screen size for tablets.

Laptops:

1024px – Smaller screen size.

1440px – Larger screen size.

4K:

2560px – Default screen size.

We targeted these devices using @media queries in CSS3. For e.g. if I want to make a site responsive for the mobile devices, I will be using:

Here, min-width: 320px means that the screen size should be greater than and equal to 320px and max-width: 425px means that the screen size should be less than and equal to 425px.

It is not necessary to use only these dimensions. Suppose if there is break in UI design between 320px and 425px then, one can add that screen size using @media query. In this case, nested @media queries play a quite good role.

The YaCy Grid is the second-generation implementation of YaCy, a peer-to-peer search engine. A YaCy Grid installation consists of a set of micro-services which communicate with each other using a common infrastructure for data persistence. The task was to deploy the second-generation of YaCy Grid. To do so, we first had created a Dockerfile. This dockerfile should start the micro services such as rabbitmq, Apache ftp and elasticsearch in one docker instance along with MCP. The microservices perform following tasks:

start.sh will first add username and then password. Then it will start RabbitMQ along with Apache FTP. For username and password, we have created a separate files to configure their properties during Docker run which can be found here:

Susper has been provided ‘Advanced Search’ feature which provides the user a great experience to search for desired results. Advanced search has been implemented in such a way it shows top authors, top providers, and distribution regarding protocols. Users can choose any of these options to get best results.

The main logic has been implemented under advancedsearch.component.ts:

exportclassAdvancedsearchComponentimplementsOnInit{ querylook={};// array of urls navigation$:Observable<any>; selectedelements:Array<any>=[];// selected urls by userchangeurl(modifier,element){// based on query urls are fetched// if an url is selected by user, it is decoded this.querylook[‘query’]=this.querylook[‘query’]+‘+’+decodeURIComponent(modifier); this.selectedelements.push(element);// according to selected urls// results are loaded from yacy this.route.navigate([‘/search’],{queryParams: this.querylook});}

// same method is implemented for removing an urlremoveurl(modifier){ this.querylook[‘query’]=this.querylook[‘query’].replace(‘+’+decodeURIComponent(modifier),”);

this.route.navigate([‘/search’],{queryParams: this.querylook});}

The changeurl() functionreplaces the query with a query and selected URL and searches for the results only from the URL provider. The removeurl() function removes URL from the query and works as a normal search, searching for the results from all providers.

Susper has been given ‘Sort By Date’ feature which provides the user with latest results with the latest date. This feature enhances the search experience and helps users to find desired results more accurately. The sorting of results date wise is done by yacy backend which uses Apache Solr technology.

The idea was to create a ‘Sort By Date’ feature similar to the market leader. For example, if a user searches for keyword ‘Jaipur’ then results appear to be like this:

If a user wishes to get latest results, they can use ‘Sort By Date’ feature provided under ‘Tools’.

The above screenshot shows the sorted results.

You may however notice that results are not arranged year wise. Currently, the backend work for this is being going on Yacy and soon will be implemented on the frontend as well once backend provide us this feature.

Under ‘Tools’ we created an option for ‘Sort By Date’ simply using <li> tag.

Earlier we were using ‘last_modified desc’ attribute provided by Solr for sorting out dates in descending order. In June 2017, this feature was deprecated with a new update of Solr. We are using /date attribute in query for sorting out results which is being provided by Solr.

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.

Then under @Injectable we created a class for the SpeechSynthesisService.

export class SpeechSynthesisService{ utterence: any; constructor(privatezone:NgZone){} speak(text:string):void{ const{SpeechSynthesisUtterance}:IWindow=<IWindow>window; const{speechSynthesis }:IWindow=<IWindow>window; this.utterence=newSpeechSynthesisUtterance(); 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 (windowasany).speechSynthesis.speak(this.utterence);}// to pause the queue of utterencepause():void{ const{speechSynthesis}:IWindow=<IWindow>window;const { SpeechSynthesisUtterance }: IWindow =<IWindow>window; this.utterence=newSpeechSynthesisUtterance(); (windowasany).speechSynthesis.pause(); }}

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.

Susper has been given a voice search feature through which it provides a user with a better experience of search. We introduced to enhance the speech-recognition user interface by adding transition effects. The transition effect was required to display appropriate messages according to voice being detected or not. The following messages were:

When a user should start a voice search, it should display ‘Speak Now’ message for 1-2 seconds and then show up with message ‘Listening…’ to acknowledge user that now it is ready to recognize the voice which will be spoken.

If a user should do not speak anything, it should display ‘Please check audio levels or your microphone working’ message in 3-4 seconds and should exit the voice search interface.

The idea of speech UI was taken from the market leader and it was implemented in a similar way. On the homepage, it looks like this:

ngOnInit() { this.timer=Observable.timer(1500,2000); this.subscription=this.timer.subscribe(t=>{ this.ticks=t;// it will throw listening message after 1.5 sec if(t===1){ this.message=“Listening…”; }// subsequent events will be performed in 2 secs interval // as it has been defined in timer() if(t===4){ this.message=“Pleasecheckyourmicrophoneaudiolevels.”; this.miccolor=‘#C2C2C2’;}// if no voice is given, it will throw audio level message// and unsubscribe to the event to exit back on homepage if(t===6){ this.subscription.unsubscribe(); this.store.dispatch(newspeechactions.SearchAction(false)); } });}

The above code will throw following messages at a particular time. For creating the text-animation effect, most developers go for plain javascript. The text-animation effects can also be achieved by using pure CSS.

@keyframes specifies animation code. Here width: 0; tells that animation begins from 0% width and ends to 100% width of the message. Also, animation-delay: 3.5s has been adjusted w.r.t timer to display messages with animation at the same time.

Recently, we have implemented intelligence feature in Susper using SUSI chat API to provide users answer a question without going deeper in search results. When a user types “height of Trump”, it shows answer like this:

Problem which we faced after implementing the feature:

When a user was erasing a query or query field was empty, Susper was still showing the answer of the intelligence component like this:

The answer should not be displayed when a query is empty because the user is not asking any question. The answer was still displayed because it had received a response from SUSI API.

How did we solve the problem?

The problem was solved in two ways.

By using if/else condition: We checked if the statement shown inside the component is similar to the if-and-else condition. If the condition is true, it should hide the component.

Using [hidden] attribute method: The Angular 4 supports [hidden] attribute which acts as { display:none; } . [hidden] attribute generally works as ngShow and ngHide which was earlier supported by Angular 2.

We preferred both the methods to solve the problem. The intelligence component is being loaded inside results component using <app-intelligence> element. Further, we added [hidden] attribute to this element like this :

<app–intelligence [hidden]=“hideIntelligence”></app-intelligence>

We created hideIntelligence as variable and assign it as boolean. To check if a query is empty, searchdata variable was used.

searchdata:any ={ query:‘ ‘, rows:10, start:0};

And then checked if a query is empty using if-else condition :

// checks if query is empty or erasedif(this.searchdata.query===‘ ‘){// display: none; is truethis.hideIntelligence=true;

}else {// display: none; is falsethis.hideIntelligence=false;}

Applying this solution, we succeeded in hiding the intelligence component. We would also had used *ngIf statement but we preferred using [hidden]. [hidden] modifies the display property. *ngIf is a structural directive which creates or destroys content inside DOM.

Earlier the Susper search box had a fixed dimension. When a user types in a query, the dimensions of the search box remained fixed. This approach resulted in several issues like:

Matching the dimensions of the search bar following the market leader.

When dimensions are dynamically changing, it should not disturb alignment w.r.t tabs in the results page.

What actually happens is, when a user enters a query, the search box quickly changes its dimensions when results appear. I will be discussing below how we achieved this goal.

On the home page, we created the dimensions of a search bar with 584 x 44 pixels.

On the results page, we created the dimensions of search bar 632 x 44 similar to market leader:

How we proceeded?

Susper is built on Angular v4.1.3. It automatically comes with a function ngOnInit() whenever a new component has been created. ngOnInit() is a part of life cycle hook in Angular 4 (in Angular 2 as well). The function is called up or initialized when the component is rendered completely. This was the key for changing dimensions of search bar dynamically as soon as a component is created.

What happens is when a user types a query on the homepage and hits enter then, results component is created. As soon as, it is created – ngOnInit() function is called.

The default dimensions of search bar have been provided as follows:

search-bar.component.css

#nav–group{ height:44px; width:584px;}

When the homepage loads up, dimensions by default are 584 x 44.

search-bar.component.ts

privatenavbarWidth:any;

ngOnInit() { this.navbarWidth=‘632px’;}

search-bar.component.html

We used [style.width] attribute to change the dimensions dynamically. Add this attribute inside input element.

I have created a container, in which images will be loaded from yacy server. Then I have created a grid with an equal number of rows and column. I have adjusted the height and width of rows and columns to obtain a grid which contains each division as a cell. The image will load inside the cell. Each cell consists of one image.

.grid{ padding–left: 80px;}

.container{ width: 100%; margin: 0; top: 0; bottom: 0; padding: 0;}

After implementing it, we were facing issues like cropping of the image inside a cell. So, to avoid cropping and maintain the image ratio we introduced .responsive-image class which will avoid cropping of images inside cell.