<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ronit Solanki</title>
    <description>The latest articles on DEV Community by Ronit Solanki (@ronit_solanki).</description>
    <link>https://dev.to/ronit_solanki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4153026%2F30698017-f96d-4793-83d4-64e2681390d6.jpg</url>
      <title>DEV Community: Ronit Solanki</title>
      <link>https://dev.to/ronit_solanki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ronit_solanki"/>
    <language>en</language>
    <item>
      <title>Ofrenda: A Local AI Altar That Keeps Your Loved Ones’ Memories Alive</title>
      <dc:creator>Ronit Solanki</dc:creator>
      <pubDate>Fri, 30 Oct 2026 18:46:08 +0000</pubDate>
      <link>https://dev.to/ronit_solanki/ofrenda-a-local-ai-altar-that-keeps-your-loved-ones-memories-alive-om3</link>
      <guid>https://dev.to/ronit_solanki/ofrenda-a-local-ai-altar-that-keeps-your-loved-ones-memories-alive-om3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ofrenda&lt;/strong&gt; is a private, local altar for the people you remember.&lt;/p&gt;

&lt;p&gt;In Día de los Muertos, an &lt;em&gt;ofrenda&lt;/em&gt; is an altar built from the things a person loved: their favorite food, their songs, the objects they kept close, the stories people tell about them. I wanted to build a digital version, one that keeps those memories alive and can be talked to.&lt;/p&gt;

&lt;p&gt;You add a person, then place "offerings" on their altar: a food, a song, a story, or an object. Then you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ask the Keeper.&lt;/strong&gt; A chat that answers only from the memories you placed. Ask "What did she love to cook?" and it tells you what you wrote, in a gentle voice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a remembrance.&lt;/strong&gt; A short tribute written from the memories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write a calaverita.&lt;/strong&gt; A playful rhyming verse in the Mexican tradition of teasing Death while celebrating the person.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I interpreted "Ghost in the Machine" in a gentler way than haunting. The ghost isn't a fake version of your loved one. It's their memory, kept safe by a machine. That's why the Keeper is deliberately &lt;strong&gt;not&lt;/strong&gt; allowed to speak as the person. It's a storyteller who looks after the memories, speaks about them in the third person, and says "that story isn't on the ofrenda yet" instead of making something up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2dt3w1by85aj1qbkgsx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2dt3w1by85aj1qbkgsx4.png" alt=" " width="799" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkfs6t6xsylylapdks3nc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkfs6t6xsylylapdks3nc.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmt9h9hjp6re08fkmbe05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmt9h9hjp6re08fkmbe05.png" alt=" " width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;




&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ronitsolanki-01" rel="noopener noreferrer"&gt;
        ronitsolanki-01
      &lt;/a&gt; / &lt;a href="https://github.com/ronitsolanki-01/Ofrenda" rel="noopener noreferrer"&gt;
        Ofrenda
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Ofrenda: a private, local altar for people you remember. Place foods, songs &amp;amp; stories, then ask a Keeper that answers only from your memories, or get a calaverita. Spring Boot, Next.js, Spring AI, llama3.1:8b &amp;amp; nomic-embed-text via Ollama. Nothing leaves your laptop.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Ofrenda&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;A private, local altar for people you remember. Place foods, songs, stories and objects on it.
Memories are embedded with &lt;code&gt;nomic-embed-text&lt;/code&gt; into a Spring AI vector store. The "Keeper" (&lt;code&gt;llama3.1:8b&lt;/code&gt;)
answers using retrieval (RAG) from those memories only, and can write a remembrance or a playful &lt;em&gt;calaverita&lt;/em&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ollama pull llama3.1:8b &amp;amp;&amp;amp; ollama pull nomic-embed-text&lt;/code&gt; (Ollama running on :11434)&lt;/li&gt;
&lt;li&gt;Backend (Java 21): &lt;code&gt;cd backend &amp;amp;&amp;amp; mvn spring-boot:run&lt;/code&gt;   → &lt;a href="http://localhost:8080" rel="nofollow noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend: &lt;code&gt;cd frontend &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm run dev&lt;/code&gt;      → &lt;a href="http://localhost:3000" rel="nofollow noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Data is saved to &lt;code&gt;backend/data/ofrenda.json&lt;/code&gt; and re-embedded on every startup.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ronitsolanki-01/Ofrenda" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Everything runs on my own machine with open-weight models.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chat model&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;llama3.1:8b&lt;/code&gt; via Ollama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embeddings&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nomic-embed-text&lt;/code&gt; via Ollama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI framework&lt;/td&gt;
&lt;td&gt;Spring AI 1.0 (&lt;code&gt;ChatClient&lt;/code&gt;, &lt;code&gt;VectorStore&lt;/code&gt;, &lt;code&gt;EmbeddingModel&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Spring Boot 3.4, Java 21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js 15 (App Router, TypeScript)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The core idea is RAG (retrieval-augmented generation), kept small and honest:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When you place an offering, the backend embeds the text with &lt;code&gt;nomic-embed-text&lt;/code&gt; and stores it in Spring AI's &lt;code&gt;SimpleVectorStore&lt;/code&gt;, tagged with the person's id.&lt;/li&gt;
&lt;li&gt;When you ask the Keeper a question, the backend runs a similarity search filtered to that person's memories and pulls the top 5.&lt;/li&gt;
&lt;li&gt;Those memories go into the system prompt for &lt;code&gt;llama3.1:8b&lt;/code&gt;, with strict rules: use only these memories, invent nothing, never pretend to be the person.&lt;/li&gt;
&lt;li&gt;Memories are saved to a small JSON file and re-embedded on startup, so the altar survives restarts without needing a database.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The calaverita and the remembrance use the same approach: all of a person's memories go into the prompt, and the model is told which style to write.&lt;/p&gt;

&lt;p&gt;The design comes from the subject itself: a papel picado banner across the top, and a marigold, pink and teal palette on deep plum, like candlelight against a night sky.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Grief is private. The things people write about someone they've lost, such as a grandmother's recipes, a father's songs and the story from the hospital, are some of the most personal data a person owns.&lt;/p&gt;

&lt;p&gt;With a closed API, every one of those memories would have to leave my machine and pass through someone else's servers. With open-weight models and local inference, &lt;strong&gt;nothing leaves the laptop&lt;/strong&gt;. There's no account, no API key, no usage bill and no terms of service sitting between you and your own memories.&lt;/p&gt;

&lt;p&gt;Open tooling also let me build exactly what I wanted. Spring AI let me plug Ollama into a normal Spring Boot backend, and I could swap models, tune the prompts and filter retrieval per person. Because the project is open too, someone else can fork it, translate it, or point it at a different model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;The goal isn't to bring anyone back. It's to make sure that the small, specific things that made a person who they were don't get lost.&lt;/p&gt;




&lt;p&gt;*Built for Hacktoberfest 2026 with open-weight models.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>springboot</category>
      <category>ai</category>
    </item>
    <item>
      <title>SlothDigest: Let a Local 4B AI Read Your 400 Unread WhatsApp Messages While You Sleep</title>
      <dc:creator>Ronit Solanki</dc:creator>
      <pubDate>Sun, 25 Oct 2026 19:22:00 +0000</pubDate>
      <link>https://dev.to/ronit_solanki/slothdigest-let-a-local-4b-ai-read-your-400-unread-whatsapp-messages-while-you-sleep-3k8k</link>
      <guid>https://dev.to/ronit_solanki/slothdigest-let-a-local-4b-ai-read-your-400-unread-whatsapp-messages-while-you-sleep-3k8k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SlothDigest&lt;/strong&gt; is an asynchronous, local-first group chat summarizer built for people who refuse to wake up and scroll through 400 unread WhatsApp messages just to find out whether a meeting moved by 15 minutes.&lt;/p&gt;

&lt;p&gt;Instead of reading noisy group threads in real time, you upload your exported &lt;code&gt;.txt&lt;/code&gt; chat logs into &lt;strong&gt;SlothDigest&lt;/strong&gt; before going to bed (or trigger a manual digest anytime). At &lt;strong&gt;3:00 AM&lt;/strong&gt;, a scheduled Spring Boot batch job wakes up, parses the raw chat transcripts, and feeds them through a local open-weight LLM (&lt;code&gt;qwen3.5:4b&lt;/code&gt; running on &lt;strong&gt;Ollama&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;When you open the React (Vite) dashboard with your morning coffee, every chaotic group chat is already distilled into three clean sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A 2-Line Summary:&lt;/strong&gt; Two short, factual sentences explaining what actually happened in the thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Items:&lt;/strong&gt; Concrete tasks, decisions, and deadlines extracted from the noise (including who is responsible and when it is due).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct Mentions:&lt;/strong&gt; A personalized list of messages that addressed or mentioned you by name (e.g., &lt;em&gt;"Sam asked if you can bring the projector"&lt;/em&gt;), so you never miss a ping buried under 50 memes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Busy students, developers in hackathon coordination threads, and anyone trapped in high-volume WhatsApp project groups get to be unapologetically lazier every morning without missing a single task or ping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7aw9cpdoaxoq4hjg5gr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7aw9cpdoaxoq4hjg5gr0.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk7rhnqeoijagye948yuk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk7rhnqeoijagye948yuk.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folp0pxwrf4y01e1hl20v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folp0pxwrf4y01e1hl20v.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ronitsolanki-01" rel="noopener noreferrer"&gt;
        ronitsolanki-01
      &lt;/a&gt; / &lt;a href="https://github.com/ronitsolanki-01/slothdigest" rel="noopener noreferrer"&gt;
        slothdigest
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      You upload or forward your group chat exports (e.g. WhatsApp .txt files) and a scheduled job summarizes them overnight. In the morning you open the app and find a 2-line summary per chat, plus action items and anything that mentions you. You never have to scroll through 400 messages.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SlothDigest&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Upload your group-chat exports, go to sleep, and read a two-line summary per chat in the morning
(plus action items and anything that mentions you). It runs on an open-weight model through Ollama
so your chats never leave your machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; Spring Boot 4.0, Spring AI 2.0 (Ollama), Spring Security 7 (JWT), JPA + H2, &lt;code&gt;@Scheduled&lt;/code&gt; job
&lt;strong&gt;Frontend:&lt;/strong&gt; React + Vite + Tailwind&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Java 17+ (21 recommended), Maven 3.9+&lt;/li&gt;
&lt;li&gt;Node 18+&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; running locally, with the model pulled: &lt;code&gt;ollama pull qwen3.5:4b&lt;/code&gt;
(change the model in &lt;code&gt;application.properties&lt;/code&gt;; thinking is turned off in &lt;code&gt;DigestAi.java&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 1. backend (http://localhost:8080)&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; backend
mvn spring-boot:run

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 2. frontend (http://localhost:5173), in another terminal&lt;/span&gt;
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; frontend
npm install
npm run dev&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Try it&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://localhost:5173" rel="nofollow noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; and create an account. Use the name your friends call you as
&lt;strong&gt;display name&lt;/strong&gt;, because that is how mentions of you are found.&lt;/li&gt;
&lt;li&gt;Upload &lt;code&gt;sample-chat.txt&lt;/code&gt; (WhatsApp…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ronitsolanki-01/slothdigest" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SlothDigest&lt;/strong&gt; is built as a full-stack application with a &lt;strong&gt;React (Vite)&lt;/strong&gt; frontend and a &lt;strong&gt;Java Spring Boot&lt;/strong&gt; backend, orchestrated around local open-source AI inference via &lt;strong&gt;Spring AI 2.x&lt;/strong&gt; and &lt;strong&gt;Ollama&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; &lt;strong&gt;React + Vite&lt;/strong&gt; organized into three focused screens: a &lt;strong&gt;Login / Register page&lt;/strong&gt;, a &lt;strong&gt;Chat Export Upload page&lt;/strong&gt;, and a &lt;strong&gt;Morning Digest Feed&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; &lt;strong&gt;Java &amp;amp; Spring Boot&lt;/strong&gt; with &lt;strong&gt;Spring Security + stateless JWT authentication&lt;/strong&gt; (&lt;code&gt;app.jwt.secret&lt;/code&gt;) supporting multi-user accounts, where each user's display name is dynamically injected into the prompt to detect direct mentions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; File-based &lt;strong&gt;H2 database&lt;/strong&gt; (&lt;code&gt;jdbc:h2:file:./data/slothdigest&lt;/code&gt;) with &lt;strong&gt;Spring Data JPA / Hibernate&lt;/strong&gt; for zero-setup local persistence (easily swappable to PostgreSQL in production).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-Source AI &amp;amp; Local Inference:&lt;/strong&gt; &lt;strong&gt;Ollama&lt;/strong&gt; serving the open-weight &lt;strong&gt;&lt;code&gt;qwen3.5:4b&lt;/code&gt;&lt;/strong&gt; model locally (plus &lt;code&gt;nomic-embed-text&lt;/code&gt; configured for future semantic search/RAG features), integrated via &lt;strong&gt;Spring AI 2.x&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture &amp;amp; Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Chat-Export Parser:&lt;/strong&gt; Raw exported &lt;code&gt;.txt&lt;/code&gt; chat logs are uploaded (up to &lt;code&gt;10MB&lt;/code&gt; multipart uploads), cleaned, and normalized into a compact &lt;code&gt;Sender: text&lt;/code&gt; line-by-line format. To protect local memory and keep inference snappy on laptop hardware, the parser keeps the most recent &lt;code&gt;12,000&lt;/code&gt; characters (&lt;code&gt;app.digest.max-chars=12000&lt;/code&gt;) within an &lt;code&gt;8,192&lt;/code&gt;-token context window (&lt;code&gt;num-ctx=8192&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow-and-Steady Overnight Batch Job (&lt;code&gt;@Scheduled&lt;/code&gt;):&lt;/strong&gt; Rather than making the user stare at a loading spinner, a Spring &lt;code&gt;@Scheduled&lt;/code&gt; cron job (&lt;code&gt;0 0 3 * * *&lt;/code&gt;) runs every night at &lt;strong&gt;3:00 AM&lt;/strong&gt; to digest all pending chat exports in the background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema-Enforced Structured Output (&lt;code&gt;BeanOutputConverter&lt;/code&gt;):&lt;/strong&gt; Small local models can sometimes wrap JSON in markdown fences or drift off-schema. In &lt;code&gt;DigestAi.java&lt;/code&gt;, I paired Spring AI's &lt;code&gt;BeanOutputConverter&amp;lt;DigestResult&amp;gt;&lt;/code&gt; with &lt;code&gt;OllamaChatOptions&lt;/code&gt; to enforce the exact JSON schema at the Ollama inference layer while disabling chain-of-thought reasoning traces (&lt;code&gt;disableThinking()&lt;/code&gt;) and setting a low temperature (&lt;code&gt;0.2&lt;/code&gt;) for fast, deterministic extraction:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;java&lt;br&gt;
public DigestResult summarize(String chatName, String readerName, String transcript) {&lt;br&gt;
    OllamaChatOptions options = OllamaChatOptions.builder()&lt;br&gt;
            .model(this.model)                          // qwen3.5:4b&lt;br&gt;
            .disableThinking()                          // no reasoning trace: faster, cleaner JSON&lt;br&gt;
            .outputSchema(converter.getJsonSchema())    // Ollama enforces this JSON schema&lt;br&gt;
            .build();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prompt prompt = new Prompt(List.of(
        new SystemMessage(SYSTEM),
        new UserMessage(USER.formatted(chatName, readerName, transcript))),
        options);

String json = chatModel.call(prompt).getResult().getOutput().getText();
return converter.convert(json);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Group chat exports contain deeply personal, unfiltered conversations—phone numbers, internal project updates, deadlines, and candid banter among friends or teammates. Uploading private group chat logs to a closed, third-party cloud API is a non-starter for privacy.&lt;/p&gt;

&lt;p&gt;Open innovation made SlothDigest possible in three ways that a closed API couldn't match:&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>VaultExam AI: Mock Tests from Your Notes, Without Uploading Them Anywhere</title>
      <dc:creator>Ronit Solanki</dc:creator>
      <pubDate>Sat, 17 Oct 2026 23:40:09 +0000</pubDate>
      <link>https://dev.to/ronit_solanki/vaultexam-ai-mock-tests-from-your-notes-without-uploading-them-anywhere-1kph</link>
      <guid>https://dev.to/ronit_solanki/vaultexam-ai-mock-tests-from-your-notes-without-uploading-them-anywhere-1kph</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;VaultExam AI is a 100% local, privacy-first tool that turns a chapter (In any format) into a ready-to-print question paper + answer key and lets you ask questions of the same document with page-cited answers.&lt;/p&gt;

&lt;p&gt;Who would pay for it: independent coaching institutes, test-prep tutors, university professors and corporate trainers. Their curated notes and question banks are their intellectual property, and they don't want to upload them to a cloud API. They also spend hours every week typing up mock tests, DPPs and Set A/B variations by hand.&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload Notes in any format. It is chunked and embedded locally, and the file is deleted from disk straight after ingestion.&lt;/li&gt;
&lt;li&gt;Ask the document: answers come only from your notes, with Page citations.&lt;/li&gt;
&lt;li&gt;Generate an exam: choose the institute name, exam type (Coaching Mock Test, University Mid-Sem, Corporate SOP Quiz), difficulty (Recall, Application, Analytical/Edge Cases) and the number of MCQs, short answers and long answers.&lt;/li&gt;
&lt;li&gt;Set A/B/C: each set draws on different parts of the document and avoids repeating earlier questions.&lt;/li&gt;
&lt;li&gt;Answer key included: MCQ answers with explanations, model answers for short and long questions, marking-scheme key points, and the source page for every question so a teacher can verify it.&lt;/li&gt;
&lt;li&gt;Print or save as PDF straight from the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fifewhp5fnwtcan713z3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fifewhp5fnwtcan713z3l.png" alt=" " width="799" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe3ifuhjmu6840752j68t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe3ifuhjmu6840752j68t.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokouh0oesziqzsuq3qas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokouh0oesziqzsuq3qas.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ronitsolanki-01/VaultExam.git" rel="noopener noreferrer"&gt;https://github.com/ronitsolanki-01/VaultExam.git&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Everything runs on the user's own machine. No cloud calls, no per-token fees.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Java 21, Spring Boot 4.1.1 and Spring AI 2.0.1&lt;/li&gt;
&lt;li&gt;LLM: an open-weight model (qwen3.5:4b) served by local Ollama&lt;/li&gt;
&lt;li&gt;Embeddings: &lt;code&gt;nomic-embed-text&lt;/code&gt; via Ollama&lt;/li&gt;
&lt;li&gt;Vector store: PostgreSQL with PGVector (pgvector/pgvector:pg16 via Docker Compose), with metadata filtering by &lt;code&gt;document_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ingestion: Spring AI's &lt;code&gt;TikaDocumentReader and PagePdfDocumentReader&lt;/code&gt; keeps page number on every chunk, then &lt;code&gt;TokenTextSplitter&lt;/code&gt; chunks it&lt;/li&gt;
&lt;li&gt;Frontend: one Next.js page (TypeScript, Tailwind), with window.print() for output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How the exam generator works: it retrieves a sample of chunks from the document, asks the model for MCQs, short answers and long answers in separate structured-output calls, then validates each result (question count, exactly four options, valid answer index) and retries if the local model returns bad JSON. Each set uses a different seeded sample of the document, plus a "don't repeat these questions" list.&lt;/p&gt;

&lt;p&gt;Things that bit me on a small local model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning models like &lt;code&gt;qwen3.5&lt;/code&gt; can spend their whole token budget "thinking" and return an empty answer, which breaks JSON parsing. I fixed it by disabling thinking in the Ollama options.&lt;/li&gt;
&lt;li&gt;Ollama's default context window silently truncates long RAG prompts, so I set a larger &lt;code&gt;num-ctx&lt;/code&gt; and tuned how many chunks each call retrieves.&lt;/li&gt;
&lt;li&gt;Small models sometimes return a bare JSON array instead of an object, so the parsing and validation code handles that and retries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;A closed API would have made this product impossible to sell to its target customers. A coaching institute's notes are its business, and "send your question bank to a third party" is a dealbreaker.&lt;/p&gt;

&lt;p&gt;Open-weight models let the whole pipeline run inside the customer's own machine. That also changes the economics: generating a hundred papers costs electricity, not tokens, so a tutor can regenerate Set B at 11pm without watching a bill. And because the stack is open, institutes can swap the model for a bigger one as their hardware allows.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>java</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
