This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine An ofrenda is a place where you keep the people you remember. I took that idea and built a small tool for something most families never write down: the stories that only exist in one person's voice.
With Ofrenda, I record someone telling a story, or add a voice memo. It writes down what was said, then makes a short remembrance card: a title, a paragraph about the person, a list of things they loved (foods, songs, places), and one line in their own words. I read it, fix anything that isn't true, and save it. The card goes on a shelf, and the recording sits next to it, so I can press play and hear them again.
That is how I read the theme. The ghost in the machine is a voice that outlasts the moment it was spoken.
Keep a family story before it fades. Record someone telling it (or add a voice memo), and
Ofrenda writes it down, then turns it into a short remembrance card using only what was said
Everything runs on your laptop: Whisper (speech to text) and an open-weight model through
Ollama. No account, no API key, no cloud. Stories are saved as plain files (text, JSON and the
original audio) in a memories/ folder, so they never depend on a service that might disappear.
ollama pull gemma3:4b
run.bat. Your browser opens at To run it on Windows: install Python and Ollama, run ollama pull gemma3:4b, then double-click run.bat. The first start downloads the speech model, so it needs internet once.
I wrote the first version with an AI coding assistant (Claude). It is a small Flask server with one page, and two open models that both run on my laptop.
Whisper does the listening. The browser records audio (or I upload a voice memo) and sends it to Flask. faster-whisper runs the small model on the CPU and writes down the speech. I choose the language first (English, Hindi, Bengali or Spanish), or let it work it out. The recording waits aside until I press Save.
Gemma 3 (4B) does the writing, through Ollama. I send the transcript and ask for a JSON answer with four fields: title, remembrance, loved and quote. The temperature is low (0.3) so it stays close to the text.
The part I worried about most is the model making things up. For a memorial, an invented detail is worse than a boring one. I used three guardrails:
What this doesn't cover: the paragraph and the list of things they loved are not checked by code. They rely on the prompt and on me reading them.
Plain files, not an app database. Each saved story is a folder in memories/, with a story.json (transcript and card) and the original audio. That folder is in .gitignore, so family stories can't be uploaded to GitHub by accident.
One thing broke. On a fresh install, transcription failed with open() got an unexpected keyword argument 'metadata_errors'. A new version of PyAV, the library faster-whisper uses to open audio, removed an argument that faster-whisper still passes. Pinning av<19 in requirements.txt fixed it.
Limits I know about:
A family's voices and stories are about as private as data gets. Because Whisper and Gemma run on my own laptop, the audio and the transcript never go to anyone's server.
The theme asks about making sure what you build isn't locked inside a service that might disappear. That was the main reason I chose plain files. Everything Ofrenda saves is a JSON file and an audio file that any program can open. If Ofrenda disappeared tomorrow, the stories would still be there, and the models I downloaded would still run.
It also costs nothing to run. I could test a recording again and again without a bill or a limit. The Whisper size, the model and the writing instructions are each one line or paragraph I can change.
A bigger hosted model would probably write a smoother remembrance, and recognise Hindi and Bengali better. For a story like this, I would still choose privacy and plain files.
I recorded my aunt telling the story of her first job, for about three
minutes. She didn't want to be recorded at first, so I told her it was
just a test.
When I played it back she was quiet for a moment, then said: "I sound
exactly like my mother."
What surprised me: she corrected the transcript herself, and fixed a
street name I never would have known was wrong.
What the card got wrong: it said she "loved the city", which she never
said. I deleted that line before saving.
I haven't shown the card to anyone yet. But her voice is in a folder
now, and that's the part I'm keeping.