-
Start screen: favourites, city, budget, end time, and noise, crowd and lighting limits. Three seeded examples.
-
A timed three-stop plan with taste-match evidence for each stop (shown with sample venues in mock mode).
-
Quiet fallback, a film to carry the mood, practical tips, and liked places left out with the reason (noise, crowds, budget).
-
Why Qloo matters: a generic LLM plan beside the taste-grounded plan that is checked against your limits (sample venues in mock mode).
-
Live Qloo data (local run, 24 Oct): a quiet Manchester evening at the Holden Gallery, Burgess Foundation, Portico Library
Inspiration
Planning an evening out can take a lot of work when noise, crowds, lighting, cost and the time you need to be home all matter. Popularity alone is not enough. I wanted to test whether Qloo's taste relationships could help find places that feel personally relevant without treating an affinity score as a fact about an individual.
QuietNight is for neurodivergent adults who want a usable plan and a clear account of why each place was selected. It does not diagnose sensory needs. The user states their own limits.
What it does
Try it in 20 seconds: open the demo, click "Gentle Ghibli evening" under Try an example, then Plan my evening. You get timed stops in London that fit "quiet, soft light, home by 21:00", a film, the louder matches it left out and why, and a generic plan beside it for comparison.
The user enters one to four favourite films, TV shows, artists, books, places or video games, then chooses a city, day, budget per stop, end time, and limits for noise, crowds and lighting.
QuietNight works as a small tool-using agent with fixed, inspectable steps. It resolves the favourites to Qloo entities, asks Qloo for taste-related places and a film, estimates the likely sensory load of each place from its tags and description, removes places that break a stated limit, and ranks what remains. It returns up to three timed stops, a quieter fallback, a film that carries the mood, and a list of attractive matches it left out. The interface also puts a generic plan beside the Qloo-grounded plan and shows the request trace. If a stop cannot be filled, it re-plans before giving up: it tries a shorter visit and other times between the neighbouring stops, then moves the whole evening earlier, and lists each attempt in the trace. Sensory limits, budget and the end time are never relaxed.
The sensory levels are labelled as estimates, not measurements. Opening hours can be stale and users are told to check with each venue. Taste evidence is phrased as a group tendency — "people who like X also tend to like this" — rather than a prediction about the user.
The deployed demo currently runs with clearly labelled fictional sample data: the mode field of every plan response reports Qloo as mock and the language model as workers-ai (Gemma 4 writes the narrative live). No login is required.
How we built it
I built QuietNight as a dependency-free Node.js 18 application with a deterministic planning pipeline. The same planner is exposed through local Node, Vercel and Netlify handlers and a Cloudflare Worker. The browser client is plain HTML, CSS and JavaScript. The agent loop is deliberately split. Qloo calls decide which entities and places are relevant, and fixed rules decide what fits the user's limits. Only then does a language-model call (Gemma 4 on Cloudflare Workers AI, with OpenRouter as a fallback) turn the structured result into the short narrative and write the generic comparison, so the model never chooses venues, scores or times. If no model is reachable, labelled sample text is used. The public demo caches repeat requests and limits requests per visitor.
The Qloo client uses https://hackathon.api.qloo.com and sends the API key only in the server-side X-Api-Key header. These are the exact calls and parameters implemented in the code:
- For each favourite,
GET /searchwith:query=<the favourite text>take=1types=<type URN>
The UI-to-URN mappings are film -> urn:entity:movie, tv -> urn:entity:tv_show, artist -> urn:entity:artist, book -> urn:entity:book, place -> urn:entity:place, and game -> urn:entity:video_game.
For place candidates,
GET /v2/insightswith:filter.type=urn:entity:placesignal.interests.entities=<comma-separated IDs returned by /search>filter.location.query=<the user's city or area>feature.explainability=truetake=30
In parallel, for the film pick,
GET /v2/insightswith:filter.type=urn:entity:moviesignal.interests.entities=<the same comma-separated entity IDs>feature.explainability=truetake=6
The planner normalises the returned entities, then combines Qloo affinity with a sensory-fit score. The sensory layer looks for explicit keywords in Qloo tags and descriptions, checks available hours, applies the user's budget, and rejects hard failures. It builds a schedule backwards from the requested end time with 15-minute gaps. Qloo explainability entries are kept for the evidence line, and excluded high-affinity places are shown with the reason they failed.
Only favourite text, the city or area, and Qloo entity IDs resolved from those favourites are sent to Qloo. Names, email addresses and device identifiers are not collected or sent. The key is not returned to the browser or included in the trace.
Challenges we ran into
Qloo does not provide measured noise or crowd levels, so I had to keep taste relevance separate from sensory suitability. QuietNight makes a limited, inspectable estimate from words in tags and descriptions, labels it as estimated, and shows why a place was filtered instead of presenting the estimate as fact.
The response fields can vary by entity type, so the normaliser accepts anticipated alternatives such as entity_id or id, types or type, and nested place properties. I tested that path against the live hackathon API on 24 October: every /search and /v2/insights call for the three example journeys returned HTTP 200, and live data exposed three bugs that sample data hid. "Edinburgh" resolved to Edinburgh, Indiana, so cities are now sent as "City, UK". A hotel was chosen as a stop, so Qloo category tags are now kept and lodging is never a stop. The fallback picked an uncategorised charity, so it now leaves the slot empty and says so. With live data the Manchester and Edinburgh examples return three stops (among them the Portico Library and Armchair Books) and the London one returns two.
It was also important to keep the application useful when a perfect three-stop sequence was impossible. The planner can return a shorter plan rather than silently adding a venue that breaks the user's limits.
Accomplishments that we're proud of
- A complete path from free-text favourites to a timed, sensory-filtered plan, a quieter fallback and visible provenance (run end to end on sample data in the hosted demo, and against the live Qloo API locally).
- A side-by-side comparison designed to make Qloo's contribution visible instead of showing an isolated API response (the generic side is a live model answer with no Qloo data; in mock mode the QuietNight side uses sample venues). In one live run for a Leeds user who asked for quiet and no crowds, the generic plan sent them to a restaurant it called "vibrant, slightly chaotic".
- Transparent exclusions: users can see when a place had strong taste affinity but failed a noise, crowd, lighting or budget rule.
- Server-side key handling, bounded and sanitised inputs, and browser rendering through
textContentrather than live HTML insertion. - Fifteen passing automated tests, run against the mock data layer, covering the three seeded journeys, sensory and budget exclusions, requested-city mock addresses, input validation and differing results for differing favourites.
- A responsive single-page interface with semantic headings, a skip link, visible focus styles, large type, reduced-motion support and dark-mode styling.
What we learned
Taste affinity and sensory suitability answer different questions. A place can be a strong Qloo match and still be wrong for a quiet evening. Keeping those scores separate made the result easier to explain and made exclusions as useful as recommendations.
Qloo explainability also needs careful language. It can support a statement about patterns among people who like an entity; it does not establish what one person will like. The product copy and narrative prompt preserve that distinction.
Finally, deterministic selection matters here. A language model is useful for concise wording, but venue choice, filtering, timing and evidence should stay tied to structured data and visible rules.
What's next for QuietNight
First, I will switch the hosted demo from sample data to the live Qloo API. The code is deployed and has been tested against live responses; only the server-side key remains to be set. I will then publish one redacted request-to-result example here.
After that, the next useful additions are travel-time checks between stops, direct links for confirming current opening hours, and Qloo tag lookup to make category selection less dependent on keywords. A later version could let users save a sensory profile locally on their own device, without sending identity data to Qloo.
Built With
- cloudflare-workers
- cloudflare-workers-ai
- css3
- gemma
- html5
- javascript
- node.js
- openrouter
- qloo