public async Task <IActionResult> Index([FromQuery] string algorithm, [FromQuery] bool?detailedResults, [FromQuery] bool?debugMode, [FromServices] IOptionsSnapshot <Config.RecommendationsConfig> recConfig, [FromServices] IAnimeRecsClientFactory recClientFactory) { if (!ModelState.IsValid) { string errorString = ModelBindingHelpers.ConstructErrorString(ModelState); _logger.LogDebug("Invalid input received for home page: {0}", errorString); return(View("Error", new ErrorViewModel(exception: null))); } algorithm = algorithm ?? recConfig.Value.DefaultRecSource; bool displayDetailedResults = detailedResults ?? false; bool debugModeOn = debugMode ?? false; string recSourceType = null; using (AnimeRecsClient client = recClientFactory.GetClient(algorithm)) { try { recSourceType = await client.GetRecSourceTypeAsync(algorithm, TimeSpan.FromMilliseconds(recConfig.Value.TimeoutMilliseconds), CancellationToken.None); } catch { ; } } bool algorithmAvailable = recSourceType != null; bool targetScoreNeeded = false; if (AnimeRecs.RecService.DTO.RecSourceTypes.AnimeRecs.Equals(recSourceType, StringComparison.OrdinalIgnoreCase) && displayDetailedResults) { targetScoreNeeded = true; } HomeViewModel viewModel = new HomeViewModel( algorithm: algorithm, algorithmAvailable: algorithmAvailable, targetScoreNeeded: targetScoreNeeded, displayDetailedResults: displayDetailedResults, debugModeOn: debugModeOn ); return(View(viewModel)); }
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); } }
static void Main(string[] args) { CommandLineArgs commandLine = new CommandLineArgs(args); if (commandLine.ShowHelp) { commandLine.DisplayHelp(Console.Out); return; } using (AnimeRecsClient client = new AnimeRecsClient(commandLine.PortNumber)) { if (commandLine.Operation.Equals("raw", StringComparison.OrdinalIgnoreCase)) { using (TcpClient rawClient = new TcpClient("localhost", commandLine.PortNumber)) { byte[] jsonBytes = Encoding.UTF8.GetBytes(commandLine.RawJson); rawClient.Client.Send(jsonBytes); using (NetworkStream socketStream = rawClient.GetStream()) { rawClient.Client.Shutdown(SocketShutdown.Send); byte[] responseJsonBytes = StreamUtil.ReadFully(socketStream); 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(OpNames.Ping, StringComparison.OrdinalIgnoreCase)) { string pingResponse = client.Ping(commandLine.PingMessage); Console.WriteLine("The service replied: {0}", pingResponse); } else if (commandLine.Operation.Equals(OpNames.ReloadTrainingData, StringComparison.OrdinalIgnoreCase)) { client.ReloadTrainingData(commandLine.ReloadMode, commandLine.Finalize); Console.WriteLine("Training data reloaded."); } else if (commandLine.Operation.Equals(OpNames.FinalizeRecSources, StringComparison.OrdinalIgnoreCase)) { client.FinalizeRecSources(); Console.WriteLine("Rec sources finalized."); } else if (commandLine.Operation.Equals(OpNames.LoadRecSource, StringComparison.OrdinalIgnoreCase)) { if (commandLine.RecSourceType.Equals(RecSourceTypes.AverageScore, StringComparison.OrdinalIgnoreCase)) { client.LoadRecSource(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource, new AverageScoreRecSourceParams( minEpisodesToCountIncomplete: commandLine.MinEpisodesToCountIncomplete, minUsersToCountAnime: commandLine.MinUsersToCountAnime, useDropped: commandLine.UseDropped ) ); } else if (commandLine.RecSourceType.Equals(RecSourceTypes.MostPopular, StringComparison.OrdinalIgnoreCase)) { client.LoadRecSource(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource, new MostPopularRecSourceParams( minEpisodesToCountIncomplete: commandLine.MinEpisodesToCountIncomplete, useDropped: commandLine.UseDropped ) ); } else if (commandLine.RecSourceType.Equals(RecSourceTypes.AnimeRecs, StringComparison.OrdinalIgnoreCase)) { client.LoadRecSource(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource, new AnimeRecsRecSourceParams( numRecommendersToUse: commandLine.NumRecommendersToUse, fractionConsideredRecommended: commandLine.FractionRecommended, minEpisodesToClassifyIncomplete: commandLine.MinEpisodesToCountIncomplete ) ); } else if (commandLine.RecSourceType.Equals(RecSourceTypes.BiasedMatrixFactorization, StringComparison.OrdinalIgnoreCase)) { client.LoadRecSource(commandLine.RecSourceName, commandLine.ReplaceExistingRecSource, commandLine.BiasedMatrixFactorizationParams); } else { throw new Exception("Oops! Missed a rec source type!"); } Console.WriteLine("Load complete."); } else if (commandLine.Operation.Equals(OpNames.UnloadRecSource, StringComparison.OrdinalIgnoreCase)) { client.UnloadRecSource(commandLine.RecSourceName); Console.WriteLine("Unload complete."); } else if (commandLine.Operation.Equals(OpNames.GetRecSourceType, StringComparison.OrdinalIgnoreCase)) { string recSourceType = client.GetRecSourceType(commandLine.RecSourceName); Console.WriteLine("Type of rec source {0} is {1}.", commandLine.RecSourceName, recSourceType); } else if (commandLine.Operation.Equals(OpNames.GetMalRecs, StringComparison.OrdinalIgnoreCase)) { MalUserLookupResults lookup; using (IMyAnimeListApi malApi = GetMalApi()) { 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); } MalRecResults<IEnumerable<RecEngine.IRecommendation>> recs = client.GetMalRecommendations( animeList: animeListEntries, recSourceName: commandLine.RecSourceName, numRecsDesired: commandLine.NumRecs, targetScore: commandLine.TargetScore); PrintRecs(recs, animeListEntries, commandLine.TargetScore); } else { throw new Exception(string.Format("Oops, missed an operation: {0}", commandLine.Operation)); } } }
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)); } } }
static void Main(string[] args) { System.Threading.Thread.CurrentThread.Name = "Main"; Logging.SetUpLogging(); try { CommandLineArgs commandLine = new CommandLineArgs(args); if (commandLine.ShowHelp) { commandLine.DisplayHelp(Console.Out); return; } ConfigRoot config = null; if (commandLine.ConfigFile != null) { config = ConfigRoot.LoadFromFile(commandLine.ConfigFile); } string connectionString = ConfigurationManager.ConnectionStrings["Postgres"].ToString(); PgMalTrainingDataLoaderFactory trainingDataLoaderFactory = new PgMalTrainingDataLoaderFactory(connectionString); using (TcpRecService recService = new TcpRecService(trainingDataLoaderFactory, commandLine.PortNumber)) { recService.Start(); if (config != null) { using (AnimeRecsClient client = new AnimeRecsClient(commandLine.PortNumber)) { foreach (DTO.LoadRecSourceRequest recSourceToLoad in config.RecSources) { client.LoadRecSource(recSourceToLoad); } if (config.FinalizeAfterLoad) { client.FinalizeRecSources(); } } } #if MONO Logging.Log.InfoFormat("Started listening on port {0}. Press ctrl+c to stop.", commandLine.PortNumber); WaitForUnixStopSignal(); #else Logging.Log.InfoFormat("Started listening on port {0}. Press any key to stop.", commandLine.PortNumber); Console.ReadKey(); #endif Logging.Log.InfoFormat("Got stop signal."); } Logging.Log.InfoFormat("Shutdown complete."); } catch (Exception ex) { Logging.Log.FatalFormat("Fatal error: {0}", ex, ex.Message); Environment.ExitCode = 1; } }