<?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: Jeman</title>
    <description>The latest articles on DEV Community by Jeman (@jemankalita).</description>
    <link>https://dev.to/jemankalita</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%2F4156263%2F71e81b7d-6186-432d-93a7-2f402f310d0f.jpg</url>
      <title>DEV Community: Jeman</title>
      <link>https://dev.to/jemankalita</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jemankalita"/>
    <language>en</language>
    <item>
      <title>আইতাৰ কথা (Aitar Kotha): I fine-tuned an open model to name plants the way my grandmother does</title>
      <dc:creator>Jeman</dc:creator>
      <pubDate>Sun, 11 Oct 2026 15:33:47 +0000</pubDate>
      <link>https://dev.to/jemankalita/aaitaar-kthaa-aitar-kotha-i-fine-tuned-an-open-model-to-name-plants-the-way-my-grandmother-does-1l5f</link>
      <guid>https://dev.to/jemankalita/aaitaar-kthaa-aitar-kotha-i-fine-tuned-an-open-model-to-name-plants-the-way-my-grandmother-does-1l5f</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hf26"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Ask ChatGPT what &lt;em&gt;Ziziphus mauritiana&lt;/em&gt; is and you'll get "Indian jujube". Ask my Aita (grandmother) and you'll get &lt;strong&gt;বগৰী, bogori&lt;/strong&gt;, plus a warning not to eat one before Saraswati Puja, and a reminder that the thorns curve backwards so you pick from the outside of the tree.&lt;/p&gt;

&lt;p&gt;That second answer is what we lose when our field guides are written for somebody else. So I built &lt;strong&gt;Aitar Kotha (আইতাৰ কথা, "Aita's words")&lt;/strong&gt;: a field guide for the plants of Assam that answers the way an Assamese grandmother would. Then, every time, it tells you to put the phone in your pocket and go and find the plant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📷 &lt;strong&gt;Show Aita a leaf.&lt;/strong&gt; An open vision model picks the plant from the photo.&lt;/li&gt;
&lt;li&gt;🗣️ &lt;strong&gt;Or ask by name&lt;/strong&gt;: &lt;em&gt;bogori&lt;/em&gt;, &lt;em&gt;sewali&lt;/em&gt;, &lt;em&gt;ou tenga&lt;/em&gt;, or type it in Assamese script.&lt;/li&gt;
&lt;li&gt;🌾 &lt;strong&gt;"In season now"&lt;/strong&gt; shows what to look for this Assamese month (it's কাতি, Kati, as I write this: sewali flowers, amlokhi and robab tenga).&lt;/li&gt;
&lt;li&gt;অ &lt;strong&gt;Everything works in English or অসমীয়া&lt;/strong&gt;, with one tap.&lt;/li&gt;
&lt;li&gt;⭐ &lt;strong&gt;Achievements you can only earn outside.&lt;/strong&gt; Each plant you &lt;em&gt;scan with the camera&lt;/em&gt; earns its badge. Collections like টেঙাৰ দল (the sour ones) and বিহুৰ গছ (Bihu plants) add up to &lt;strong&gt;আইতাৰ তৰা, Aita's Star&lt;/strong&gt;, for all 43.&lt;/li&gt;
&lt;li&gt;🔊 &lt;strong&gt;শুনা · Listen.&lt;/strong&gt; With an ElevenLabs key, Aita reads the card aloud in Assamese, so you never have to look at the screen at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjro4gbxr1p18z66f5iic.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjro4gbxr1p18z66f5iic.gif" alt="A photo of tulsi goes in, Gemma names it on my laptop, and the tulsi badge pops up" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Two narrated walkthroughs, recorded with the real fine-tuned Aita and real Gemma running on my laptop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;▶️ &lt;strong&gt;&lt;a href="https://github.com/jemankalita/aitar-kotha/blob/main/docs/aitar-kotha-demo-en.mp4" rel="noopener noreferrer"&gt;Demo in English (1:05)&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;▶️ &lt;strong&gt;&lt;a href="https://github.com/jemankalita/aitar-kotha/blob/main/docs/aitar-kotha-demo-as.mp4" rel="noopener noreferrer"&gt;অসমীয়াত, in Assamese (0:58)&lt;/a&gt;&lt;/strong&gt;, with the whole app switched to Assamese&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are narrated by Meta's open &lt;a href="https://huggingface.co/facebook/mms-tts-asm" rel="noopener noreferrer"&gt;MMS-TTS&lt;/a&gt; model running on my laptop, which has an Assamese voice. Even the narration is open source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the demo:&lt;/strong&gt; &lt;a href="https://jemankalita.github.io/aitar-kotha/" rel="noopener noreferrer"&gt;https://jemankalita.github.io/aitar-kotha/&lt;/a&gt; (works on your phone, in English or অসমীয়া). The live demo answers from the family notes; the open AI (fine-tuned Aita and photo scanning) runs when you run it yourself, which is the whole point: your family's knowledge, on your own device.&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/jemankalita" rel="noopener noreferrer"&gt;
        jemankalita
      &lt;/a&gt; / &lt;a href="https://github.com/jemankalita/aitar-kotha" rel="noopener noreferrer"&gt;
        aitar-kotha
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      আইতাৰ কথা: an Assamese plant field guide that talks like your grandmother. Fine-tuned open model (Tinker + Qwen), offline-first, bilingual, with badges. Hacktoberfest Open-Source AI Challenge Week 1.
    &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;আইতাৰ কথা · Aitar Kotha&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Plants of Assam, the way Aita (grandmother) told it.&lt;/strong&gt; Point your phone at a plant, or just say its name, and a small open-weight model fine-tuned on Assamese family plant knowledge answers like an Assamese grandmother would:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;বগৰী — bogori&lt;/strong&gt; (Indian jujube, &lt;em&gt;Ziziphus mauritiana&lt;/em&gt;)
A thorny small tree with small shiny oval leaves… Eaten raw with salt and chilli, or made into sweet-sour bogori achar dried in the winter sun
Many families tell children not to eat bogori until after Saraswati Puja…
&lt;strong&gt;Now put the phone away and go find one.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hf26" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://jemankalita.github.io/aitar-kotha/" rel="nofollow noopener noreferrer"&gt;https://jemankalita.github.io/aitar-kotha/&lt;/a&gt;. The demo answers from the family notes in your browser (names, seasons, English ⇄ অসমীয়া, achievements). The open AI, meaning the fine-tuned Aita and photo scanning, runs when you run it yourself (below). That's the point: your…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jemankalita/aitar-kotha" 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;h3&gt;
  
  
  1. The knowledge comes from family, not the internet
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;data/plants.json&lt;/code&gt; holds 43 plants as my family knows them: the Assamese name in script and in roman letters, the English and scientific names, the season, how to recognise the plant, how we use it, one story, and any warning. &lt;code&gt;data/plants_as.json&lt;/code&gt; holds the same notes in Assamese.&lt;/p&gt;

&lt;p&gt;Plant knowledge in Assam lives in conversation, not on the web. It's in what an Aita says while pointing at a bush, or in which leaves go into which dish at Bihu. Books gave me the scientific names; the uses, the stories and the warnings are the part only family has. So every entry carries a &lt;code&gt;verified&lt;/code&gt; flag, and the app shows a "not yet checked with elders" label on any card where it's still &lt;code&gt;false&lt;/code&gt;. A note only counts once the family has heard it read back in Assamese.&lt;/p&gt;

&lt;p&gt;Traditional remedies are written down as culture, not as medical advice, and any plant with a dangerous look-alike carries a warning.&lt;/p&gt;

&lt;p&gt;Each card also shows a photo of the plant: 41 freely licensed photos from Wikimedia Commons, each credited to its photographer on the card.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Teaching an open model to answer like Aita (Tinker)
&lt;/h3&gt;

&lt;p&gt;I turned the notes into &lt;strong&gt;383 practice conversations&lt;/strong&gt; and LoRA-fine-tuned &lt;strong&gt;Qwen3.5-4B&lt;/strong&gt; on &lt;a href="https://tinker-docs.thinkingmachines.ai" rel="noopener noreferrer"&gt;Tinker&lt;/a&gt;. The fine-tune trains only on Aita's replies, and the answer pattern is always the same: Assamese name first, then how to know the plant, how families use it, one story, any danger, and finally &lt;em&gt;"now put the phone away."&lt;/em&gt; I also trained it to say "I don't know" about plants that aren't from Assam, and never to tell anyone to eat something they can't name for sure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;training_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_lora_training_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Qwen/Qwen3.5-4B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_renderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3_5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;training_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tokenizer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;conversation_to_datum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;train_on_what&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TrainOnWhat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LAST_ASSISTANT_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batches&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;training_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forward_backward&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cross_entropy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;training_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;optim_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tinker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AdamParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;learning_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2e-4&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I tested both models on &lt;strong&gt;172 questions the model never saw&lt;/strong&gt;, phrased differently from the training ones (e.g. "Koka told me to look for bogori today. What is it?", or বগৰীৰ বিষয়ে কোৱাচোন।):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Base Qwen3.5-4B&lt;/th&gt;
&lt;th&gt;Aita (fine-tuned)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assamese script name&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;77%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roman Assamese name&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scientific name&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;85%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The training run was 96 steps (LoRA rank 32, 4 epochs over 383 chats); loss fell from 31.1 to about 0.5. Neither model got the family notes during this test: this is only what the weights learned.&lt;/p&gt;

&lt;p&gt;My favourite example: asked &lt;em&gt;"Koka told me to look for sewali today. What is it?"&lt;/em&gt;, base Qwen started reasoning aloud and guessed &lt;em&gt;Sesbania grandiflora&lt;/em&gt;, the wrong plant. Aita answered &lt;strong&gt;শেৱালি, sewali (Night-flowering jasmine, &lt;em&gt;Nyctanthes arbor-tristis&lt;/em&gt;). Look under the bush at dawn: small white flowers with bright orange tubes carpet the ground.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Honest caveats: answers were capped at 400 tokens and the base model spends many of them thinking out loud, so its score is a little pessimistic. And Aita isn't perfect from memory alone: asked about bogori with no notes, she got the name, season and uses right but described the bark of a different tree. That's why the app always hands her the family notes too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Photo scanning, honestly
&lt;/h3&gt;

&lt;p&gt;Gemma 3 (4B) runs on my laptop's 4 GB GPU, about 20–25 seconds per photo. On six test photos it got four right: sewali, tulsi, star fruit, ou tenga and water spinach were each identified at least once. Its self-reported confidence was 95–100% even when it was wrong, so I don't trust that number. A badge only appears after a scan, and Aita says so when she isn't sure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The walking app
&lt;/h3&gt;

&lt;p&gt;A small FastAPI server and a phone-first web app. When the fine-tuned model is unreachable, the app answers straight from the family notes, and a service worker keeps those notes on the phone so you can still ask by name on a trail with no signal. Photos are downscaled on the phone and their real file type is checked before anything reaches the vision model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open matters for this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You can't fine-tune a closed model on your grandmother's knowledge and keep the result.&lt;/strong&gt; Here the weights are mine: an adapter of a few megabytes that I can download and run in Ollama on my own laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small languages deserve better than "close enough".&lt;/strong&gt; Assamese plant names, folk uses and Bihu customs are thin on the web, which is exactly where general models guess. With an open model I could teach it the real names, and test whether it learned them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It runs without the cloud.&lt;/strong&gt; The notes, the app and the exported model all work offline, so nothing about where you walk leaves the phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest about the one closed piece:&lt;/strong&gt; the Assamese voice uses ElevenLabs. It's optional; without a key the Listen button just doesn't appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Built for outside
&lt;/h2&gt;

&lt;p&gt;The app is designed so the screen is the shortest part of the walk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The answer ends by sending you away.&lt;/strong&gt; Every reply from Aita closes with &lt;em&gt;"now put the phone away"&lt;/em&gt; and tells you what to look for: the curved thorns, the smell, the colour of the flower tube.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Badges only come from the camera.&lt;/strong&gt; Typing a name teaches you something; earning the badge means you stood in front of the plant and took its photo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works with no signal.&lt;/strong&gt; A service worker keeps all 43 plants' notes on the phone, so asking by name works in a bari or by a pond with no network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can speak.&lt;/strong&gt; With an ElevenLabs key, "Listen" reads the card aloud in Assamese, so the phone can stay in your pocket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tested the scan on real photographs of the plants, not illustrations: tulsi, sewali, star fruit, ou tenga and water spinach were all recognised at least once by Gemma running on my own laptop, and the honest misses are in the section above. The open model is what makes a phone-in-pocket walk possible at all: there's no server to reach, and no record of where you walked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More plants, and the names other communities of Assam use (Bodo, Mising, Karbi…)&lt;/li&gt;
&lt;li&gt;Let elders record their own voice for each story&lt;/li&gt;
&lt;li&gt;A printable pocket card for walks with no phone at all&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I read along the way
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/gagan1985/building-an-open-source-indian-address-parser-from-raw-mcabank-data-to-a-fine-tuned-llm-2n9c"&gt;Building an Open-Source Indian Address Parser: From Raw MCA/Bank Data to a Fine-Tuned LLM&lt;/a&gt; by Gagan: a LoRA pipeline for Indian data, end to end&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/mchittineni/translating-78000-indian-village-names-into-six-scripts-when-your-data-feed-is-only-in-english-1c76"&gt;Translating 50,000+ Indian village names into six scripts&lt;/a&gt; by mchittineni: why English-only data fails rural India&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/aiexplore369zoho/lora-doesnt-approximate-fine-tuning-it-changes-what-you-can-teach-1i2"&gt;LoRA Doesn't Approximate Fine-Tuning. It Changes What You Can Teach&lt;/a&gt;: useful framing for what a small adapter can and can't learn&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Tinker:&lt;/strong&gt; Tinker LoRA-fine-tuned Qwen3.5-4B into Aita (383 conversations, 96 steps), evaluated on 172 unseen questions: the Assamese-script name went from 31% to 77%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 3 (4B) does the photo scanning, entirely on my laptop through Ollama.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of GitHub Copilot:&lt;/strong&gt; I used Copilot in VS Code to write the entire codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Built with Github Copilot as my pair programmer.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hf26challenge</category>
      <category>devchallenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>HandNotes: teaching an open model to read my friend's handwriting, on his own laptop</title>
      <dc:creator>Jeman</dc:creator>
      <pubDate>Sun, 04 Oct 2026 23:55:25 +0000</pubDate>
      <link>https://dev.to/jemankalita/handnotes-teaching-an-open-model-to-read-my-friends-handwriting-on-his-own-laptop-3ce3</link>
      <guid>https://dev.to/jemankalita/handnotes-teaching-an-open-model-to-read-my-friends-handwriting-on-his-own-laptop-3ce3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsl6kk3hqtbcyd9nti2jh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsl6kk3hqtbcyd9nti2jh.gif" alt="HandNotes demo: adding his short forms, reading a page live, comparing with the plain model, and making flashcards" width="600" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;My friend writes down &lt;strong&gt;everything&lt;/strong&gt; in class. Every lecture, every assignment, page after page. The problem shows up the night before an exam: he photographs his notes, uploads them to an AI chatbot, asks for a summary, and gets nothing useful back. It can't read his handwriting.&lt;/p&gt;

&lt;p&gt;When I ran his pages through a vision model myself, I found something worse than "can't read it". The model read &lt;em&gt;most&lt;/em&gt; of it, and the mistakes looked right:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The Perennial Student&lt;/em&gt; (the book he was writing about) became &lt;em&gt;The **Peripheral&lt;/em&gt;* Student*&lt;/li&gt;
&lt;li&gt;"satirical" became "spatialical"&lt;/li&gt;
&lt;li&gt;"his reputation" became "her reputation"&lt;/li&gt;
&lt;li&gt;a date in a letter disappeared, and "5:00 to 7:00 pm" became "8:00 to 8:00"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then there's his shorthand. He writes "acc" for &lt;em&gt;according&lt;/em&gt; and "gitq" for &lt;em&gt;given in the question&lt;/em&gt;, which no model is ever going to guess.&lt;/p&gt;

&lt;p&gt;A tired student skimming a summary at 2 AM would never catch any of that. So I built &lt;strong&gt;HandNotes&lt;/strong&gt;: a handwriting reader that runs entirely on his laptop, lets you correct what it got wrong, and remembers those corrections for the next page.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reads a photo of his notes live.&lt;/strong&gt; Text streams in word by word from an open vision model running locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highlights words it isn't sure about&lt;/strong&gt;, with one-click jumps to each one so checking a page is fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learns from corrections.&lt;/strong&gt; Every fix is compared word by word with what the model wrote. His vocabulary and past misreads go into the prompt for the next page, and a misread you've corrected twice gets fixed automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knows his short forms.&lt;/strong&gt; Teach it "gitq = given in the question" once, either by adding it or just by expanding it while correcting a page, and it expands it on every page after that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shows its work.&lt;/strong&gt; An accuracy chart per page, a list of his usual misreads, and a "compare with plain model" view that shows, word by word, what the memory changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turns notes into revision material:&lt;/strong&gt; a summary with likely exam questions, flip-to-reveal flashcards, and export to PDF, Word or text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What he said:&lt;/strong&gt; when I showed it to him, he really liked it, and he told me he's going to use it on a regular basis. Coming from the person who photographs his notes because typing them up is too much effort, that's the review I was hoping for.&lt;/p&gt;

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

&lt;p&gt;It runs locally (that's the point), so the GIF at the top is a real run recorded on my laptop, sped up 4x: adding his short forms, reading one of his pages live, comparing against the plain model, and making flashcards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plain model vs. with his memory, on the same page.&lt;/strong&gt; Struck through is what the plain model read; green is what it read with his memory:&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%2Fxu8rsabrvcjge28xp9sg.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%2Fxu8rsabrvcjge28xp9sg.png" alt="Plain model vs. with his memory" width="580" height="980"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The revision summary&lt;/strong&gt;, generated locally from the transcript:&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%2Fm2w7u69to7t1itcwzqu8.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%2Fm2w7u69to7t1itcwzqu8.png" alt="Revision summary with exam questions" width="800" height="593"&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/jemankalita" rel="noopener noreferrer"&gt;
        jemankalita
      &lt;/a&gt; / &lt;a href="https://github.com/jemankalita/Hacktoberfest-Build-for-a-Friend" rel="noopener noreferrer"&gt;
        Hacktoberfest-Build-for-a-Friend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A handwriting reader that learns one friend's handwriting from corrections. Gemma 3 via Ollama, runs fully offline on a 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;HandNotes&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A handwriting reader that learns one person's handwriting, running entirely on your own laptop.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/47f039e2bb65bfab8ea791546ebb1507e20768fb754ba7f0c2e2e9d35b342394/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f47656d6d615f332d3432383546343f7374796c653d666f722d7468652d6261646765266c6f676f3d676f6f676c65266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/47f039e2bb65bfab8ea791546ebb1507e20768fb754ba7f0c2e2e9d35b342394/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f47656d6d615f332d3432383546343f7374796c653d666f722d7468652d6261646765266c6f676f3d676f6f676c65266c6f676f436f6c6f723d7768697465" alt="Gemma 3"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/8dbbb5d9f139c803cb4588df6c90f5c185914bbd8897b812c93dbc5975a17eab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f6c6c616d612d3030303030303f7374796c653d666f722d7468652d6261646765266c6f676f3d6f6c6c616d61266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/8dbbb5d9f139c803cb4588df6c90f5c185914bbd8897b812c93dbc5975a17eab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f6c6c616d612d3030303030303f7374796c653d666f722d7468652d6261646765266c6f676f3d6f6c6c616d61266c6f676f436f6c6f723d7768697465" alt="Ollama"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/324b4cfa68deb1b9c0008c02e910370ae1e1b7141ce0fe77972b6ea034e7abb7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d3337373641423f7374796c653d666f722d7468652d6261646765266c6f676f3d707974686f6e266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/324b4cfa68deb1b9c0008c02e910370ae1e1b7141ce0fe77972b6ea034e7abb7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d3337373641423f7374796c653d666f722d7468652d6261646765266c6f676f3d707974686f6e266c6f676f436f6c6f723d7768697465" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f1089fe65f9ac27d38b03b1b728ac926659fcd1c88dc75269faa736fa95131d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d3030393638383f7374796c653d666f722d7468652d6261646765266c6f676f3d66617374617069266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/f1089fe65f9ac27d38b03b1b728ac926659fcd1c88dc75269faa736fa95131d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d3030393638383f7374796c653d666f722d7468652d6261646765266c6f676f3d66617374617069266c6f676f436f6c6f723d7768697465" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b108dc2388739d4cea2bef5cf6909c24a38398e393601fe6be0d7f63327431ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f48544d4c352d4533344632363f7374796c653d666f722d7468652d6261646765266c6f676f3d68746d6c35266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/b108dc2388739d4cea2bef5cf6909c24a38398e393601fe6be0d7f63327431ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f48544d4c352d4533344632363f7374796c653d666f722d7468652d6261646765266c6f676f3d68746d6c35266c6f676f436f6c6f723d7768697465" alt="HTML5"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/afaf2b32bd626ef5722cf58da6b55f219c5678fb76148df50359ce4879e89885/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4353532d3636333339393f7374796c653d666f722d7468652d6261646765266c6f676f3d637373266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/afaf2b32bd626ef5722cf58da6b55f219c5678fb76148df50359ce4879e89885/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4353532d3636333339393f7374796c653d666f722d7468652d6261646765266c6f676f3d637373266c6f676f436f6c6f723d7768697465" alt="CSS"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/88b8bdce872268b3d0d7ec69e16716a0adf8fa0165eb6069bcb49e23bd5550ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4a6176615363726970742d4637444631453f7374796c653d666f722d7468652d6261646765266c6f676f3d6a617661736372697074266c6f676f436f6c6f723d626c61636b"&gt;&lt;img src="https://camo.githubusercontent.com/88b8bdce872268b3d0d7ec69e16716a0adf8fa0165eb6069bcb49e23bd5550ef/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4a6176615363726970742d4637444631453f7374796c653d666f722d7468652d6261646765266c6f676f3d6a617661736372697074266c6f676f436f6c6f723d626c61636b" alt="JavaScript"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/62ad6d3037fa512e9bf7468a4dbecf49d20c398f60f71735aea7d11860221f0c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7079746573742d3041394544433f7374796c653d666f722d7468652d6261646765266c6f676f3d707974657374266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/62ad6d3037fa512e9bf7468a4dbecf49d20c398f60f71735aea7d11860221f0c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7079746573742d3041394544433f7374796c653d666f722d7468652d6261646765266c6f676f3d707974657374266c6f676f436f6c6f723d7768697465" alt="pytest"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/2792a6b590e1b7fbcc5f7c80df8da3149453c596df80f16fa86bd82c487bec8d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666f722d7468652d6261646765"&gt;&lt;img src="https://camo.githubusercontent.com/2792a6b590e1b7fbcc5f7c80df8da3149453c596df80f16fa86bd82c487bec8d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666f722d7468652d6261646765" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My friend writes down everything in class, then photographs his notes the night before an exam and asks an AI chatbot to summarize them. It can't read his handwriting. And when a model &lt;em&gt;does&lt;/em&gt; read most of it, the mistakes look right: in our first test a book title turned into a different word, "his" became "her", and a date quietly disappeared.&lt;/p&gt;
&lt;p&gt;HandNotes reads his notes with an open vision model (Gemma 3 via Ollama) on his own machine, lets you fix what it got wrong, and remembers those fixes so the next page comes out better. Nothing is uploaded anywhere.&lt;/p&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01" rel="nofollow"&gt;DEV Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/jemankalita/Hacktoberfest-Build-for-a-Friend/docs/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjemankalita%2FHacktoberfest-Build-for-a-Friend%2FHEAD%2Fdocs%2Fdemo.gif" alt="HandNotes reading a real page of his notes, shown at 4x speed"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Real run at 4x speed: adding his short forms, reading a page live, comparing with the plain model, and making flashcards.&lt;/em&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jemankalita/Hacktoberfest-Build-for-a-Friend" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Setup is three commands: &lt;code&gt;ollama pull gemma3:4b&lt;/code&gt;, &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;, &lt;code&gt;python server.py&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The model:&lt;/strong&gt; &lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma 3 4B&lt;/a&gt;, an open-weight vision model, served locally by &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;. On my laptop (GTX 1650 Ti, 4 GB) Ollama splits it about half GPU, half CPU, and a page takes 30 to 40 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The app:&lt;/strong&gt; a small FastAPI server bound to &lt;code&gt;127.0.0.1&lt;/code&gt;, with a hand-written HTML/CSS/JS front end. Fonts and icons are bundled, so even the UI makes no network requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The prompt matters more than I expected.&lt;/strong&gt; My first prompt let the model "tidy up" his notes: it dropped a whole line with a date in it. Telling it to copy literally, skip nothing, and mark unclear words with &lt;code&gt;[?]&lt;/code&gt; brought the date back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The learning is a memory, not retraining.&lt;/strong&gt; Fine-tuning a vision model in a weekend on a 4 GB GPU wasn't realistic, so HandNotes keeps a small per-writer memory file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The model transcribes the page.&lt;/li&gt;
&lt;li&gt;You fix the transcript and save.&lt;/li&gt;
&lt;li&gt;A word-level diff (&lt;code&gt;difflib&lt;/code&gt;) between the model's output and your fix records each misread (&lt;code&gt;"Peripheral" → "Perennial"&lt;/code&gt;), the words he uses, and the page's accuracy.&lt;/li&gt;
&lt;li&gt;On the next page, those words and misreads are added to the prompt, and misreads confirmed at least twice are replaced automatically. Short words like &lt;em&gt;his/her&lt;/em&gt; are never auto-replaced, because they depend on context.&lt;/li&gt;
&lt;li&gt;Short forms are detected separately. If one short word gets replaced by a longer phrase that starts with the same letter and contains its letters in order (&lt;code&gt;gitq&lt;/code&gt; → &lt;strong&gt;g&lt;/strong&gt;iven &lt;strong&gt;i&lt;/strong&gt;n &lt;strong&gt;t&lt;/strong&gt;he &lt;strong&gt;q&lt;/strong&gt;uestion), it's stored as his shorthand. The model is told to copy those exactly as written, and HandNotes expands them after every read.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How well does it work?&lt;/strong&gt; I ran four of his pages in order, letting the memory build up, and scored each against a transcript checked word by word against the photo. For pages 2 to 4 I also read the page with the plain model for comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Page&lt;/th&gt;
&lt;th&gt;With memory&lt;/th&gt;
&lt;th&gt;Plain model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Literature assessment&lt;/td&gt;
&lt;td&gt;94.1%&lt;/td&gt;
&lt;td&gt;(no memory yet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Research overview&lt;/td&gt;
&lt;td&gt;95.5%&lt;/td&gt;
&lt;td&gt;95.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Formal letter&lt;/td&gt;
&lt;td&gt;96.0%&lt;/td&gt;
&lt;td&gt;95.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Literature assessment&lt;/td&gt;
&lt;td&gt;90.1%&lt;/td&gt;
&lt;td&gt;91.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That table isn't the neat upward line I hoped for, and it taught me more than one would have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The memory does fix names and terms.&lt;/strong&gt; Re-reading the first page with memory, "Peripheral" became "Perennial" and "spatialical" became "satirical".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can also learn the wrong lesson.&lt;/strong&gt; My friend spells "behavior" on one page and "behaviour" on another. The memory learned one spelling and "fixed" the other into it, which is why page 4 came out &lt;em&gt;worse&lt;/em&gt; with memory. On another re-read, it turned a correct "Coles" into "Cole".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pronouns are the stubborn error.&lt;/strong&gt; Even when told to copy literally, the model kept turning "his" into "her".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors travel.&lt;/strong&gt; On one run the model invented a word at the end of a page ("distressed"), and it flowed straight into the generated summary. That's why the review step comes before the study tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also found a bug in my own scoring along the way: curly and straight apostrophes (&lt;code&gt;student’s&lt;/code&gt; vs &lt;code&gt;student's&lt;/code&gt;) were counted as misreads. I fixed it with a test and re-ran everything, so the numbers above are from the corrected version.&lt;/p&gt;

&lt;p&gt;The next step is clear from that list: let the user mark a change as "his slip, don't learn this" versus "the model misread this", and flag words he genuinely uses instead of auto-replacing them. After that, I want to cut each corrected word out of the page and use that library to fine-tune a small open handwriting model on his writing specifically.&lt;/p&gt;

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

&lt;p&gt;For this project, open isn't a nice-to-have. It's the reason the project can exist at all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It can be taught one person.&lt;/strong&gt; A hosted chatbot can't be taught my friend's handwriting or his shorthand. An open model I run myself, with a memory I control, can. And because every correction is stored locally, his own handwriting dataset builds up as he uses it. With an open model I can actually fine-tune on that later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;His notes stay his.&lt;/strong&gt; These are photos of his assignments and personal letters. Nothing is uploaded anywhere: the server only listens on &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works where he studies.&lt;/strong&gt; No internet needed once the model is downloaded, which matters in a hostel room the night before an exam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing to run.&lt;/strong&gt; No subscription and no API bill. For a student who's already "too lazy" to type up his notes, anything that costs money or effort won't get used.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could see and change everything.&lt;/strong&gt; When the model dropped a line, I could rewrite the prompt. When the memory learned the wrong lesson, I could see exactly why in a JSON file. I could swap models with one environment variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built this pairing with Claude Code over one long night. It helped with the code, the tests (37 of them, covering the memory, short forms, the API with the model mocked, and the exporters), the demo recording, and the measurements above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 3 4B does all the reading, summarizing and flashcard generation, running locally through Ollama.&lt;/li&gt;
&lt;/ul&gt;

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