Inspiration

Almost every reader has been there: you finish a book that didn't land, or life gets busy, and suddenly weeks go by without reading. Reading apps, book boxes and libraries see this as "lapsed readers", and their usual fix is a generic email: here are this month's bestsellers. That rarely works, because a bestseller list knows nothing about you.

But people in a reading slump haven't stopped loving stories. They're still binging shows, replaying games and looping albums. I wondered: what if the way back to books started from what someone already loves, even if none of it is a book? Qloo's taste graph connects exactly those things across domains, which made it the perfect engine for the idea.

What it does

Slump Breaker is a Qloo-powered agent that turns a lapsed reader's taste into a comeback book.

  • Business view: a book business uploads a CSV of lapsed readers (name, favorites, and optionally why they stopped). For each reader, Slump Breaker returns a comeback book, two alternatives, the evidence linking each book to the reader's favorites, and a ready-to-send win-back message for email, push or SMS.
  • Reader view: the same engine from the reader's side. Enter up to five favorites, say why you stopped, and get three picks with covers, ratings and reasons. "Worked / Not for me" feedback re-asks Qloo for fresh picks.
  • Why Qloo?: the same reader asked two ways, a plain AI next to the Qloo-grounded answer, side by side.

Favorites can be shows, movies, games, music artists, books, book genres (dark romance, romcom, romantasy, cozy mystery) or tropes (enemies to lovers, fake dating, second chance, found family). Every recommended book comes from Qloo, and every pick shows which favorite it came from.

How I built it

Slump Breaker is a Python + Streamlit app with a small, bounded agent at its core:

  1. resolve_entity: find each favorite in Qloo (a title, or a genre/trope as Qloo tags).
  2. get_book_recs: ask Qloo for books linked to each favorite on its own.
  3. get_blended_recs: ask Qloo for books that fit all favorites together as one taste. A genre acts as a filter here, so "Fourth Wing" + "dark romance" gives dark romance that Fourth Wing readers love.
  4. finish: Gemini chooses the final three only from what Qloo returned and writes the reason and the message. A grounding check drops anything that wasn't in Qloo's results.

Qloo calls run in parallel within the 5-requests-per-second limit, are cached for 6 hours, and retry on rate limits and server errors. Every step lands in a trace the user can open. If Gemini is down, a rule-based plan runs the same Qloo tools; if Qloo is down, clearly labelled sample data keeps the app usable.

Books are ranked by how many of the reader's favorites they connect to, then by Qloo's affinity score:

$$\text{rank}(b) = \big(\,|\text{favorites linked to } b|,\ \text{affinity}(b)\,\big)$$

Then two final rules shape the three picks: they're spread across different favorites where possible, and any pick with fewer than $10{,}000$ Goodreads ratings is swapped for a better-known book from the same Qloo results.

It's deployed on Streamlit Community Cloud, with optional Supabase sign-in and a test suite of 90 tests.

Challenges I ran into

  • Same name, different things. Qloo search mixes types: "Dune" returns a film, a book and a TV show. Worse, "Twisted Love" matched a 2026 film and an obscure 2016 book before Ana Huang's bestseller, because Qloo stores it as "Twisted Love (Twisted, #1)". I taught the matcher to ignore series tags and to prefer a far more popular match over an obscure namesake.
  • Hidden trope tags. Qloo's tag search only showed tropes like "Enemies to lovers" for TV and film, and filtering books by them returned nothing. Then I noticed book results carrying tags like enemies_to_lovers and dark_romance. They existed all along; search just didn't list them. Tropes without a usable tag start from two famous example books instead, skipping those authors so readers get new writers rather than sequels.
  • One favorite taking over. For a reader who loves Stranger Things, GTA V and Taylor Swift, all three picks said "Linked to: Grand Theft Auto V", because only GTA's books overlapped with the combined list. I added a spread step so each favorite gets a voice.
  • Weak lists for some favorites. Some favorites map to surprising books (one artist's list was all business exposés), so forcing variety could make picks worse. The fix was to only swap in well-known books, and to replace obscure picks like a manga volume 22 with well-loved ones.
  • Deployment surprises. The hosted app stayed in demo mode even after I added keys: the clients were cached once at startup, before the secrets existed. They're now cached per key value, so new secrets take effect on the next page load.

Accomplishments that I'm proud of

  • Every recommendation is grounded: no invented books, and each pick shows the favorite that led to it.
  • Genres and tropes work as real Qloo signals, not guesses, and they combine with titles ("Fourth Wing" + "dark romance" gives exactly what a Fourth Wing reader wants next).
  • It degrades gracefully: no Gemini, no Qloo, or a slow API all still give a working, honestly labelled result.
  • A 110-reader test file that exercises every kind of input, from typos and short forms to unknown tropes and spreadsheet-formula names.

What I learned

  • Real data beats assumptions. Most of my best fixes came from probing Qloo's live responses: popularity scores, series naming and hidden tags all differed from what I expected.
  • The LLM should choose and explain, not invent. Letting Qloo supply the candidates and Gemini only pick among them made the output both trustworthy and well written.
  • Recommendation quality is more than relevance. For someone in a slump, a well-loved, approachable book matters as much as a perfect taste match.

What's next for Slump Breaker

  • An Author option that starts from an author's best-known books (recommending straight from an author gave generic results).
  • More tropes and genres, and letting readers combine several ("enemies to lovers" + "romantasy").
  • Closing the loop: sending messages through email/CRM tools and learning from which comeback books actually bring readers back.
  • Smarter slump handling: shorter reads for burnout, and series starters for readers who lost the habit.

Built With

  • ai-agents
  • csv
  • function-calling
  • gemini-api
  • github
  • google-gemini
  • html
  • llm
  • pytest
  • python
  • qloo
  • qloo-api
  • qloo-taste-ai
  • recommendation-engine
  • requests
  • rest-api
  • streamlit
  • streamlit-community-cloud
  • supabase
Share this project:

Updates

Submission history