def setUp(self): super(CFRecommendationsViewsTestCase, self).setUp() self.user = db_user.get_or_create(1, 'vansika_1') self.user2 = db_user.get_or_create(2, 'vansika_2') self.user3 = db_user.get_or_create(3, 'vansika_3') # generate test data data = {"recording_mbid": []} for score in range(1500, 0, -1): data["recording_mbid"].append({ "recording_mbid": str(uuid.uuid4()), "score": score }) db_recommendations_cf_recording.insert_user_recommendation( 1, UserRecommendationsJson(**{ 'top_artist': data['recording_mbid'], 'similar_artist': [] })) db_recommendations_cf_recording.insert_user_recommendation( 2, UserRecommendationsJson(**{ 'top_artist': [], 'similar_artist': data['recording_mbid'] })) # get recommendations self.user_recommendations = db_recommendations_cf_recording.get_user_recommendation( 1) self.user2_recommendations = db_recommendations_cf_recording.get_user_recommendation( 2)
def setUp(self): super(CFRecommendationsViewsTestCase, self).setUp() self.user = db_user.get_or_create(1, 'vansika_1') self.user2 = db_user.get_or_create(2, 'vansika_2') self.user3 = db_user.get_or_create(3, 'vansika_3') # insert recommendations with open(self.path_to_data_file('cf_recommendations_db_data_for_api_test_recording.json'), 'r') as f: self.payload = json.load(f) db_recommendations_cf_recording.insert_user_recommendation( 1, UserRecommendationsJson(**{ 'top_artist': self.payload['recording_mbid'], 'similar_artist': [] }) ) db_recommendations_cf_recording.insert_user_recommendation( 2, UserRecommendationsJson(**{ 'top_artist': [], 'similar_artist': self.payload['recording_mbid'] }) ) # get recommendations self.user_recommendations = db_recommendations_cf_recording.get_user_recommendation(1) self.user2_recommendations = db_recommendations_cf_recording.get_user_recommendation(2)
def test_insert_user_recommendation(self): top_artist_recording_mbids = [{ 'recording_mbid': 'a36d6fc9-49d0-4789-a7dd-a2b72369ca45', 'score': 2.3 }, { 'recording_mbid': 'b36d6fc9-49d0-4789-a7dd-a2b72369ca45', 'score': 3.0 }] similar_artist_recording_mbids = [{ 'recording_mbid': 'c36d6fc9-49d0-4789-a7dd-a2b72369ca45', 'score': 1.9 }, { 'recording_mbid': 'd36d6fc9-49d0-4789-a7dd-a2b72369ca45', 'score': 7.6 }] db_recommendations_cf_recording.insert_user_recommendation( self.user['id'], UserRecommendationsJson( **{ 'top_artist': top_artist_recording_mbids, 'similar_artist': similar_artist_recording_mbids })) result = db_recommendations_cf_recording.get_user_recommendation( self.user['id']) self.assertEqual( getattr(result, 'recording_mbid').dict()['top_artist'], top_artist_recording_mbids) self.assertEqual( getattr(result, 'recording_mbid').dict()['similar_artist'], similar_artist_recording_mbids) self.assertGreater(int(getattr(result, 'created').strftime('%s')), 0)
def test_get_user_recommendation(self): data_inserted = self.insert_test_data() data_received = db_recommendations_cf_recording.get_user_recommendation( self.user['id']) self.assertEqual( getattr(data_received, 'recording_mbid').dict()['top_artist'], data_inserted['top_artist_recording_mbids']) self.assertEqual( getattr(data_received, 'recording_mbid').dict()['similar_artist'], data_inserted['similar_artist_recording_mbids'])
def _get_template(active_section, user): """ Get template to render based on active section. Args: active_section (str): Type of recommendation playlist to render i.e top_artist, similar_artist user: Database user object. Returns: Template to render. """ data = db_recommendations_cf_recording.get_user_recommendation(user.id) if data is None: current_app.logger.error('Inactive user: "******"'.format(user.musicbrainz_id)) return render_template( "recommendations_cf_recording/{}.html".format(active_section), active_section=active_section, user=user, error_msg="Looks like the user wasn't active in the last week. Submit your listens and check back after a week!" ) result = getattr(data, 'recording_mbid').dict()[active_section] if not result: current_app.logger.error('Top/Similar artists not found in Mapping/artist relation for "{}"'.format(user.musicbrainz_id)) return render_template( "recommendations_cf_recording/{}.html".format(active_section), active_section=active_section, user=user, error_msg="Looks like the recommendations weren't generated because of anomalies in our data." \ "We are working on it. Check back later." ) listens = _get_listens_from_recording_mbid(result) if not listens: current_app.logger.error('The API returned an empty response for {} recommendations.\nData: {}' .format(active_section, result)) return render_template( "recommendations_cf_recording/{}.html".format(active_section), active_section=active_section, user=user, error_msg="An error occurred while processing your request. Check back later!" ) spotify_data = {} current_user_data = {} if current_user.is_authenticated: spotify_data = spotify.get_user_dict(current_user.id) current_user_data = { "id": current_user.id, "name": current_user.musicbrainz_id, "auth_token": current_user.auth_token, } props = { "user": { "id": user.id, "name": user.musicbrainz_id, }, "current_user": current_user_data, "spotify": spotify_data, "api_url": current_app.config["API_URL"], "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'], "listens": listens, "mode": "cf_recs" } return render_template( "recommendations_cf_recording/{}.html".format(active_section), active_section=active_section, props=ujson.dumps(props), user=user, last_updated=getattr(data, 'created').strftime('%d %b %Y') )
def get_recommendations(user_name): """ Get recommendations sorted on rating and ratings for user ``user_name``. A sample response from the endpoint may look like: .. code-block:: json { "payload": { "last_updated": 1588494361, "type": "<artist_type>", "entity": "recording", "mbids": [ { "recording_mbid": "526bd613-fddd-4bd6-9137-ab709ac74cab", "score": 9.345 }, { "recording_mbid": "a6081bc1-2a76-4984-b21f-38bc3dcca3a5", "score": 6.998 } ], "user_name": "unclejohn69", "count": 10, "total_mbid_count": 30, "offset": 10 } } .. note:: - This endpoint is experimental and probably will change in the future. - <artist_type>: 'top' or 'similar' :param artist_type: Mandatory, artist type in ['top', 'similar'] Ex. artist_type = top will fetch recommended recording mbids that belong to top artists listened to by the user. artist_type = similar will fetch recommended recording mbids that belong to artists similar to top artists listened to by the user. :type artist_type: ``str`` :param count: Optional, number of recording mbids to return, Default: :data:`~webserver.views.api.DEFAULT_ITEMS_PER_GET` Max: :data:`~webserver.views.api.MAX_ITEMS_PER_GET` :type count: ``int`` :param offset: Optional, number of mbids to skip from the beginning, for pagination. Ex. An offset of 5 means the 5 mbids will be skipped, defaults to 0 :type offset: ``int`` :statuscode 200: Successful query, you have data! :statuscode 400: Bad request, check ``response['error']`` for more details :statuscode 404: User not found. :statuscode 204: Recommendations for the user haven't been generated, empty response will be returned """ user = db_user.get_by_mb_id(user_name) if user is None: raise APINotFound("Cannot find user: {}".format(user_name)) artist_type = request.args.get('artist_type') if not _is_valid_artist_type(artist_type): raise APIBadRequest("Invalid artist type: {}".format(artist_type)) offset = get_non_negative_param('offset', default=0) count = get_non_negative_param('count', default=DEFAULT_ITEMS_PER_GET) recommendations = db_recommendations_cf_recording.get_user_recommendation(user['id']) if recommendations is None: err_msg = 'No recommendations due to absence of recent listening history for user {}'.format(user_name) raise APINoContent(err_msg) mbid_list, total_mbid_count = _process_recommendations(recommendations, count, artist_type, user_name, offset) payload = { 'payload': { 'mbids': mbid_list, 'entity': "recording", 'type': artist_type, 'user_name': user_name, 'last_updated': int(getattr(recommendations, 'created').timestamp()), 'count': len(mbid_list), 'total_mbid_count': total_mbid_count, 'offset': offset } } return jsonify(payload)