DEV Community

Ayush Kumar
Ayush Kumar

Posted on Edited on Fully Autonomous

Dead Air: a ghost station running on my own CPU

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine

What I Built

Dead Air is a fictional shortwave radio. You give it a place, something that doesn't belong there, and a feeling. It returns a short transmission from whoever—or whatever—might still be listening.

The default note is an abandoned railway station where the next train is announced in the listener's own voice. Other starting points include an empty family home with a table set for someone who is gone, and a lighthouse whose foghorn seems to answer questions.

In the recorded test, the station answered:

"The next train will arrive soon," my voice echoes through the deserted corridors of the old station. But something's off; there's no other sound besides mine now.

These are prompts, not a library of finished stories. Every transmission comes from a small open-weight model running on the same computer as the app.

I took “Ghost in the Machine” literally: a machine invents the voice at the other end. The interface looks like a receiver left on after the last broadcast. There's a speaker grille, a tuning needle, and a pale green display. The dial is decorative. The listener note is what changes the story.

Demo

Watch the recorded walkthrough

The walkthrough shows the actual local app generating a transmission and saving it as a text file. The model is cached before the recording; the first download is about 1.41 GB. There is no cloud generation fallback.

Code

Source code and local setup

The application code is MIT licensed. The README includes setup commands, the model's license and attribution, the privacy boundary, and known limitations.

How I Built It

The core is HuggingFaceTB/SmolLM2-1.7B-Instruct, an Apache-2.0 open-weight model. Transformers.js loads its q4 ONNX weights and runs them through ONNX Runtime on the CPU.

The browser sends three fields to a Node HTTP server bound to the loopback address. The server checks their types and lengths, builds a short chat prompt with one example, and asks for a brief, non-graphic transmission. It allows one generation at a time and caps each response at 140 new tokens.

I first tried the 360M version of SmolLM2. It ran, but often wandered away from the listener's note. The 1.7B model with a short example followed the scene more closely in the local tests. In the recording, the request took 27.7 seconds, including loading the cached weights into memory. That's an observation from this machine, not a speed guarantee.

The interface is plain HTML, CSS, and JavaScript. There is no frontend build step. It uses installed fonts and local assets, so the page doesn't need a CDN. Received text is inserted with textContent; it cannot become executable page markup.

The little details have jobs. The moving needle tells you the model is busy. Loading status reports the real model download. An unsuccessful request keeps your note and the last received story. Saving a transmission includes its prompt, time, and model name so the story has some provenance outside the page.

The small model is also the main limitation. It can miss a detail, repeat itself, or run into the token limit mid-sentence. I kept those limits visible instead of adding canned responses when generation disappoints. There are automated checks for the HTTP boundary and failure recovery, alongside separate real-model and browser checks documented in the repository.

AI assistance was used for implementation, verification, and this write-up. The fiction users receive is generated by SmolLM2 itself.

Why Does Open Innovation Matter?

A ghost story about a childhood home can start with a real memory. I wanted that note to stay on the listener's own computer. After the one-time download from Hugging Face, the model runs from its local cache; the app also has a cache-only mode that refuses remote model downloads.

There is no provider account or per-transmission API bill. That doesn't make inference free of resource costs: it still uses the computer's memory, CPU, and electricity. But the listener can keep running the downloaded app and weights without depending on a hosted inference endpoint.

The prompt and generation settings are small enough to read in one file. Someone can change the station's voice, inspect what gets sent to the model, or adapt the project for their own fiction. SmolLM2's open weights and permissive license make that practical.

Dead Air won't contact the dead, and it won't always write a good ending. It will give a small machine a strange place to think about—and let the result stay with the person who asked.

Top comments (0)