Esempio n. 1
0
        private async Task <MalRecResults <IEnumerable <IRecommendation> > > GetMalRecommendationsAsync(Operation <GetMalRecsRequest> operation, TimeSpan timeout, CancellationToken cancellationToken)
        {
            GetMalRecsResponse response = await DoOperationWithResponseBodyAsync <GetMalRecsResponse>(
                operation, timeout, cancellationToken, descriptionForErrors : "getting recommendations").ConfigureAwait(false);

            // This should be set as if we were running against an in-process rec source.
            // So it should be an IEnumerable<AverageScoreRecommendation> if getting recs from an AverageScore rec source, etc.
            // MalRecResultsExtensions.cs contains extension methods for "casting" MalRecResults to a strongly-typed MalRecResults.
            IEnumerable <IRecommendation> results;

            Type responseType = response.GetType();
            // check if m_responseToRecs implements IResponseToRecsConverter<responseType>
            Type converterInterfaceOpenType   = typeof(IResponseToRecsConverter <>);
            Type converterInterfaceClosedType = converterInterfaceOpenType.MakeGenericType(responseType);

            if (converterInterfaceClosedType.IsInstanceOfType(m_responseToRecs))
            {
                // Good, we have a handler.
                MethodInfo converterMethod     = converterInterfaceClosedType.GetMethod(ResponseToRecsConverter.ConvertMethodName);
                object     conversionResultObj = converterMethod.Invoke(m_responseToRecs, new object[] { response });
                results = (IEnumerable <IRecommendation>)conversionResultObj;
            }
            else
            {
                // Fallback. This will throw an exception if the recommendation DTO type is registered in the DTO assembly
                // but no handler is registered in this assembly.
                GetMalRecsResponse <DTO.Recommendation> specificResponse = (GetMalRecsResponse <DTO.Recommendation>)response;
                List <IRecommendation> recommendations = new List <IRecommendation>();
                foreach (DTO.Recommendation dtoRec in specificResponse.Recommendations)
                {
                    recommendations.Add(new BasicRecommendation(dtoRec.MalAnimeId));
                }

                results = recommendations;
            }

            Dictionary <int, RecEngine.MAL.MalAnime> animes = new Dictionary <int, RecEngine.MAL.MalAnime>();

            foreach (DTO.MalAnime dtoAnime in response.Animes)
            {
                animes[dtoAnime.MalAnimeId] = new RecEngine.MAL.MalAnime(dtoAnime.MalAnimeId, dtoAnime.MalAnimeType, dtoAnime.Title);
            }

            MalRecResults <IEnumerable <IRecommendation> > resultsWithAnimes = new MalRecResults <IEnumerable <IRecommendation> >(results, animes, response.RecommendationType);

            return(resultsWithAnimes);
        }
Esempio n. 2
0
 protected override void SetSpecializedExtraResponseProperties(
     GetMalRecsResponse <DTO.AnimeRecsRecommendation, MalAnimeRecsExtraResponseData> response, MalAnimeRecsResults recResults)
 {
     response.Data = new MalAnimeRecsExtraResponseData(
         targetScoreUsed: recResults.TargetScoreUsed,
         recommenders: recResults.Recommenders.Select(recommender => new DTO.MalAnimeRecsRecommender(
                                                          userId: recommender.UserId,
                                                          username: UsernamesByUserId[recommender.UserId],
                                                          recs: recommender.AllRecommendations.Select(recommendedAnime => new DTO.MalAnimeRecsRecommenderRecommendation(
                                                                                                          malAnimeId: recommendedAnime.MalAnimeId,
                                                                                                          judgment: recommender.RecsLiked.Contains(recommendedAnime) ? DTO.AnimeRecsRecommendationJudgment.Liked
                         : recommender.RecsNotLiked.Contains(recommendedAnime) ? DTO.AnimeRecsRecommendationJudgment.NotLiked
                         : recommender.RecsInconclusive.Contains(recommendedAnime) ? DTO.AnimeRecsRecommendationJudgment.Inconclusive
                         : AnimeRecsRecommendationJudgment.NotInCommon,
                                                                                                          recommenderScore: recommendedAnime.RecommenderScore,
                                                                                                          averageScore: recommendedAnime.AverageScore
                                                                                                          )).ToList(),
                                                          compatibility: recommender.Compatibility,
                                                          compatibilityLowEndpoint: recommender.CompatibilityLowEndpoint,
                                                          compatibilityHighEndpoint: recommender.CompatibilityHighEndpoint
                                                          )).ToList()
         );
 }
        IEnumerable <RecEngine.IRecommendation> IResponseToRecsConverter <GetMalRecsResponse <RatingPredictionRecommendation> > .ConvertResponseToRecommendations(GetMalRecsResponse <RatingPredictionRecommendation> response)
        {
            List <RecEngine.RatingPredictionRecommendation> recommendations = new List <RecEngine.RatingPredictionRecommendation>();

            foreach (DTO.RatingPredictionRecommendation dtoRec in response.Recommendations)
            {
                recommendations.Add(new RecEngine.RatingPredictionRecommendation(
                                        itemId: dtoRec.MalAnimeId,
                                        predictedRating: dtoRec.PredictedRating
                                        ));
            }

            return(recommendations);
        }
Esempio n. 4
0
 protected override void SetSpecializedExtraResponseProperties(
     GetMalRecsResponse <DTO.RatingPredictionRecommendation, MalPositiveFeedbackExtraResponseData> response,
     MalPositiveFeedbackRecResults recResults)
 {
     response.Data = new MalPositiveFeedbackExtraResponseData(targetScoreUsed: recResults.TargetScoreUsed);
 }
Esempio n. 5
0
        // Take in type derived from GetMalRecsResponse, return IEnumerable<IRecommendation>
        IEnumerable <RecEngine.IRecommendation> IResponseToRecsConverter <GetMalRecsResponse <MostPopularRecommendation> > .ConvertResponseToRecommendations(GetMalRecsResponse <MostPopularRecommendation> response)
        {
            List <RecEngine.MostPopularRecommendation> recommendations = new List <RecEngine.MostPopularRecommendation>();

            foreach (DTO.MostPopularRecommendation dtoRec in response.Recommendations)
            {
                recommendations.Add(new AnimeRecs.RecEngine.MostPopularRecommendation(
                                        itemId: dtoRec.MalAnimeId,
                                        popularityRank: dtoRec.PopularityRank,
                                        numRatings: dtoRec.NumRatings
                                        ));
            }
            return(recommendations);
        }
Esempio n. 6
0
        // Take in type derived from GetMalRecsResponse, return IEnumerable<IRecommendation>
        IEnumerable <RecEngine.IRecommendation> IResponseToRecsConverter <GetMalRecsResponse <DTO.AnimeRecsRecommendation, DTO.MalAnimeRecsExtraResponseData> > .ConvertResponseToRecommendations(GetMalRecsResponse <DTO.AnimeRecsRecommendation, DTO.MalAnimeRecsExtraResponseData> response)
        {
            List <RecEngine.AnimeRecsRecommendation> recommendations = new List <RecEngine.AnimeRecsRecommendation>();

            foreach (DTO.AnimeRecsRecommendation dtoRec in response.Recommendations)
            {
                recommendations.Add(new RecEngine.AnimeRecsRecommendation(dtoRec.RecommenderUserId, itemId: dtoRec.MalAnimeId));
            }

            List <MalAnimeRecsRecommenderUser> recommenders = new List <MalAnimeRecsRecommenderUser>();

            foreach (DTO.MalAnimeRecsRecommender dtoRecommender in response.Data.Recommenders)
            {
                HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation> recsLiked        = new HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation>();
                HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation> recsNotLiked     = new HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation>();
                HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation> recsInconclusive = new HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation>();
                HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation> recsNotInCommon  = new HashSet <RecEngine.MAL.MalAnimeRecsRecommenderRecommendation>();

                foreach (DTO.MalAnimeRecsRecommenderRecommendation rec in dtoRecommender.Recs)
                {
                    switch (rec.Judgment)
                    {
                    case AnimeRecsRecommendationJudgment.Liked:
                        recsLiked.Add(new RecEngine.MAL.MalAnimeRecsRecommenderRecommendation(rec.MalAnimeId, rec.RecommenderScore, rec.AverageScore));
                        break;

                    case AnimeRecsRecommendationJudgment.NotLiked:
                        recsNotLiked.Add(new RecEngine.MAL.MalAnimeRecsRecommenderRecommendation(rec.MalAnimeId, rec.RecommenderScore, rec.AverageScore));
                        break;

                    case AnimeRecsRecommendationJudgment.Inconclusive:
                        recsInconclusive.Add(new RecEngine.MAL.MalAnimeRecsRecommenderRecommendation(rec.MalAnimeId, rec.RecommenderScore, rec.AverageScore));
                        break;

                    case AnimeRecsRecommendationJudgment.NotInCommon:
                        recsNotInCommon.Add(new RecEngine.MAL.MalAnimeRecsRecommenderRecommendation(rec.MalAnimeId, rec.RecommenderScore, rec.AverageScore));
                        break;
                    }
                }

                recommenders.Add(new MalAnimeRecsRecommenderUser(
                                     userId: dtoRecommender.UserId,
                                     username: dtoRecommender.Username,
                                     recsLiked: recsLiked,
                                     recsNotLiked: recsNotLiked,
                                     recsInconclusive: recsInconclusive,
                                     recsNotInCommon: recsNotInCommon,
                                     compatibility: dtoRecommender.Compatibility,
                                     compatibilityLowEndpoint: dtoRecommender.CompatibilityLowEndpoint,
                                     compatibilityHighEndpoint: dtoRecommender.CompatibilityHighEndpoint
                                     ));
            }

            return(new RecEngine.MAL.MalAnimeRecsResults(recommendations, recommenders, response.Data.TargetScoreUsed));
        }
        // Take in type derived from GetMalRecsResponse, return IEnumerable<IRecommendation>
        IEnumerable <RecEngine.IRecommendation> IResponseToRecsConverter <GetMalRecsResponse <AverageScoreRecommendation> > .ConvertResponseToRecommendations(GetMalRecsResponse <AverageScoreRecommendation> response)
        {
            List <RecEngine.AverageScoreRecommendation> recommendations = new List <RecEngine.AverageScoreRecommendation>();

            foreach (DTO.AverageScoreRecommendation dtoRec in response.Recommendations)
            {
                recommendations.Add(new AnimeRecs.RecEngine.AverageScoreRecommendation(dtoRec.MalAnimeId, dtoRec.NumRatings, dtoRec.AverageScore));
            }
            return(recommendations);
        }
Esempio n. 8
0
        public async Task <GetMalRecsResponse> GetMalRecsAsync(GetMalRecsRequest request, CancellationToken cancellationToken)
        {
            request.AssertArgumentNotNull("request");
            request.RecSourceName.AssertArgumentNotNull("request.RecSourceName");
            request.AnimeList.AssertArgumentNotNull("request.AnimeList");
            request.AnimeList.Entries.AssertArgumentNotNull("request.AnimeList.Entries");

            if (request.TargetScore == null && request.TargetFraction == null)
            {
                Error error = new Error(ErrorCodes.InvalidArgument, "Payload.TargetScore or Payload.TargetFraction must be set.");
                throw new RecServiceErrorException(error);
            }

            string targetScoreString;

            if (request.TargetFraction != null)
            {
                targetScoreString = request.TargetFraction.Value.ToString("P2");
            }
            else
            {
                targetScoreString = request.TargetScore.Value.ToString();
            }

            Logging.Log.InfoFormat("Request for {0} MAL recs using rec source {1}. User has {2} anime list entries. Target score is {3}.",
                                   request.NumRecsDesired, request.RecSourceName, request.AnimeList.Entries.Count, targetScoreString);

            // Acquire read lock on rec sources
            const int lockTimeoutInSeconds = 3;

            using (CancellationTokenSource lockTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(lockTimeoutInSeconds)))
                using (CancellationTokenSource lockCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, lockTimeout.Token))
                {
                    bool gotLock = false;
                    try
                    {
                        using (var recSourcesLock = await m_recSourcesLockAsync.EnterReadLockAsync(lockCancel.Token).ConfigureAwait(false))
                        {
                            gotLock = true;
                            // Get rec source by name
                            if (!m_recSources.ContainsKey(request.RecSourceName))
                            {
                                Error error = new Error(errorCode: ErrorCodes.NoSuchRecSource,
                                                        message: string.Format("No rec source called \"{0}\" is loaded.", request.RecSourceName));
                                throw new RecServiceErrorException(error);
                            }
                            ITrainableJsonRecSource recSource = m_recSources[request.RecSourceName];

                            // Convert DTO anime list to RecEngine anime list

                            Dictionary <int, AnimeRecs.RecEngine.MAL.MalListEntry> entries = new Dictionary <int, RecEngine.MAL.MalListEntry>();
                            foreach (AnimeRecs.RecService.DTO.MalListEntry dtoEntry in request.AnimeList.Entries)
                            {
                                AnimeRecs.RecEngine.MAL.MalListEntry recEngineEntry = new RecEngine.MAL.MalListEntry(dtoEntry.Rating, dtoEntry.Status, dtoEntry.NumEpisodesWatched);
                                entries[dtoEntry.MalAnimeId] = recEngineEntry;
                            }
                            MalUserListEntries animeList = new MalUserListEntries(ratings: entries, animes: m_animes,
                                                                                  malUsername: null, prerequisites: m_prereqs);

                            Stopwatch          timer    = Stopwatch.StartNew();
                            GetMalRecsResponse response = recSource.GetRecommendations(animeList, request, cancellationToken);
                            timer.Stop();

                            Logging.Log.InfoFormat("Got recommendations from rec source {0}. Took {1}.", request.RecSourceName, timer.Elapsed);
                            return(response);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        // If we couldn't get a read lock within 3 seconds, a reload/retrain is probably going on
                        if (!gotLock)
                        {
                            Error error = new Error(errorCode: ErrorCodes.Maintenance,
                                                    message: "The rec service is currently undergoing maintenance and cannot respond to rec requests.");
                            throw new RecServiceErrorException(error);
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
        }