Spaces:
Runtime error
A newer version of the Gradio SDK is available: 6.20.0
title: The Oracle
emoji: ๐ฎ
colorFrom: indigo
colorTo: yellow
sdk: gradio
sdk_version: 6.16.0
python_version: '3.13'
app_file: app.py
pinned: false
license: mit
short_description: Oracle An Akinator-style guessing game
models:
- bartowski/Llama-3.2-1B-Instruct-GGUF
- bartowski/Llama-3.2-3B-Instruct-GGUF
tags:
- build-small-hackathon
- thousand-token-wood
- llama
- llama-cpp
- gradio
- game
- guessing-game
- offline-first
- on-device
๐ฎ The Oracle
Think of an animal, a fruit, or a vegetable. The Oracle asks simple yes/no questions and divines exactly what you're thinking โ an Akinator-style mind-reader. Built with Llama ๐ฆ and designed to run fully offline.
Built for the Build Small Hackathon ยท An Adventure in Thousand Token Wood.
Model
- Llama 3.2 1B Instruct
(
Llama-3.2-1B-Instruct-Q4_K_M.gguf) โ what the live Space runs โ through the llama.cpp runtime (in-process viallama-cpp-python). Just 1B parameters, far under the โค32B limit and the โค4B Tiny Titan bar. It's used only to phrase questions and to derive attributes when learning a new item; all deduction is pure deterministic code, so a 1B model is plenty. - Also supports Llama 3.2 3B Instruct
(the default) for slightly richer phrasing โ set via
ORACLE_LLAMA_REPO/ORACLE_LLAMA_FILE.
Because questions are pre-generated once at boot and cached (persisted in the Storage Bucket), the model size barely affects gameplay โ the live cache holds all 42 questions, so each turn is an instant lookup.
Badges & prizes we're targeting
| Target | Status | How |
|---|---|---|
| ๐ Off the Grid | โ | no cloud APIs; the engine + cached questions run fully offline |
| ๐จ Off-Brand | โ | fully custom crystal-ball UI (art, buttons, reveal), not default Gradio |
| ๐ Field Notes | โ | the design journey above + the two deep-dive docs / this write-up |
| ๐ฆ Llama Champion | โ | the model runs through the llama.cpp runtime (ORACLE_QUESTION_LLM=1) |
| ๐ Tiny Titan (special award) | ๐ฏ | built on a genuinely tiny โค4B model (Llama-3.2-3B) |
| ๐ก Sharing is Caring | optional | the attribute database is shareable as a dataset |
| ๐ฏ Well-Tuned | โ๏ธ n/a | deliberately no fine-tuned model โ accuracy comes from the engine |
Demo
X post
https://x.com/i/status/2064387556376981633
Why it fits the track
The game spends almost no tokens per turn. A deterministic engine does the deduction over a small attribute database, and a tiny Llama 3.2 3B model is used only to phrase questions in natural language (pre-generated at boot, so gameplay is instant). Small model, small token budget, no network required.
Design journey
Attempt 1 โ one model did everything (ask and guess). It asked repetitive, elimination-style questions, never narrowed down, and games didn't end.
Attempt 2 โ two models: one writes questions, one eliminates items from a list. Questions got better, but elimination was slow and wrong on large lists, and the model's facts couldn't be trusted (it called a tomato a root vegetable).
Final โ facts in a JSON attribute database; a deterministic engine does all the elimination; the small model only phrases the questions (generated once at boot and cached, so gameplay is instant). A Teach mode lets it learn new items from Wikipedia, so the database grows on its own.
flowchart TD
A[Boot] --> B(Model pre-generates natural questions, cached)
B --> C(Gameplay: deterministic elimination engine)
C --> D(Learning: model extracts facts from Wikipedia)
How it works
answers so far โโบ engine.filter_candidates โโบ engine.choose_attribute โโบ look up cached question โโบ ask
โโบ 1 left โ guess 0 left โ discovery/teach
(the cached questions are written by Llama once at boot โ see How question generation works)
- engine.py โ pure-Python core. Filters candidates by the answers (exact, no model), then picks the attribute that best splits the set (max info gain). Auto-reloads the JSON if it changes on disk.
- data/*.json โ the attribute database (animals / fruits / vegetables); the single source of truth. Every item defines every attribute.
- question_maker.py โ the only place the LLM is used: turn an attribute into a natural yes/no question. Pre-generated at boot and cached (instant in-game), with built-in phrasing as fallback. Never decides elimination.
- llm.py โ runs the model through the llama.cpp runtime (in-process via
llama-cpp-python, or an HTTPllama-serverfor local dev), with thread caps, a timeout, and warmup so it can never hang the game. - discovery.py โ when the Oracle doesn't know an item, the player teaches it; attributes are filled from the player's answers, the LLM, and the existing DB, so the new item is complete and guessable next time. Also explains why a wrong answer threw it off.
- app.py โ
gradio.Server:@app.api("next")per turn,@app.api("learn")for teaching, servesindex.html. - index.html โ a fully custom crystal-ball UI (image art, category pick, image answer buttons, "I'm not sure", dramatic reveal, Teach mode).
- check_db.py โ validator: completeness, uniqueness, guessability, balance.
Deep dives
- How question generation works โ the engine picks the attribute, the model only phrases it, and questions are pre-generated and cached at boot for instant gameplay.
- How Teach / discovery works โ how the Oracle learns a new item (player answers + Llama + Wikipedia + the existing DB) and explains why a wrong answer threw it off.
Run locally
pip install -r requirements.txt
python app.py # plays immediately, offline (built-in question phrasing)
For natural, model-written questions (runs the 3B model in-process via llama.cpp โ the GGUF downloads once from the Hub):
ORACLE_QUESTION_LLM=1 python app.py
(Alternatively, run a local llama-server and set ORACLE_LLAMA_URL.)
Test & validate
pytest -q # 20 offline tests
python check_db.py # validate the attribute database
Deploy (Hugging Face Spaces ยท Gradio)
Push these files to a Space under build-small-hackathon; the Gradio SDK runs
app.py on port 7860. The game works offline out of the box. To persist items
taught during play and to run the Llama model on the Space (for the Llama
Champion badge), see DEPLOY.md โ in short: mount a Storage
Bucket at /data, set ORACLE_DATA_DIR=/data, and set ORACLE_QUESTION_LLM=1.
Config (env vars)
| Var | Default | Purpose |
|---|---|---|
ORACLE_QUESTION_LLM |
1 |
1 = model-written questions via llama.cpp; 0 = built-in phrasing (no model) |
ORACLE_REVEAL_LLM |
0 |
1 = model writes the pre-guess reveal line; 0 = instant templated line |
ORACLE_DISCOVERY_WEB |
1 |
1 = allow Wikipedia grounding when teaching a new item |
ORACLE_DATA_DIR |
(bundled data/) |
point at a mounted HF Storage Bucket (e.g. /data) to persist learned items; the model also caches in <dir>/models/ |
ORACLE_MODEL_DIR |
(<ORACLE_DATA_DIR>/models) |
override where the GGUF model is downloaded/cached |
ORACLE_LLAMA_REPO / ORACLE_LLAMA_FILE |
Llama-3.2-3B GGUF | swap the model (e.g. the 1B for more speed) |
ORACLE_LLAMA_URL |
http://localhost:8080/v1/chat/completions |
external llama-server endpoint (HTTP fallback) |
ORACLE_LLAMA_THREADS |
(cores available, capped at 4) | llama.cpp threads โ keep small on CPU Spaces |
ORACLE_LLM_TIMEOUT |
25 |
seconds before a slow generation gives up and uses built-in phrasing |
ORACLE_MAX_QUESTIONS |
20 |
force a guess after this many questions |
MIT
