Spaces:
Runtime error
A newer version of the Gradio SDK is available: 6.20.0
How Teach / discovery mode works
Teach mode is where the Oracle learns. When it meets something not in its database, the player tells it what they were thinking of, and the model reasons out that item's attributes and saves them โ so next time, the Oracle just knows.
All of this lives in discovery.py, exposed through app.py's @app.api("learn")
endpoint and the Teach UI in index.html.
When it triggers
- The Oracle runs out of candidates โ
engine.filter_candidates()returns 0, sonext_turnreturnsaction: "giveup"and the UI shows the Teach panel. - The Oracle guesses wrong โ the player clicks "No", which opens Teach.
- The ๏ผ Teach button โ the player adds something any time, no game needed (a category picker appears so they can choose animal / fruit / vegetable).
The learn flow
flowchart TD
A[player names the item] --> B[_canonical: resolve aliases]
B --> C{already in DB?}
C -->|yes| D[find_contradictions โ explain wrong answers]
C -->|no| E[gather attributes from 3 sources]
E --> F[add_item โ write JSON, persist, refresh cache]
F --> G[learned!]
discovery.learn_item(category, name, history) is the entry point.
1. Resolve the name
_canonical() maps aliases and spelling variants to the canonical DB name โ
chilli/chili โ chili pepper, aubergine โ eggplant, courgette โ
zucchini, etc. This stops the app from creating junk duplicates of things it
already knows.
2. If it's already known โ explain the mistake
If the item exists, the Oracle didn't lack the data โ the player's answers steered
it wrong. find_contradictions() compares each in-game answer to the item's true
attributes and reports the genuine mismatches with a plain-English reason from
ATTR_REASON:
โ You answered No to "Is it starchy?", but a potato is starchy โ it should have been Yes.
Only real contradictions are flagged; correct answers and "I'm not sure" are ignored.
3. If it's new โ fill every attribute from three sources
A learned item must be complete (define every attribute) or it can't be told apart from others. Attributes are gathered in order of trust:
- The player's own in-game answers โ
attributes_from_history(). They were thinking of it, so their yes/no answers are ground truth for their item. - The model โ
derive_attributes()asks the Llama model (viallm.py) to fill the category's attribute table as true/false/unknown, optionally grounded by a short Wikipedia summary (fetch_web_context(), controlled byORACLE_DISCOVERY_WEB). The model's answers overlay the player's. - The existing database โ
complete_attributes()fills anything still unknown by majority vote among the most similar known items (nearest-neighbour). Fully offline and deterministic.
The result is always a full attribute set, even with no model and no network.
4. Save it
add_item() appends the record to the category's JSON file, persists it (in
ORACLE_DATA_DIR / the mounted bucket, so it survives restarts), and clears the
engine cache so the next game sees the new item immediately โ no restart.
Why this design
- The model does real reasoning here โ turning "rambutan" + a Wikipedia blurb into a structured attribute profile is genuine work a lookup table can't do. This is the part of the app where the tiny model is most load-bearing.
- It never corrupts the truth โ known items are explained, not overwritten; new items are completed from multiple sources and then validated.
Validate after teaching
Run the database checker any time you've added items (it's also a great guard for hand-edits):
python check_db.py # COMPLETE ยท UNIQUE ยท GUESSABLE ยท BALANCED
It confirms every item defines every attribute, no two items are identical, and a simulated game can still guess each one.
Related env vars
| Var | Effect |
|---|---|
ORACLE_QUESTION_LLM=1 |
use the model to derive attributes for new items |
ORACLE_DISCOVERY_WEB=1 |
allow Wikipedia grounding while learning |
ORACLE_DATA_DIR=/data |
persist learned items to a mounted Storage Bucket |