diff --git a/.vscode/settings.json b/.vscode/settings.json index b9398da1e02c97e522fc69e2b4e9392d5aa1664e..81b3e0aefe0560c1efa3d9d6e5e9198145320993 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,7 +11,8 @@ } }, "python.testing.pytestArgs": [ - "tests" + "tests", + "-s" ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true diff --git a/project/recommendation/api_models/api_models.py b/project/recommendation/api_models/api_models.py index 94886587706e31414bcaeda8d1ae1fdaf76fd9c2..9d34c50ce56ba6e43c615e8056296a697ab13616 100644 --- a/project/recommendation/api_models/api_models.py +++ b/project/recommendation/api_models/api_models.py @@ -1,7 +1,9 @@ from dataclasses import dataclass -from typing import List +from typing import List, Optional + +from project.dalia.api_models.api_models import Item @dataclass class SuggestedContents: - uris: List[str] + results: Optional[List[Item]] diff --git a/project/recommendation/materials/suggested_content.py b/project/recommendation/materials/suggested_content.py index 89015a88dbe87c0558fe17793feec88fca64e589..6c5754e92360e95a20ac7fafe2b78a0244e6f8ad 100644 --- a/project/recommendation/materials/suggested_content.py +++ b/project/recommendation/materials/suggested_content.py @@ -1,11 +1,13 @@ +from typing import Set from uuid import UUID from rdflib import URIRef, Variable +from project.dalia.query.items.metadata.items import get_metadata_for_learning_resources from project.dalia.query.utils import query_dalia_dataset from project.dalia.query_builder.query_builder import QueryBuilder +from project.dalia.rdf.dalia_kb import _LEARNING_RESOURCE_BASE_URI from project.dalia.rdf.namespace import SCHEMA, MoDalia, fabio -from project.dalia.rdf.prefix import LEARNING_RESOURCE_BASE_URI from project.recommendation.api_models.api_models import ( SuggestedContents, ) @@ -15,9 +17,9 @@ def _get_shared_keywords(uuid: UUID): query = f""" PREFIX schema: <https://schema.org/> SELECT ?sub (COUNT(?sharedKeyword) AS ?keywordCount) WHERE {{ - <{LEARNING_RESOURCE_BASE_URI}{uuid}> schema:keywords ?sharedKeyword . + <{_LEARNING_RESOURCE_BASE_URI}{uuid}> schema:keywords ?sharedKeyword . ?sub schema:keywords ?sharedKeyword . - FILTER(?sub != <{LEARNING_RESOURCE_BASE_URI}{uuid}>) + FILTER(?sub != <{_LEARNING_RESOURCE_BASE_URI}{uuid}>) }} GROUP BY ?sub HAVING(?keywordCount >= 2) @@ -34,7 +36,7 @@ def _get_is_part_of(uuid: UUID): .SELECT(var_material) .WHERE( ( - URIRef(f"{LEARNING_RESOURCE_BASE_URI}{uuid}"), + URIRef(f"{_LEARNING_RESOURCE_BASE_URI}{uuid}"), URIRef(URIRef(SCHEMA.NS + "isPartOf")), var_material, ) @@ -52,7 +54,7 @@ def _get_is_related_to(uuid: UUID): .SELECT(var_material) .WHERE( ( - URIRef(f"{LEARNING_RESOURCE_BASE_URI}{uuid}"), + URIRef(f"{_LEARNING_RESOURCE_BASE_URI}{uuid}"), URIRef(URIRef(MoDalia.NS + "isRelatedTo")), var_material, ) @@ -70,7 +72,7 @@ def _get_is_based_on(uuid: UUID): .SELECT(var_material) .WHERE( ( - URIRef(f"{LEARNING_RESOURCE_BASE_URI}{uuid}"), + URIRef(f"{_LEARNING_RESOURCE_BASE_URI}{uuid}"), URIRef(URIRef(MoDalia.NS + "isBasedOn")), var_material, ) @@ -88,14 +90,14 @@ def _get_authors(uuid: UUID): PREFIX m4i: <http://w3id.org/nfdi4ing/metadata4ing#> SELECT DISTINCT ?lr WHERE {{ - <{LEARNING_RESOURCE_BASE_URI}{uuid}> schema:author ?list. + <{_LEARNING_RESOURCE_BASE_URI}{uuid}> schema:author ?list. ?list arq:member ?member. ?member a ?type. ?member m4i:orcidId ?id. ?lr schema:author ?newlist. ?newlist arq:member ?newmember. ?newmember m4i:orcidId ?id. - FILTER(?lr != <{LEARNING_RESOURCE_BASE_URI}{uuid}>) + FILTER(?lr != <{_LEARNING_RESOURCE_BASE_URI}{uuid}>) FILTER(?type = schema:Person) }} LIMIT 10""" @@ -111,7 +113,7 @@ def _get_same_discipline(uuid: UUID): .SELECT(var_material) .WHERE( ( - URIRef(f"{LEARNING_RESOURCE_BASE_URI}{uuid}"), + URIRef(f"{_LEARNING_RESOURCE_BASE_URI}{uuid}"), URIRef(URIRef(fabio.NS + "hasDiscipline")), var_discipline, ), @@ -137,14 +139,22 @@ RANKING = ( ) -def get_suggested_contents(uuid: UUID): +def get_suggested_contents_id(uuid: UUID) -> Set: number_of_materials = 5 results = set() for i in range(len(RANKING)): for result in RANKING[i](uuid): - if LEARNING_RESOURCE_BASE_URI == result[: len(LEARNING_RESOURCE_BASE_URI)]: + if ( + _LEARNING_RESOURCE_BASE_URI + == result[: len(_LEARNING_RESOURCE_BASE_URI)] + ): results.add(result) if len(results) == number_of_materials: - return SuggestedContents(results) + return results - return SuggestedContents(results) + return results + + +def get_suggested_contents(uuid: UUID) -> SuggestedContents: + ids = get_suggested_contents_id(uuid) + return SuggestedContents(get_metadata_for_learning_resources(list(ids))) diff --git a/project/recommendation/urls.py b/project/recommendation/urls.py index 398d0ca99fdf423af97e28bbeb437e9a3892da9f..2b339398ca96495fc21775092f733764da10f7df 100644 --- a/project/recommendation/urls.py +++ b/project/recommendation/urls.py @@ -8,8 +8,8 @@ from project.recommendation import views urlpatterns = [ path( - "v1/<uuid:material_id>/suggestions", + "v1/item/<uuid:material_id>/recommendations", views.MaterialSuggestionsView.as_view(), - name="material_suggestions", + name="material_recommendations", ), ] diff --git a/project/recommendation/views.py b/project/recommendation/views.py index e29e695311ef22193f454068845fc37e6a0c7c1d..52c245f32729455c2a03d4c48119f7d6ec6edf89 100644 --- a/project/recommendation/views.py +++ b/project/recommendation/views.py @@ -1,5 +1,6 @@ from uuid import UUID +from rest_framework import status from rest_framework.request import Request from rest_framework.response import Response from rest_framework.views import APIView @@ -8,10 +9,13 @@ import project.recommendation.serializers as serializers from project.recommendation.materials.suggested_content import get_suggested_contents -# endpoint /<uuid:material_id>/suggestions +# endpoint /items/<uuid:material_id>/recommendations class MaterialSuggestionsView(APIView): def get(self, request: Request, material_id: UUID): - result_serializer = serializers.SuggestedContentSerializer( - get_suggested_contents(material_id) - ) - return Response(result_serializer.data) + suggested_contents = get_suggested_contents(material_id) + if len(suggested_contents.results) == 0: + return Response( + {"messages": "No suggestions found"}, status=status.HTTP_404_NOT_FOUND + ) + result = serializers.SuggestedContentSerializer(suggested_contents) + return Response(result.data)