Spaces:
Running on Zero
Running on Zero
| # The face was always there: building PAREIDOLIA with two small OpenBMB models | |
| *A Build Small Hackathon field report β Thousand Token Wood.* | |
| *Live: [build-small-hackathon/pareidolia](https://huggingface.co/spaces/build-small-hackathon/pareidolia)* | |
| --- | |
| Pareidolia is the thing your brain does when it sees a face in a power outlet, | |
| in the front of a car, in two windows and a door. Everyone has it. No app | |
| celebrates it. | |
| So we built one. Point your camera at any object. A small vision model studies | |
| the photo the way you study clouds β and the face that was *already hiding* in | |
| your fire hydrant opens its eyes, blinks at you, and tells you, in its own | |
| voice, exactly what it has been putting up with. | |
| > *"Forty years on this corner. Not one dog has shown me respect."* | |
| Two models do all of it, and together they're about **11B parameters** β well | |
| under the hackathon's 32B ceiling, and every parameter earns its place: | |
| - **[openbmb/MiniCPM-V-4_5](https://huggingface.co/openbmb/MiniCPM-V-4_5)** (8.7B) β finds the face and writes the soul. | |
| - **[openbmb/VoxCPM2](https://huggingface.co/openbmb/VoxCPM2)** (2.29B) β gives each object a distinct designed voice, from a text description alone, no reference audio. | |
| ## The one rule: taste from the model, facts from the code | |
| The failure mode that kills a project like this is obvious once you hit it: no | |
| vision model is *trained* to point at the two bolts on a hydrant and call them | |
| eyes. Ask it for pixel coordinates and it will confidently place an eye in the | |
| sky. A misplaced eye doesn't read as a quirky soul β it reads as a broken | |
| sticker. | |
| So we never let the model touch a coordinate. The sΓ©ance is one structured | |
| generation: the model **names visible features** ("the two bonnet bolts," "the | |
| front outlet cap"), reads the object's condition, and writes its grudge β then | |
| deterministic OpenCV snaps those names onto the strongest real circles, blobs, | |
| and corners nearby. The model brings taste; the code owns the facts. It's the | |
| pattern this community already celebrates, and it's the whole reason the eyes | |
| land on things that are really there. | |
| The writing is governed the same way β not vibes, but a bank of grudge | |
| archetypes keyed to an object's *visible condition* (the veteran/rusted, the | |
| martyr/worn, the perfectionist/pristine, the diva/displayed), with an iron rule | |
| that every line must reference something actually in the photo. A coffee mug | |
| with a violin-shaped handle, unprompted: *"Why a violin? Why not a guitar?"* | |
| ## The shared wall, alive with zero GPU | |
| Every awakened object joins a public **Menagerie** β one wall, shared by every | |
| visitor. Because each record is deterministic, the overlays (the blinking, the | |
| saccades, the mouth riding the audio) replay entirely client-side from JSON. | |
| The landing page is fully alive even when the GPU is asleep, and every object | |
| gets its own shareable page with a social preview card showing it *with its | |
| eyes*. The GPU only wakes when you awaken something new. | |
| Privacy is structural, not bolted on: the same generation gates real human | |
| faces and NSFW before anything else runs, and nothing reaches the public wall | |
| that hasn't passed that gate. No visitor identity is ever stored. | |
| ## What we tried, measured, and threw away | |
| The honest part. We had two "obvious" upgrades and let live measurement veto | |
| both: | |
| - **A punch-up pass** that rewrote each grudge to be funnier. Tested live on six | |
| real awakenings: zero rewrites better than the original, two grammatically | |
| broken. Our acceptance check validated *form* (length, banned openers, cites a | |
| specific) but couldn't see *coherence*. Reverted within the hour. A flat | |
| original beats a broken rewrite. | |
| - **A set-of-marks grounding flip** β let OpenCV draw numbered badges and have | |
| the model pick numbers instead of inventing coordinates. It sounded purer. The | |
| bench said no: **3/14** plausible faces versus **8/14** for the coarse-then-snap | |
| flow. The model picked badges sitting on the pavement while confabulating names | |
| for them. The real lesson: a vision model's coarse spatial *intuition*, | |
| corrected by deterministic snapping, beats its discrete *selection* over | |
| badly-curated choices. | |
| Both are written up, with their data, in the repo's | |
| [FIELD_NOTES.md](https://huggingface.co/spaces/build-small-hackathon/pareidolia/blob/main/FIELD_NOTES.md). | |
| Every awakening's full trace β the model's JSON, the snap deltas, the chosen | |
| voice β is published to a [public dataset](https://huggingface.co/datasets/AndresCarreon/pareidolia-menagerie). | |
| ## What shipped to make it survive a judging crowd | |
| - A face-**geometry gate** that measures each placed face (eyes level? cramped? | |
| mouth below? on the object?) and gives the model one in-context do-over when it | |
| fails. | |
| - A **health endpoint and an external watchdog** that auto-restarts the Space if | |
| the ZeroGPU context ever wedges. | |
| - Honest, retryable messaging when the free GPU quota is busy β *"the spirits are | |
| overwhelmed; rest a moment and try again, or sign in for your own candle"* β | |
| instead of a generic error. | |
| It's small models, used carefully, doing something that genuinely couldn't exist | |
| without them. Go wake something up. It was in there all along. ποΈ | |