private async Task <MalRecResults <IEnumerable <IRecommendation> > > GetRecommendationsAsync(AnimeRecsInputJson input,
                                                                                                     Config.RecommendationsConfig recConfig, Dictionary <int, MalListEntry> animeList,
                                                                                                     Dictionary <int, MalListEntry> animeWithheld, IAnimeRecsClientFactory recClientFactory)
        {
            int numRecsToTryToGet = recConfig.MaximumRecommendationsToReturn;

            if (animeWithheld.Count > 0)
            {
                // Get rating prediction information about all anime if in debug mode and withholding anime.
                // For all currently implemented algorithms, this does not cause a performance problem.
                numRecsToTryToGet = 100000;
            }

            using (AnimeRecsClient recClient = recClientFactory.GetClient(input.RecSourceName))
            {
                MalRecResults <IEnumerable <IRecommendation> > recResults;
                try
                {
                    if (input.GoodPercentile != null)
                    {
                        decimal targetFraction = input.GoodPercentile.Value / 100;
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using target of top {3}%.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, targetFraction);
                        recResults = await recClient.GetMalRecommendationsWithFractionTargetAsync(animeList,
                                                                                                  input.RecSourceName, numRecsToTryToGet, targetFraction,
                                                                                                  TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds), CancellationToken.None).ConfigureAwait(false);
                    }
                    else if (input.GoodCutoff != null)
                    {
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using target of {3}.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, input.GoodCutoff.Value);
                        recResults = await recClient.GetMalRecommendationsAsync(animeList, input.RecSourceName,
                                                                                numRecsToTryToGet, input.GoodCutoff.Value, TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds),
                                                                                CancellationToken.None).ConfigureAwait(false);
                    }
                    else
                    {
                        decimal targetFraction = recConfig.DefaultTargetPercentile / 100;
                        _logger.LogInformation("Querying rec source {0} for {1} recommendations for {2} using default target of top {3}%.",
                                               input.RecSourceName, numRecsToTryToGet, input.MalName, targetFraction);
                        recResults = await recClient.GetMalRecommendationsWithFractionTargetAsync(animeList,
                                                                                                  input.RecSourceName, numRecsToTryToGet, targetFraction,
                                                                                                  TimeSpan.FromMilliseconds(recConfig.TimeoutMilliseconds), CancellationToken.None)
                                     .ConfigureAwait(false);
                    }
                }
                catch (AnimeRecs.RecService.DTO.RecServiceErrorException ex)
                {
                    if (ex.Error.ErrorCode == AnimeRecs.RecService.DTO.ErrorCodes.Maintenance)
                    {
                        _logger.LogInformation("Could not service recommendation request for {0}. The rec service is currently undergoing maintenance.",
                                               input.MalName);
                        AjaxError  error  = new AjaxError(AjaxError.InternalError, "The site is currently undergoing scheduled maintenance. Check back in a few minutes.");
                        JsonResult result = Json(error);
                        result.StatusCode = 500;
                        throw new ShortCircuitException(result);
                    }
                    else
                    {
                        throw;
                    }
                }
                _logger.LogInformation("Got results from rec service for {0}.", input.MalName);

                return(recResults);
            }
        }
Beispiel #2
0
        static void Main(string[] args)
        {
            CommandLineArgs commandLine = new CommandLineArgs(args);

            if (commandLine.ShowHelp)
            {
                commandLine.DisplayHelp(Console.Out);
                return;
            }

            Config config = Config.LoadFromFile(commandLine.ConfigFile);

            using (AnimeRecsClient client = new AnimeRecsClient(commandLine.PortNumber))
            {
                if (commandLine.Operation.Equals("raw", StringComparison.OrdinalIgnoreCase))
                {
                    byte[] requestJsonBytes          = Encoding.UTF8.GetBytes(commandLine.RawJson);
                    int    requestLength             = requestJsonBytes.Length;
                    int    requestLengthNetworkOrder = IPAddress.HostToNetworkOrder(requestLength);
                    byte[] requestLengthBytes        = BitConverter.GetBytes(requestLengthNetworkOrder);

                    byte[] requestBytes = new byte[requestLengthBytes.Length + requestJsonBytes.Length];
                    requestLengthBytes.CopyTo(requestBytes, index: 0);
                    requestJsonBytes.CopyTo(requestBytes, index: requestLengthBytes.Length);

                    using (Socket rawClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                    {
                        TimeSpan sendTimeout = TimeSpan.FromSeconds(5);
                        rawClientSocket.SendAllAsync(requestBytes, sendTimeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                        rawClientSocket.Shutdown(SocketShutdown.Send);

                        byte[]  responseLengthBuffer       = rawClientSocket.ReceiveAllAsync(numBytesToReceive: 4, receiveAllTimeout: TimeSpan.FromMinutes(3), cancellationToken: CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                        int     responseLengthNetworkOrder = BitConverter.ToInt32(responseLengthBuffer, 0);
                        int     responseLength             = IPAddress.NetworkToHostOrder(responseLengthNetworkOrder);
                        byte[]  responseJsonBytes          = rawClientSocket.ReceiveAllAsync(responseLength, receiveAllTimeout: TimeSpan.FromSeconds(5), cancellationToken: CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                        string  responseJsonString         = Encoding.UTF8.GetString(responseJsonBytes);
                        dynamic responseJson   = JsonConvert.DeserializeObject <dynamic>(responseJsonString);
                        string  prettyResponse = JsonConvert.SerializeObject(responseJson, Formatting.Indented);
                        Console.WriteLine(prettyResponse);
                    }
                }
                else if (commandLine.Operation.Equals(OperationTypes.Ping, StringComparison.OrdinalIgnoreCase))
                {
                    TimeSpan  timeout      = TimeSpan.FromSeconds(3);
                    Stopwatch timer        = Stopwatch.StartNew();
                    string    pingResponse = client.PingAsync(commandLine.PingMessage, timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    timer.Stop();
                    Console.WriteLine($"The service replied: {pingResponse} (took {timer.Elapsed})");
                }
                else if (commandLine.Operation.Equals(OperationTypes.ReloadTrainingData, StringComparison.OrdinalIgnoreCase))
                {
                    TimeSpan timeout = TimeSpan.FromMinutes(3);
                    client.ReloadTrainingDataAsync(commandLine.ReloadMode, commandLine.Finalize, timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    Console.WriteLine("Training data reloaded.");
                }
                else if (commandLine.Operation.Equals(OperationTypes.FinalizeRecSources, StringComparison.OrdinalIgnoreCase))
                {
                    TimeSpan timeout = TimeSpan.FromSeconds(5);
                    client.FinalizeRecSourcesAsync(timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();;
                    Console.WriteLine("Rec sources finalized.");
                }
                else if (commandLine.Operation.Equals(OperationTypes.LoadRecSource, StringComparison.OrdinalIgnoreCase))
                {
                    if (commandLine.RecSourceType.Equals(RecSourceTypes.AverageScore, StringComparison.OrdinalIgnoreCase))
                    {
                        TimeSpan timeout = TimeSpan.FromSeconds(30);
                        client.LoadRecSourceAsync(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource,
                                                  new AverageScoreRecSourceParams(
                                                      minEpisodesToCountIncomplete: commandLine.MinEpisodesToCountIncomplete,
                                                      minUsersToCountAnime: commandLine.MinUsersToCountAnime,
                                                      useDropped: commandLine.UseDropped
                                                      ),
                                                  timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    }
                    else if (commandLine.RecSourceType.Equals(RecSourceTypes.MostPopular, StringComparison.OrdinalIgnoreCase))
                    {
                        TimeSpan timeout = TimeSpan.FromSeconds(30);
                        client.LoadRecSourceAsync(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource,
                                                  new MostPopularRecSourceParams(
                                                      minEpisodesToCountIncomplete: commandLine.MinEpisodesToCountIncomplete,
                                                      useDropped: commandLine.UseDropped
                                                      ), timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    }
                    else if (commandLine.RecSourceType.Equals(RecSourceTypes.AnimeRecs, StringComparison.OrdinalIgnoreCase))
                    {
                        TimeSpan timeout = TimeSpan.FromSeconds(60);
                        client.LoadRecSourceAsync(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource,
                                                  new AnimeRecsRecSourceParams(
                                                      numRecommendersToUse: commandLine.NumRecommendersToUse,
                                                      fractionConsideredRecommended: commandLine.FractionRecommended,
                                                      minEpisodesToClassifyIncomplete: commandLine.MinEpisodesToCountIncomplete
                                                      ), timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    }
                    else if (commandLine.RecSourceType.Equals(RecSourceTypes.BiasedMatrixFactorization, StringComparison.OrdinalIgnoreCase))
                    {
                        TimeSpan timeout = TimeSpan.FromMinutes(3);
                        client.LoadRecSourceAsync(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource,
                                                  commandLine.BiasedMatrixFactorizationParams, timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    }
                    else
                    {
                        throw new Exception("Oops! Missed a rec source type!");
                    }

                    Console.WriteLine("Load complete.");
                }
                else if (commandLine.Operation.Equals(OperationTypes.UnloadRecSource, StringComparison.OrdinalIgnoreCase))
                {
                    TimeSpan timeout = TimeSpan.FromSeconds(10);
                    client.UnloadRecSourceAsync(commandLine.RecSourceName, timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    Console.WriteLine("Unload complete.");
                }
                else if (commandLine.Operation.Equals(OperationTypes.GetRecSourceType, StringComparison.OrdinalIgnoreCase))
                {
                    TimeSpan timeout       = TimeSpan.FromSeconds(3);
                    string   recSourceType = client.GetRecSourceTypeAsync(commandLine.RecSourceName, timeout, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
                    Console.WriteLine("Type of rec source {0} is {1}.", commandLine.RecSourceName, recSourceType);
                }
                else if (commandLine.Operation.Equals(OperationTypes.GetMalRecs, StringComparison.OrdinalIgnoreCase))
                {
                    MalUserLookupResults lookup;

                    using (IMyAnimeListApi malApi = GetMalApi(config))
                    {
                        lookup = malApi.GetAnimeListForUser(commandLine.MalUsername);
                    }

                    Dictionary <int, RecEngine.MAL.MalListEntry> animeListEntries = new Dictionary <int, RecEngine.MAL.MalListEntry>();
                    foreach (MyAnimeListEntry entry in lookup.AnimeList)
                    {
                        animeListEntries[entry.AnimeInfo.AnimeId] = new RecEngine.MAL.MalListEntry((byte?)entry.Score, entry.Status, (short)entry.NumEpisodesWatched);
                    }

                    TimeSpan timeout = TimeSpan.FromSeconds(10);
                    MalRecResults <IEnumerable <RecEngine.IRecommendation> > recs = client.GetMalRecommendationsAsync(
                        animeList: animeListEntries,
                        recSourceName: commandLine.RecSourceName,
                        numRecsDesired: commandLine.NumRecs,
                        targetScore: commandLine.TargetScore,
                        timeout: timeout,
                        cancellationToken: CancellationToken.None
                        )
                                                                                    .ConfigureAwait(false).GetAwaiter().GetResult();

                    PrintRecs(recs, animeListEntries, commandLine.TargetScore);
                }
                else
                {
                    throw new Exception(string.Format("Oops, missed an operation: {0}", commandLine.Operation));
                }
            }
        }