[recommendations-funcionality | WIP] moved rec services and components to openaireLibrary, progress on item-to-item recs for landings

This commit is contained in:
Alex Martzios 2024-06-14 14:11:03 +03:00
parent e80df9f3b0
commit 2b12959a4e
7 changed files with 217 additions and 20 deletions

View File

@ -19,13 +19,6 @@
<div *ngIf="!showFeedback" class="uk-grid uk-margin-remove-left" uk-grid>
<!-- center box-->
<div id="landing-center-content" class="uk-width-expand uk-padding-remove uk-background-default">
<!-- back button for fc4eosc -->
<div *ngIf="!showLoading && resultLandingInfo && sessionStorage?.previousPage == 'fc4eosc'" class="uk-container uk-container-xlarge uk-margin-top uk-margin-left">
<a class="uk-button uk-button-link uk-flex uk-flex-middle" (click)="goBack();">
<icon [name]="'west'" [flex]="true" [ratio]="1"></icon>
<span class="uk-margin-small-left">Back</span>
</a>
</div>
<ng-template #graph_and_feedback_template>
<div class="uk-padding-xsmall">
@ -61,7 +54,7 @@
</div>
</div>
<div *ngIf="!showLoading && resultLandingInfo" class="uk-margin-bottom" [class.uk-margin-top]="!(sessionStorage?.previousPage == 'fc4eosc')">
<div *ngIf="!showLoading && resultLandingInfo" class="uk-margin-top uk-margin-bottom">
<div class="uk-flex uk-flex-middle uk-flex-center">
<div class="landing-action-bar uk-box-shadow-small uk-margin-bottom">
<div class="uk-grid uk-grid-small uk-flex-between uk-text-xsmall uk-flex-middle uk-grid-divider" uk-grid>
@ -984,8 +977,29 @@
<ng-template #recommended_content>
<div class="uk-flex uk-flex-middle uk-margin-medium-bottom">
<icon [name]="'recommendations'" [flex]="true" [ratio]="1.5"></icon>
<span class="uk-text-bold uk-margin-left">Recommended for you</span>
<span class="uk-text-bold uk-margin-left">Recommended results</span>
</div>
<ng-container *ngIf="recommendationError">
<div class="uk-height-small uk-flex uk-flex-center uk-flex-middle">
<div class="uk-animation-fade uk-text-meta uk-text-large">
{{recommendationError}}
</div>
</div>
</ng-container>
<ng-container *ngIf="recommendedResults && recommendedResults.length == 0">
<div class="uk-height-small uk-flex uk-flex-center uk-flex-middle">
<div class="uk-animation-fade uk-text-meta uk-text-large">
No recommendations found.
</div>
</div>
</ng-container>
<ng-container *ngIf="recommendedResults && recommendedResults.length">
<div class="uk-grid uk-child-width-1-3@m" uk-height-match=".uk-card" uk-grid>
<div *ngFor="let result of recommendedResults">
<recommendation-card [result]="result"></recommendation-card>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #metricsContent>

View File

@ -29,7 +29,7 @@ import {FullScreenModalComponent} from "../../utils/modal/full-screen-modal/full
import {SdgFosSuggestComponent} from '../landing-utils/sdg-fos-suggest/sdg-fos-suggest.component';
import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service";
import {ContextsService} from "../../claims/claim-utils/service/contexts.service";
import {RecommendationsService} from '../../../recommendations/recommendations.service';
import {RecommendationsService} from '../../recommendations/recommendations.service';
declare var ResizeObserver;
@ -40,7 +40,6 @@ declare var ResizeObserver;
export class ResultLandingComponent {
public referrer: string;
public prevPath: string;
public sessionStorage = sessionStorage;
@Input() type: string = "publication";
@ -110,6 +109,7 @@ export class ResultLandingComponent {
// Message variables
public errorMessage = "";
public recommendationError = "";
public showLoading: boolean = true;
public routerHelper: RouterHelper = new RouterHelper();
@ -185,7 +185,9 @@ export class ResultLandingComponent {
public rightSidebarOffcanvasClicked: boolean = false;
public egiTransferModalOpen = false;
getRecommendationsForPublicationAPI: string = 'https://darelab.athenarc.gr/api/faircore/item-to-item-recommender/item_to_item/'
recommendedResults;
getRecommendationsForPublicationAPI: string = 'https://darelab.athenarc.gr/api/faircore/item-to-item-recommender/recommend/'
constructor(private _resultLandingService: ResultLandingService,
private _vocabulariesService: ISVocabulariesService,
@ -991,8 +993,16 @@ export class ResultLandingComponent {
}
private getRecommendations() {
this.subscriptions.push(this.recommendationsService.getRecommendationsForPublication(this.getRecommendationsForPublicationAPI, 'enermaps', this.resultLandingInfo.objIdentifier).subscribe(data => {
console.log(data);
this.recommendationError = null;
this.subscriptions.push(this.recommendationsService.getRecommendationsForPublication(this.getRecommendationsForPublicationAPI, this.resultLandingInfo.objIdentifier).subscribe(data => {
this.recommendedResults = data;
}, error => {
console.log(error);
if(error.status == 404) {
this.recommendationError = "No recommendations found.";
} else {
this.recommendationError = "Sorry, something went wrong.";
}
}));
}
@ -1229,8 +1239,4 @@ export class ResultLandingComponent {
return "https://"+(this.properties.environment == "beta" ? "beta." : "")+"search.marketplace.eosc-portal.eu/";
}
}
public goBack() {
window.history.back();
}
}

View File

@ -39,7 +39,8 @@ import {EntityActionsModule} from "../../utils/entity-actions/entity-actions.mod
import {ResultLandingRoutingModule} from "./resultLanding-routing.module";
import {OrcidCoreModule} from "../../orcid/orcid-core.module";
import {SearchTabModule} from "../../utils/tabs/contents/search-tab.module";
import {RecommendationsService} from '../../../recommendations/recommendations.service';
import {RecommendationsService} from '../../recommendations/recommendations.service';
import {RecommendationCardModule} from '../../recommendations/recommendation-card.module';
@NgModule({
imports: [
@ -50,7 +51,7 @@ import {RecommendationsService} from '../../../recommendations/recommendations.s
DeletedByInferenceModule, ShowAuthorsModule, HelperModule, ResultLandingUtilsModule, AlertModalModule,
LandingHeaderModule, NoLoadPaging, ResultPreviewModule, FeedbackModule, TabsModule, LoadingModule,
OrcidCoreModule, IconsModule, InputModule, EGIDataTransferModule, RecaptchaModule,
SdgFosSuggestModule, FullScreenModalModule, SafeHtmlPipeModule, EntityActionsModule
SdgFosSuggestModule, FullScreenModalModule, SafeHtmlPipeModule, EntityActionsModule, RecommendationCardModule
],
declarations: [
ResultLandingComponent

View File

@ -0,0 +1,50 @@
import {Component, Input} from "@angular/core";
import {EnvProperties} from "../utils/properties/env-properties";
import {properties} from "src/environments/environment";
import {RecommendationsService} from "./recommendations.service";
@Component({
selector: 'recommendation-card',
template: `
<a [routerLink]="properties.searchLinkToResult.split('?')[0]" [queryParams]="{'id': removePrefix(result.result_id)}"
(click)="category && result && community ? selectResult(category, result, community) : ''" class="uk-link-reset" target="_blank">
<div class="uk-card uk-card-default uk-card-hover uk-text-xsmall uk-padding-small">
<ng-container *ngIf="result.result_title">
<div class="multi-line-ellipsis lines-2">
<span class="uk-text-small uk-text-bold">{{result.result_title}}</span>
</div>
<hr *ngIf="result.result_publisher || result.result_publication_date || result.result_country || result.result_authors">
</ng-container>
<div *ngIf="result.result_publisher" class="uk-text-truncate"><span class="uk-text-meta">Publisher:</span> {{result.result_publisher}}</div>
<div *ngIf="result.result_publication_date" class="uk-text-truncate"><span class="uk-text-meta">Date:</span> {{result.result_publication_date}}</div>
<div *ngIf="result.result_country" class="uk-text-truncate"><span class="uk-text-meta">Country:</span> {{result.result_country}}</div>
<div *ngIf="result.result_authors" class="uk-text-truncate"><span class="uk-text-meta">Authors:</span> {{result.result_authors}}</div>
</div>
</a>
`
})
export class RecommendationCardComponent {
private subscriptions = [];
properties: EnvProperties = properties;
@Input() result;
@Input() category;
@Input() community;
giveFeedbackForRecommendationAPI: string = 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/update/';
constructor(private recommendationsService: RecommendationsService) {
}
selectResult(item, result, community) {
this.subscriptions.push(this.recommendationsService.giveFeedbackForRecommendation(this.giveFeedbackForRecommendationAPI, community, item.field, result.result_id).subscribe(data => {
// console.log(data);
}));
}
removePrefix(str: string) {
return str.substring(str.indexOf("|") + 1);
}
}

View File

@ -0,0 +1,24 @@
import {CommonModule} from "@angular/common";
import {NgModule} from "@angular/core";
import {RecommendationCardComponent} from "./recommendation-card.component";
import {RouterModule} from "@angular/router";
import {RecommendationsService} from "./recommendations.service";
@NgModule({
imports: [
CommonModule, RouterModule
],
declarations: [
RecommendationCardComponent
],
providers: [
RecommendationsService
],
exports: [
RecommendationCardComponent
]
})
export class RecommendationCardModule {
}

View File

@ -0,0 +1,8 @@
export class Recommendation {
id: string;
title: string;
country: string;
authors: string;
publisher: string;
date: string;
}

View File

@ -0,0 +1,94 @@
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {Injectable} from "@angular/core";
import {Recommendation} from "./recommendation";
import {map} from "rxjs/operators";
@Injectable()
export class RecommendationsService {
constructor(private http: HttpClient) {
}
getAvailableCommunities(url: string) {
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.get(url, options);
}
getRecommendationsForCommunity(url: string, communityId: string) {
const body = {
"community": communityId,
};
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post(url, body, options)
}
giveFeedbackForRecommendation(url: string, communityId: string, category: string, doi: string) {
const body = {
"category": category,
"community": communityId,
"publication": doi,
};
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post(url, body, options);
}
getRecommendationsForPublication(url: string, id: string) {
const body = {
"num": 6,
"result_id": "50|" + id
// "result_id": "50|doi_dedup___::b0c1c7d86521ca2cce50610e8f61fa04"
};
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post(url, body, options);
}
getRecommendationsForOrcid(url: string, id: string) {
const body = {
"author_id": id,
// the one below returns 500 internal server error
// "author_id": "0009-0003-3633-2226"
}
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post(url, body, options);
}
// parseRecommendations(data: any): Recommendation[] {
// const recommendations: Recommendation[] = [];
// const length = Array.isArray(data) ? data.length : 1;
// for (let i = 0; i < length; i++) {
// const resData = Array.isArray(data) ? data[i] : data;
// const recommendation: Recommendation = new Recommendation();
// recommendation['id'] = resData.result_id;
// recommendation['title'] = resData.result_title;
// recommendation['country'] = resData.result_country;
// recommendation['authors'] = resData.result_authors;
// recommendation['publisher'] = resData.result_publisher;
// recommendation['date'] = resData.result_publication_date;
// recommendations.push(recommendation);
// }
// return recommendations;
// }
}