Repository navigation
feat: ai reading recommendations (read next and discover) through openrouter - #53
Merged
Merged
Conversation
Two lists, refreshed on demand (or weekly) in the background: - Read next: picks from the unread books in the library (the next unread book of each series, plus standalones). - Discover: titles the reader doesn't have, books and/or web serials, optionally using OpenRouter's web search (Exa, limited to Royal Road, Reddit, Goodreads, Scribble Hub and Novel Updates). The taste profile is built from the library: finished/started works grouped by series or web serial, ratings, reading time, last read, DNFs, genre/tag hours, followed serials and feedback on earlier picks. Reviews and highlights are only sent when allowed in settings. Feedback (not interested, already read, doesn't exist, saved) is kept per title and fed into later runs. Runs record tokens, searches and cost. The key comes from OPENROUTER_API_KEY (or SHELFLOOM_OPENROUTER_API_KEY); the feature is off without it.
A For You page (More menu on phones) with three tabs: Read next (unread library books, with covers and a Read button), Discover (books and web serials to find, with a Royal Road or Z-Library link) and Saved. Each pick shows the model's reason; feedback buttons (save, read it, not for me, doesn't exist) hide the pick, with an undo, and shape the next refresh. A refresh runs in the background and the page polls until it is done; the last run's tokens, web searches and cost show below the list, and a failed run's error shows above the previous picks. Home gets an Up Next row with the read next picks. Settings gets a Recommendations section: the model (with OpenRouter's price for it), web search for Discover, sharing reviews and highlights (off by default) and weekly refreshes. The Z-Library search opens with the pick's title and author when Shelfloom has an account.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
AI recommendations through OpenRouter, in two lists:
New For You page (sidebar, or More on phones) with Read next / Discover / Saved tabs. Each pick has a reason and feedback buttons (save, read it, not for me, doesn't exist) with undo. Feedback is kept per title and fed into later runs.
What the model is told
Works grouped by series or web serial: finished/in progress counts, DNF, reading hours, ratings, when last read, genres and tags. Also genre and tag reading-hour totals, the followed web serials, and feedback lists. Reviews and highlights are only sent when "Share reviews and highlights" is on (off by default).
On a copy of the live library this comes to about 9k tokens for Read next and 6k for Discover, before search results.
Backend
internal/openrouter: small stdlib client for chat completions (structured outputs withrequire_parameters, web search server tool, usage and cost, citations) and the model list.internal/recommend: builds the profile and prompts, reads answers leniently (code fences, chatty text), and matches titles against the library.internal/server/recommendations.go: refreshes run in the background (one per kind at a time) and are recorded inrecommendation_runswith tokens, searches and cost. The last good run's picks stay visible when a newer run fails. Runs left running by a restart are marked failed on start. An optional weekly refresh runs from the background loop. If the provider rejects structured output (400 or 404), the request is retried without it.0003_recommendations.sql: tables for runs, picks and feedback.settingstable): model, web search, share notes, weekly refresh, discover kinds.Config
OPENROUTER_API_KEYSHELFLOOM_OPENROUTER_API_KEYwins if both are set)SHELFLOOM_OPENROUTER_MODELgoogle/gemini-3.8-flash)SHELFLOOM_OPENROUTER_BASE_URLTesting