Downloads · 30 days
11
55% of all-time downloads
KernelMedia/marquee-ai
marquee-ai is a text generation model from KernelMedia. Use it when you need the model to write or continue text. It is set up for transformers. The card lists the license as apache-2.0.
v1.1 · contract v1 · base Qwen3-4B-Instruct-2507
Downloads · 30 days
11
55% of all-time downloads
All-time downloads
20
Public
Repo size
6.8 GB
Likes
1
Public
Click a slice to open those files.
.gguf3.3 GB · 85%
From the Hugging Face model README
v1.1 · contract v1 · base Qwen3-4B-Instruct-2507
Turns one item in a media library into Plex-style rows of other items in that same library. Built for self-hosted media servers.
IN: "The Sopranos"
OUT:
Shows like The Sopranos Gomorrah, Boardwalk Empire, The Wire, ZeroZeroZero
More from Tim Van Patten Game of Thrones, Black Mirror, Boardwalk Empire
More with Edie Falco Nurse Jackie, Oz
Shot by Alik Sakharov Game of Thrones, House of Cards
The model alone does nothing useful. It decides which rows to show, their order, and what to call them. It does not choose what goes in them -- a retriever does, by joining your library on shared cast, crew and franchise, and by embedding similarity.
The model never even sees item ids. It answers with index references into candidates it was handed, so it cannot invent a title that isn't in your library. Hallucination isn't low here, it's structurally impossible.
pip install marquee-ai
hf download KernelMedia/marquee-ai --local-dir marquee
cd marquee && ollama create marquee -f Modelfile
~3.6 GB: the model plus a catalog of ~195,000 films and shows with full cast and crew.
| VRAM | ~4.7 GB (Q6_K at 6144 context). Runs on a 6GB card, or CPU. |
| RAM | ~2.5 GB for the 195k-title catalog index |
| Disk | ~3.3 GB model + ~240 MB catalog + ~300 MB embeddings |
| Latency | ~1s per request on an RTX 3060; cached responses are instant |
marquee serve --library catalog.jsonl --port 8080
That's the whole setup -- catalog and embeddings ship precomputed.
POST /recommendcurl -X POST localhost:8080/recommend -H 'Content-Type: application/json' \
-d '{"title": "The Sopranos", "row_size": 20}'
{
"seed": {"id": "wd:Q23628", "title": "The Sopranos", "year": 1999,
"media_type": "tv", "rating": 0.0, "owned": true},
"rows": [
{"type": "thematic", "title": "Shows like The Sopranos",
"items": [
{"id": "wd:Q...", "title": "Gomorrah", "year": 2014,
"media_type": "tv", "owned": true},
{"id": "wd:Q...", "title": "Boardwalk Empire", "year": 2010,
"media_type": "tv", "owned": true}
]},
{"type": "director", "title": "More from Tim Van Patten",
"items": [
{"id": "wd:Q...", "title": "Game of Thrones", "year": 2011,
"media_type": "tv", "owned": true}
]}
]
}
Body: seed_id or title, plus optional year, media_type, row_size,
owned_only, semantic_k. Rows arrive in a fixed order -- thematic, franchise,
director, cast, crew.
An ambiguous title returns 409 with the candidates rather than guessing. A catalog this size holds many remakes sharing a bare title:
{"error": "22 items match 'Macbeth'; pass seed_id, or narrow with year/media_type",
"matches": [
{"id": "wd:Q15934383", "title": "Macbeth", "year": 2015, "media_type": "movie"},
{"id": "wd:Q2573008", "title": "Macbeth", "year": 1951, "media_type": "movie"}
]}
{"title": "Macbeth", "year": 2015} or {"title": "Macbeth (2015)"} resolves it.
GET /metadata and POST /metadata/batchFull catalog record for one item, or up to 500 in one call. Pure index lookups -- no
model, no GPU. Look up by id, tmdb_id, imdb_id (all exact), or title (fuzzy,
can be ambiguous like /recommend).
curl 'localhost:8080/metadata?tmdb_id=335984'
{
"id": "wd:Q21500755", "title": "Blade Runner 2049", "media_type": "movie",
"year": 2017, "genres": ["cyberpunk", "dystopian film", "neo-noir"],
"people": [{"name": "Denis Villeneuve", "role": "director"},
{"name": "Roger Deakins", "role": "cinematographer"}],
"summary": "Blade Runner 2049 is a 2017 American science fiction film...",
"franchise": "Blade Runner", "runtime_min": 164,
"country": "United Kingdom", "language": "English",
"external": {"wikidata": "Q21500755", "tmdb": "335984", "imdb": "tt1856101"}
}
curl -X POST localhost:8080/metadata/batch -H 'Content-Type: application/json' -d '{
"queries": [{"tmdb_id": 335984}, {"imdb_id": "tt0141842"}]
}'
Every query gets a result in the order sent -- found, ambiguous with candidates, or not found -- so you can zip the response against your input.
GET /search?q= and GET /person?name=/search matches titles and people in one call -- "Scorsese" isn't a title but has
109 credits. /person returns everything someone worked on, films and shows together,
ranked by a popularity-weighted score, deduplicated across roles. Both are index
lookups, no model call.
curl 'localhost:8080/person?name=Roger%20Deakins&limit=3'
{"person": "Roger Deakins", "count": 3, "credits": [
{"id": "wd:...", "title": "The Shawshank Redemption", "year": 1994,
"score": 8.66, "roles": ["cinematographer"]}
]}
score is what ranking actually uses -- popularity-weighted, so a well-known film
outranks an obscure one even without a raw rating to sort by.
GET /health and DELETE /cache{"status": "ok", "contract_version": 1,
"model_self_test": {"passed": true, "detail": "contract v1 OK (3/3 clean)"},
"library_items": 194509, "owned": 194509, "requestable": 0}
status is degraded if the self-test fails -- model and package disagree, or the
chat template is wrong. Recommendations are cached per seed; call DELETE /cache
after a library rescan or you'll serve rows referring to items you no longer have.
By default it recommends from the whole catalog. To mark what's actually on your server, so a UI can show a Request button on the rest:
marquee ingest --server library.jsonl --catalog catalog.jsonl \
--out lib.jsonl --mode requestable
marquee serve --library lib.jsonl
Your export needs one line per item; tmdb_id and media_type are enough:
{"id": "myserver-04471", "tmdb_id": 335984, "media_type": "movie"}
50 unseen holdout examples, run through plain transformers.generate with no
grammar constraint, on the unmerged adapter -- so this measures the weights, not a
decoder forcing shape, and not the quantization the GGUF ships with.
| Metric | Base Qwen3-4B | Marquee |
|---|---|---|
| JSON parses | -- | 100% |
| Fully contract-clean | -- | 100% |
| Hallucinated ids | -- | 0.0% |
| Row-order violations | -- | 0% |
That number does not carry over unchanged to the shipped GGUF: merging a LoRA adapter and quantizing it are both lossy steps this harness doesn't exercise. Measured end-to-end through actual Ollama serving (20 held-out seeds, real greedy decoding) -- Q6_K: 19/20 clean. See Limitations below for what pushed us to Q6_K over a smaller quant.
What this is, honestly: the fine-tune buys format discipline, not taste. The retriever picks every item; the model decides which rows to show and writes one row title. It does not make recommendations smarter on its own -- that lives in the retriever's embeddings and joins.
<tool_call> instead of JSON. Training
directly on real bf16 weights removes that mismatch.bge-small embeddings blended
with keyword and genre overlap; ~31% of the catalog has no plot summary to embed,
so those titles lean on genre/subject tags alone.external.tmdb/external.imdb ids in /metadata.Ollama will not use the Jinja template embedded in GGUF metadata and falls back to a
bare {{ .Prompt }} passthrough, so the model never receives the <|im_start|>
markers it was trained on and reverts to base-model behaviour. The supplied
Modelfile carries an explicit ChatML TEMPLATE block. Do not remove it.
Two things degrade output independently, and both are already handled in the shipped Modelfile/GGUF:
temperature must stay low -- 0.1 gave 8/8 clean over 8 test seeds without a
grammar, 0.3 gave 5/8. The Modelfile ships 0.1.<tool_call> tokens instead of JSON on most requests
(1/20 clean vs Q6_K's 19/20, same weights, same greedy decoding, only the quant
level changed). Q6_K is the smallest quant confirmed clean.Verify any deployment by calling it without a JSON schema. A working fine-tune
emits valid contract JSON unprompted. marquee serve runs this check at startup.
The catalog is built entirely from Wikidata (CC0) and Wikipedia (plot summaries, embedded then discarded -- never redistributed as text, so CC BY-SA's share-alike terms are never triggered). No TMDB data is shipped or was used in training.
Not used: TMDB (API terms prohibit ML training and third-party redistribution of cached content), IMDb (non-transferable, non-sublicensable licence), Rotten Tomatoes (no public API).
Apache-2.0, inherited from Qwen3-4B-Instruct-2507. Catalog: CC0.