BookshelfReader 3.2.0
dotnet add package BookshelfReader --version 3.2.0
NuGet\Install-Package BookshelfReader -Version 3.2.0
<PackageReference Include="BookshelfReader" Version="3.2.0" />
<PackageVersion Include="BookshelfReader" Version="3.2.0" />
<PackageReference Include="BookshelfReader" />
paket add BookshelfReader --version 3.2.0
#r "nuget: BookshelfReader, 3.2.0"
#:package BookshelfReader@3.2.0
#addin nuget:?package=BookshelfReader&version=3.2.0
#tool nuget:?package=BookshelfReader&version=3.2.0
BookshelfReader
BookshelfReader provides dependency injection helpers and API endpoint mappings for wiring a bookshelf parsing pipeline (vision spine reading, genre classification, and Open Library lookup) into an existing ASP.NET Core application. Use the BookshelfReader NuGet package; you do not need to run the included API host by itself. A runnable reference host lives in BookshelfReader.Host for local testing only and is not packaged. Only the BookshelfReader project is marked packable so dotnet pack emits just the NuGet payload.
Uploaded photos are read by sending them to a vision model. The provider is pluggable so you can use whichever vision API key you already have - Anthropic Claude (the default, via the Messages API), OpenAI (Chat Completions, vision-capable model), or Google Gemini (Generative Language API). Select one with Vision:Provider; Claude stays the default and its behavior is unchanged. Regardless of provider, images are processed in memory only - never written to disk - and are downscaled and re-encoded before they leave the server, which strips all EXIF metadata (including phone GPS coordinates).
Consuming the NuGet package
- Reference the
BookshelfReaderpackage from your ASP.NET Core project. - In
Program.csadd:using BookshelfReader.Api.Extensions; using BookshelfReader.Extensions; using BookshelfReader.Extensions.Authentication; builder.Services.AddBookshelfReader(builder.Configuration); // Required when you map the endpoints yourself: registers the image upload // validation/handling services that MapBookshelfReaderApi() depends on. builder.Services.AddBookshelfReaderApi(); builder.Services .AddAuthentication(options => { options.DefaultScheme = ApiKeyAuthenticationDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = ApiKeyAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = ApiKeyAuthenticationDefaults.AuthenticationScheme; }) .AddBookshelfReaderApiKey(); builder.Services.AddAuthorization(); builder.Services.AddBookshelfReaderRateLimiting(builder.Configuration); app.UseRateLimiter(); app.MapBookshelfReaderApi(); - Provide configuration values (environment variables or
appsettings.json):Authentication:ApiKey:HeaderName(defaultX-API-Key),RequireApiKey, andValidKeys.RateLimiting:Parse:Enabled(defaultfalse),PermitLimit(default10), andWindowSeconds(default60). Enabling this policy also requiresbuilder.Services.AddBookshelfReaderRateLimiting(builder.Configuration);during service registration andapp.UseRateLimiter();before mapping the API endpoints.Uploads:MaxBytes(1–20 MB) andAllowedContentTypes(JPEG/PNG).Enrichment:Enabled(defaulttrue),MaxConcurrentLookups(1–16, default 4), andMinMatchScore(0–100, default 55). When enabled,/api/bookshelf/parselooks up each parsed title against Open Library and attaches the best match (title, author, year, ISBN, cover URL, subjects) to the candidate'smetadatafield, so callers get display-ready results from a single request.Vision:Providerselects the vision backend -Claude(default),OpenAI, orGemini(case-insensitive). Only the selected provider's section below is bound and validated, so you only need a key for the provider you choose. The host fails fast at startup if the selected provider has no key.ClaudeVision(used whenVision:ProviderisClaude, the default):ApiKey(falls back to theANTHROPIC_API_KEYenvironment variable if unset),BaseUrl(defaulthttps://api.anthropic.com/, must be HTTPS),Model(defaultclaude-haiku-4-5),MaxTokens(default2048),TimeoutSeconds(default60), andMaxImageDimension(default1568, images are downscaled so their longest edge does not exceed this many pixels before being sent to the model).OpenAIVision(used whenVision:ProviderisOpenAI):ApiKey(falls back toOPENAI_API_KEY),BaseUrl(defaulthttps://api.openai.com/, must be HTTPS),Model(defaultgpt-4o-mini, a current low-cost vision-capable chat model),MaxTokens(default2048),TimeoutSeconds(default60), andMaxImageDimension(default1568). The image is sent as a base64 data URL and JSON mode is requested.GeminiVision(used whenVision:ProviderisGemini):ApiKey(falls back toGEMINI_API_KEY),BaseUrl(defaulthttps://generativelanguage.googleapis.com/, must be HTTPS),Model(defaultgemini-2.0-flash, a current low-cost multimodal model),MaxTokens(default2048),TimeoutSeconds(default60), andMaxImageDimension(default1568). The image is sent as inline base64 data and JSON output is requested.- Optional:
OpenLibrary:BaseUrl(must be HTTPS) andOpenLibrary:UserAgent(sent to Open Library; defaults to a BookshelfReader identifier).
For whichever provider you select, create a dedicated console workspace and API key for this integration (with its own spend limit) so usage and billing stay isolated. At Claude claude-haiku-4-5 pricing, a typical bookshelf photo costs roughly $0.003-$0.005 per request; OpenAI gpt-4o-mini and Gemini gemini-2.0-flash are similarly inexpensive vision models, though exact costs vary by provider and image size.
Packing for nuget.org (testing)
dotnet restore
dotnet pack BookshelfReader/BookshelfReader.csproj \
-c Release \
-p:PackageVersion=3.0.0-beta1 \
-p:IncludeSymbols=true \
-p:SymbolPackageFormat=snupkg
# Equivalent solution-wide pack (only the packable project emits a package)
# dotnet pack BookshelfReader.sln -c Release
Publish the resulting .nupkg (and optional .snupkg) artifact to nuget.org with your API key. Mark prerelease versions with a suffix such as -beta1.
Tests
dotnet test
Tests cover the DI wiring, option validation, and pipeline components to ensure the NuGet surface behaves as expected.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FuzzySharp (>= 2.0.2)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- OpenCvSharp4.Windows (>= 4.10.0.20240616)
- SixLabors.ImageSharp (>= 3.1.12)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.