This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine.
🕯️ Memory Keeper AI — Because Some Stories Deserve to Live Forever
What if AI could help us preserve the stories behind our most meaningful memories, without sending those memories to the cloud?
That question inspired me to build Memory Keeper AI, a privacy-first digital memory preservation application powered by Gemma 3 1B, Ollama, React, and Express.js.
We take photographs, save messages, and capture countless moments throughout our lives. But photographs don't always capture the conversations, emotions, and little details that make a memory truly special.
Sometimes, those details slowly disappear.
I wanted to explore how locally running AI could help preserve those personal stories in a meaningful way.
And that became Memory Keeper AI.
What I Built
Memory Keeper AI is a local AI-powered web application that transforms personal memories into thoughtful, beautifully written stories.
Users can write about a childhood experience, family tradition, special celebration, or someone they want to remember.
The application then uses Gemma running locally through Ollama to help turn that memory into a meaningful narrative while keeping the original details intact.
✨ Key Features
📝 Create Personal Memories
Users can enter a memory title, describe what happened, and optionally identify the person associated with that memory.
🤖 AI-Powered Storytelling
Gemma transforms the original memory into a readable narrative, complete with a meaningful title and closing reflection.
❤️ Choose an Emotional Tone
Users can choose between three storytelling styles:
- Warm & Loving — for heartfelt memories.
- Reflective — for thoughtful, nostalgic moments.
- Celebratory — for happy experiences and special occasions.
📚 Memory Collection
Generated stories are initially saved as drafts. Users can review them, preserve them in their collection, search existing memories, and revisit them later.
🔐 Local AI Processing
The application runs Gemma on the user's computer through Ollama, without sending memory prompts to an external AI API.
🌙 A Nostalgic User Interface
I designed the React frontend with warm colors, subtle visual details, and an interface inspired by journals, handwritten letters, and treasured memories.
The goal was to create something that feels personal rather than technical.
👻 How It Connects to Ghost in the Machine
When I first read the challenge theme, I thought about the relationship between technology and the past.
Halloween often celebrates the mysterious and supernatural. Día de los Muertos, meanwhile, inspires reflection on remembrance, family, and the people whose stories remain part of our lives.
I wanted to interpret Ghost in the Machine differently.
Instead of building an AI that pretends to communicate with the dead, I built something that helps preserve the authentic memories we already have.
For me, the "ghost" is the memory of a moment that is no longer happening but continues to live through its story.
And the "machine" is an AI writing companion that helps us preserve that story.
The AI doesn't bring someone back. It helps us remember what made them unforgettable.
Demo
🎥 Watch Memory Keeper AI in Action
Watch the full demo on YouTube
The demonstration shows the Memory Keeper application and its core workflow:
- Opening the React dashboard.
- Creating a new personal memory.
- Selecting an emotional storytelling tone.
- Generating a narrative using Gemma through Ollama.
- Reviewing the AI-generated story.
- Preserving the memory in the local collection.
There is no paid cloud AI API involved in generating the story.
The inference happens locally.
Code
💻 GitHub Repository: Memory Keeper AI — Source Code
The project uses a simple React and Express architecture so that other developers can understand it, run it locally, and experiment with their own models.
Project Structure
memory-keeper-ai/
├── client/
│ ├── src/
│ │ ├── App.jsx
│ │ ├── App.css
│ │ ├── index.css
│ │ └── main.jsx
│ ├── vite.config.js
│ └── package.json
│
├── server/
│ ├── data/
│ │ └── memories.json
│ ├── index.js
│ └── package.json
│
└── README.md
The project intentionally uses JSON file storage instead of a cloud database, keeping the initial implementation lightweight and easy to run.
Personal memory data should stay out of the public GitHub repository.
How I Built It
I used technologies I was already comfortable working with and focused on making the AI integration the central part of the application.
🛠️ Technology Stack
| Component | Technology |
|---|---|
| Frontend | React.js + Vite |
| Styling | CSS + Lucide React |
| Backend | Node.js + Express.js |
| AI Model | Gemma 3 1B |
| AI Runtime | Ollama |
| Storage | Local JSON Files |
| Communication | REST API |
Step 1 — Running Gemma Locally
I chose Gemma 3 1B because I wanted a relatively lightweight model that could be run locally and integrated into a small web application.
Ollama made the integration straightforward.
After installing Ollama, I downloaded the model using:
ollama pull gemma3:1b
I tested the model directly:
ollama run gemma3:1b
Once the model was responding successfully, I connected it to my Express backend.
Step 2 — Building the Express Backend
I created a simple Express server to handle memory generation and storage.
The main AI endpoint is:
POST /api/generate-memory-story
It receives a title, memory description, person, and selected storytelling tone.
The backend builds a prompt and sends it to the local Ollama API:
const response = await fetch(
"http://127.0.0.1:11434/api/chat",
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "gemma3:1b",
messages: [
{
role: "user",
content: prompt
}
],
stream: false,
format: "json",
options: {
temperature: 0.3
}
})
}
);
The generated content is processed by Express and stored as a memory draft.
I used Ollama's JSON output mode because I needed a predictable response structure.
The expected response includes:
{
"story_title": "Evenings Under the Mango Tree",
"story": "The generated memory narrative...",
"closing_note": "A thoughtful closing reflection..."
}
Step 3 — Designing the AI Prompt
This was one of the most important parts of the implementation.
Memory Keeper is not supposed to invent fictional events about real people.
I wanted Gemma to improve the storytelling while respecting what the user actually remembered.
So I included instructions such as:
You are Memory Keeper AI,
a compassionate local AI writing assistant.
Use ONLY the facts provided by the user.
Do not invent names, places, dates,
events, or quotations.
If the memory is short, keep the story short.
Use a respectful and natural tone.
Do not pretend to contact or speak
for deceased people.
Write in the same language as
the original memory.
This doesn't guarantee perfect factual accuracy, but it gives the model clear boundaries and helps keep the experience focused on preservation rather than invention.
Step 4 — Storing Memories Locally
Instead of using a database service, I stored generated memories in a local JSON file.
Each record includes:
- Unique memory ID
- Original title and description
- Associated person
- Storytelling tone
- AI-generated title and narrative
- Closing reflection
- Draft or saved status
- Creation timestamp
This approach was enough for the first working prototype.
It also made the application easy to set up without additional infrastructure.
Step 5 — Building the React Frontend
For the frontend, I used React with Vite and regular CSS.
I wanted the interface to feel like opening a personal journal.
The application includes:
- An overview dashboard.
- A memory creation form.
- Storytelling tone selection.
- An AI story-reading interface.
- A searchable memory collection.
- Light and dark themes.
The React application communicates with Express through REST endpoints.
Step 6 — Connecting Everything
The complete flow looks like this:
User writes a memory
|
v
React Frontend
|
v
Express REST API
|
v
Ollama + Gemma 3 1B
|
v
AI-generated memory story
|
v
Local JSON storage
|
v
Review and preserve memory
The AI isn't simply an extra feature.
It is the part of the application that transforms a personal recollection into a readable story.
Without Gemma, Memory Keeper would only be a basic digital journal.
Challenges and Lessons Learned
One challenge was designing the output format.
A normal AI response could contain paragraphs in an unpredictable structure. But my frontend needed separate fields for the story title, body, and closing note.
Using Ollama's JSON output option and validating the returned fields helped me make the API easier to work with.
Another important consideration was factual accuracy.
Because the project deals with real memories, I couldn't treat creative storytelling in the same way as ordinary fictional text generation.
I needed a prompt that encouraged emotionally meaningful writing without deliberately adding imaginary facts.
I also learned that local inference introduces its own tradeoffs.
The experience depends on the model installed, the user's hardware, and whether Ollama is running. The first response can be slower than later responses, particularly on less powerful computers.
But for this project, local control was an important part of the design.
Why Does Open Innovation Matter?
For Memory Keeper AI, choosing an open-weight model wasn't simply a technical preference.
It was directly connected to the purpose of the application.
1. Personal Memories Deserve Privacy
A memory might include personal family experiences, private feelings, or stories about people who are no longer with us.
I didn't want the application to require uploading those memories to an external AI provider.
With Gemma and Ollama, the prompts are processed locally.
2. No Cloud AI Subscription Required
Memory Keeper doesn't depend on a paid AI API for story generation.
Users provide their own computing resources, and the local model performs the inference.
This makes experimenting with the application more accessible without per-request cloud inference charges.
3. The Application Can Work Offline
Once Node.js dependencies, the frontend assets, Ollama, and Gemma are installed, the core memory-generation workflow can run locally without an internet connection.
The current frontend uses externally hosted Google Fonts, so those assets would need to be bundled locally or replaced with system fonts for a completely offline interface.
4. Developers Can Experiment
Because the model is running locally, I can change the prompt, adjust the generation settings, and experiment with other compatible models.
I'm not restricted to a single external AI provider.
5. Simplicity Matters
Open-weight AI allowed me to create a complete working AI application using familiar tools:
React, Express, Ollama, Gemma, and a JSON file.
There was no need to set up paid inference infrastructure or a complicated agent framework.
That simplicity made the project practical to build during a time-limited hackathon.
For me, open innovation means having the freedom to build useful AI applications without giving up control of the technology or the data.
The Spirit of It
I tested the application using a memory about spending childhood evenings with a grandmother.
The original memory described sitting beneath a mango tree, listening to childhood stories, and watching the sunset together.
It was a simple memory.
But it represented exactly the kind of moment Memory Keeper was designed to preserve.
The application took that recollection and turned it into a narrative that could be saved and revisited.
That test helped me appreciate the difference between generating content and preserving meaning.
The most important part of Memory Keeper isn't that AI can write beautiful sentences.
It's that someone's own words remain the foundation of the story.
AI should help us tell our stories, not replace them with its own.
And that is what I wanted this project to demonstrate.
Prize Categories
🏆 Best Use of Gemma
I'm submitting Memory Keeper AI for the Best Use of Gemma category.
Gemma 3 1B is central to the project's functionality.
It is responsible for transforming user-provided memories into structured narratives, including titles, stories, and closing reflections.
The model runs locally through Ollama, and the backend integrates directly with its inference API.
This application demonstrates a practical and privacy-conscious use of Gemma for personal storytelling and memory preservation.
What's Next?
Memory Keeper AI is currently a working local prototype.
In the future, I'd like to explore:
- Digital time capsules for special occasions.
- A chronological memory timeline.
- Photo attachments for memories.
- PDF exports of preserved stories.
- Multilingual memory preservation.
- Local audio transcription for family stories.
- Additional privacy and encryption features.
These improvements could help make Memory Keeper useful beyond the hackathon.
Final Thoughts ❤️
We often think of AI as something that should help us move faster, create more, or automate our work.
But I wanted to explore a different possibility.
What if AI could help us slow down and remember?
Memory Keeper AI is a small experiment in preserving the moments that shape our lives, using open-weight technology that gives users control over their stories.
Because the past isn't just a collection of dates and photographs.
It's made of the people we loved, the places we visited, the lessons we learned, and the ordinary moments that became unforgettable.
Every memory matters. Every story deserves to be remembered. 🕯️
Thank you to the DEV Community and Hacktoberfest for inspiring me to build this project.
Built with ❤️ using React, Express.js, Gemma, and Ollama.
#hacktoberfest #hf26challenge #ai #opensource
Top comments (0)