<?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: Aakif Kohari</title>
    <description>The latest articles on DEV Community by Aakif Kohari (@aakif-kohari).</description>
    <link>https://dev.to/aakif-kohari</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%2F4160154%2Fab957dd1-c77b-4ff1-b682-513ac946f84d.png</url>
      <title>DEV Community: Aakif Kohari</title>
      <link>https://dev.to/aakif-kohari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aakif-kohari"/>
    <language>en</language>
    <item>
      <title>SlothSort: a Downloads tidier that runs Gemma on my laptop so I don't have to</title>
      <dc:creator>Aakif Kohari</dc:creator>
      <pubDate>Wed, 21 Oct 2026 11:51:49 +0000</pubDate>
      <link>https://dev.to/aakif-kohari/slothsort-a-downloads-tidier-that-runs-gemma-on-my-laptop-so-i-dont-have-to-2f0b</link>
      <guid>https://dev.to/aakif-kohari/slothsort-a-downloads-tidier-that-runs-gemma-on-my-laptop-so-i-dont-have-to-2f0b</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;My Downloads folder had 124 loose files: lecture PDFs, receipts, installers and screenshots, all mixed together. I kept saying I'd sort them "later".&lt;/p&gt;

&lt;p&gt;SlothSort does it for me. Obvious files (&lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.zip&lt;/code&gt;, &lt;code&gt;.mp3&lt;/code&gt;) are sorted by instant rules. The ambiguous ones, like a PDF that could be lecture notes or a receipt, go to Gemma running on my own machine. It files them under Study, Work, Personal or Receipts.&lt;/p&gt;

&lt;p&gt;It is built to be trusted by someone who is too lazy to double-check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is a dry run by default.&lt;/li&gt;
&lt;li&gt;It never deletes or overwrites.&lt;/li&gt;
&lt;li&gt;Every run writes an undo log.&lt;/li&gt;
&lt;li&gt;The model can only choose from a fixed list of folders.&lt;/li&gt;
&lt;/ul&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/Aakif-Kohari" rel="noopener noreferrer"&gt;
        Aakif-Kohari
      &lt;/a&gt; / &lt;a href="https://github.com/Aakif-Kohari/slothsort" rel="noopener noreferrer"&gt;
        slothsort
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SlothSort: a lazy, local-first Downloads tidier powered by an open-weight model (Gemma via Ollama). Dry-run by default, undo built in, zero dependencies.
    &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;SlothSort 🦥&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;The Downloads-folder tidier for people who would rather not tidy their Downloads folder.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SlothSort sorts the loose files in a folder (default &lt;code&gt;~/Downloads&lt;/code&gt;) into sensible subfolders. Obvious files (&lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.zip&lt;/code&gt;, &lt;code&gt;.mp3&lt;/code&gt;...) are handled by instant rules. The ambiguous ones, like a PDF that could be lecture notes or a receipt, are decided by an &lt;strong&gt;open-weight model running on your own machine&lt;/strong&gt; (Gemma through &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt;). Nothing leaves your laptop, it works offline, and it costs nothing per run.&lt;/p&gt;
&lt;p&gt;Built for the DEV x MLH &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge: Week 3 ("Slow and Steady")&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it is safe to be lazy&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dry run by default.&lt;/strong&gt; &lt;code&gt;slothsort plan&lt;/code&gt; shows every move and touches nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never deletes, never overwrites.&lt;/strong&gt; Files are only moved. Name clashes become &lt;code&gt;name (2).ext&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-command undo.&lt;/strong&gt; Every &lt;code&gt;apply&lt;/code&gt; writes a log to &lt;code&gt;.slothsort/&lt;/code&gt;; &lt;code&gt;slothsort undo&lt;/code&gt; puts everything back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Aakif-Kohari/slothsort" 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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; Gemma 4 (&lt;code&gt;gemma4:e2b&lt;/code&gt;) served by Ollama on localhost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured output:&lt;/strong&gt; I pass a JSON schema with an &lt;code&gt;enum&lt;/code&gt; of allowed folders. I also re-validate the answer in code, so a wrong or made-up folder gets rejected and the file lands in "Other".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules first, model second:&lt;/strong&gt; extension rules handle the obvious files instantly, which keeps it fast and cheap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero dependencies:&lt;/strong&gt; a ~90-line Ollama client using only Python's standard library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests:&lt;/strong&gt; 7 pytest tests using fake classifiers and temp folders. They never need Ollama.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;My Downloads folder contains my resume, ID scans and bank receipts. I did not want to send those filenames to someone else's server just to sort them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy:&lt;/strong&gt; the model runs on my laptop, so file names never leave it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline:&lt;/strong&gt; it works with no internet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No cost:&lt;/strong&gt; there is no API key, quota or per-run cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable:&lt;/strong&gt; changing the model is one flag, &lt;code&gt;--model gemma4:e4b&lt;/code&gt;. Because the weights are open, I could also fine-tune it on my own folder structure.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>KhataPing: a local Gemma model that writes polite khata reminders for kirana shops</title>
      <dc:creator>Aakif Kohari</dc:creator>
      <pubDate>Tue, 13 Oct 2026 10:18:19 +0000</pubDate>
      <link>https://dev.to/aakif-kohari/khataping-a-local-gemma-model-that-writes-polite-khata-reminders-for-kirana-shops-p9i</link>
      <guid>https://dev.to/aakif-kohari/khataping-a-local-gemma-model-that-writes-polite-khata-reminders-for-kirana-shops-p9i</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;Every kirana store, stationery shop and tuition teacher in India runs on a &lt;em&gt;khata&lt;/em&gt;, a handwritten ledger of who owes what. The hard part isn't the bookkeeping. It's asking a neighbour you've served for years to pay up without sounding rude, so the reminder gets postponed and the shop loses money.&lt;/p&gt;

&lt;p&gt;KhataPing reads a simple ledger CSV, works out who owes what and how long it has been pending, and writes a respectful WhatsApp reminder in Hindi, Marathi, Hinglish or English. The tone follows the balance: friendly under two weeks, polite up to a month, firm after that. Never threatening. The shopkeeper edits the message and taps "Open in WhatsApp". They always press send themselves.&lt;/p&gt;

&lt;p&gt;I've been building tools for kirana owners (my earlier project, BikriTracker, predicts their sales), and the same pain keeps coming up: money that is owed but never chased.&lt;/p&gt;

&lt;p&gt;Example output for a customer who has owed Rs 3,000 for 125 days (Hinglish, firm tone, offline template):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Namaste Imran Shaikh ji, Patil Kirana Store se yaad dilana tha ki aapke khate mein ₹3,000 baaki hai. Ye 125 din se pending hai. Please is hafte tak payment kar dein, ya bata dein kab tak ho payega. Thank you!&lt;/p&gt;
&lt;/blockquote&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/Aakif-Kohari" rel="noopener noreferrer"&gt;
        Aakif-Kohari
      &lt;/a&gt; / &lt;a href="https://github.com/Aakif-Kohari/khataping" rel="noopener noreferrer"&gt;
        khataping
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Polite khata (credit ledger) reminders in Hindi, Marathi, Hinglish &amp;amp; English - written by an open-weight Gemma model running locally. Hacktoberfest 2026 Week 2: Side Hustle.
    &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;KhataPing&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Polite khata reminders for small shops, written by an open-weight model that runs on the shopkeeper's own laptop.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge: Week 2 - Side Hustle&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every kirana, tailor, stationery shop and tuition teacher in India runs a &lt;em&gt;khata&lt;/em&gt; - a hand-kept ledger of who owes what. Chasing the money is awkward: nobody wants to sound rude to a neighbour they've served for ten years, and the person who forgets to ask loses real money.&lt;/p&gt;
&lt;p&gt;KhataPing reads a simple ledger CSV, works out who owes what and for how long, and writes a respectful WhatsApp reminder in the customer's language - Hindi, Marathi, Hinglish or English - with the tone matched to how overdue the balance is.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it can be a small paid tool&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A real recurring pain:&lt;/strong&gt; late khata payments are a cash-flow problem for the shop, every month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Aakif-Kohari/khataping" 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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open-weight model:&lt;/strong&gt; Gemma, run locally through Ollama. The model tag is a setting, so any Gemma size works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamlit&lt;/strong&gt; for the UI, plain Python for everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model never does arithmetic.&lt;/strong&gt; Balances, ageing and sorting live in a tested &lt;code&gt;ledger.py&lt;/code&gt;. Payments settle the oldest credit first, so "days pending" means the age of the oldest unpaid credit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model's output is checked before anyone sees it.&lt;/strong&gt; A reply is accepted only if it contains the exact pending amount and nothing threatening (police, court or legal talk, in English, Hindi and Marathi). Otherwise the app uses a built-in template instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works without the model.&lt;/strong&gt; If Ollama isn't running, four languages and three tones of offline templates keep the tool usable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;41 pytest cases&lt;/strong&gt; cover FIFO settlement, overpayment, malformed CSVs, Indian digit grouping (12,34,567), and the case where the model changes the amount.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lesson: when the subject is money, the model's job should be the smallest part of the system, and the system should still work when the model is wrong or missing.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy.&lt;/strong&gt; A khata is a list of named neighbours and what they owe. A tool that sends that to a third-party API is a poor trade for the shopkeeper. With a local open-weight model, names, phone numbers and balances never leave the shop's laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; Reminders are short, so a small local model is enough, and there is no per-message fee. That makes a small monthly price (my guess, untested) viable for a shop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control.&lt;/strong&gt; I can swap the model with one setting, so the shop isn't tied to one vendor's pricing or availability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where it fell short: small local models are uneven in Marathi and Hindi, which is why the human edits before sending and why the plain, safe templates exist.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>TrailCard: a Gemma-powered trail planner that works with no signal</title>
      <dc:creator>Aakif Kohari</dc:creator>
      <pubDate>Wed, 07 Oct 2026 13:18:25 +0000</pubDate>
      <link>https://dev.to/aakif-kohari/trailcard-a-gemma-powered-trail-planner-that-works-with-no-signal-k90</link>
      <guid>https://dev.to/aakif-kohari/trailcard-a-gemma-powered-trail-planner-that-works-with-no-signal-k90</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&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;TrailCard is an offline trail-day planner. You enter a trail (or upload a GPX file) and it produces one printable A4 card: when to start, the latest time to turn back, when the sun sets, how much water to carry, and plain-language advice on packing, getting lost and Leave No Trace.&lt;/p&gt;

&lt;p&gt;The point is that the screen is the shortest part of the experience. You spend two minutes planning, print the card (or save it to your phone), put the phone on airplane mode and go outside. Nothing needs a signal on the trail.&lt;/p&gt;

&lt;p&gt;It is for casual hikers, trek groups and anyone who walks somewhere with patchy coverage. The mistakes that actually cause trouble are simple ones: starting too late and not knowing when to turn around. TrailCard turns those into numbers on a page.&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/Aakif-Kohari" rel="noopener noreferrer"&gt;
        Aakif-Kohari
      &lt;/a&gt; / &lt;a href="https://github.com/Aakif-Kohari/trailcard" rel="noopener noreferrer"&gt;
        trailcard
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Offline trail-day planner: Python computes sunset, turnaround and water; a local open-weight Gemma model (Ollama) writes a printable one-page trail card. Built for Hacktoberfest 2026 Touch Grass.
    &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;🥾 TrailCard&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Plan the trail day on a screen, then put the screen away.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TrailCard is an offline trail-day planner. You describe a hike (distance, climb, start time, location, or upload a GPX file) and it produces a &lt;strong&gt;one-page printable trail card&lt;/strong&gt;: when to start, when to turn back, when the sun sets, how much water to carry, and plain-language advice written by an &lt;strong&gt;open-weight Gemma model running locally through &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Print the card or save it to your phone, switch to airplane mode, and go outside. The screen is the shortest part of the experience.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it works with no signal&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Needs internet?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Walking time, turnaround, water&lt;/td&gt;
&lt;td&gt;Plain Python (&lt;a href="https://github.com/Aakif-Kohari/trailcard/planner.py" rel="noopener noreferrer"&gt;&lt;code&gt;planner.py&lt;/code&gt;&lt;/a&gt;) using Naismith's rule&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sunrise and sunset&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/sffjunkie/astral" rel="noopener noreferrer"&gt;&lt;code&gt;astral&lt;/code&gt;&lt;/a&gt;, computed from latitude, longitude and date&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPX distance and&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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/Aakif-Kohari/trailcard" 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;The core idea is a clear split: &lt;strong&gt;numbers come from code, words come from the model.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;planner.py&lt;/code&gt; is plain Python. It uses Naismith's rule (5 km/h plus 1 minute per 10 m of climb), adds breaks, and uses &lt;code&gt;astral&lt;/code&gt; for sunrise and sunset. It works out the latest safe start, the planned finish and a hard turnaround time, which is the last moment you can be at the halfway point and still finish an hour before sunset. It also works out water per person.&lt;/li&gt;
&lt;li&gt;The open-weight model is &lt;strong&gt;Gemma, run locally through Ollama&lt;/strong&gt; (the app defaults to &lt;code&gt;gemma3&lt;/code&gt; and lists whatever models you have installed). It receives those numbers as JSON and only writes the advice in six sections: Summary, Timeline, Pack list, Turnaround rule, If you get lost, and Leave No Trace.&lt;/li&gt;
&lt;li&gt;Small language models make things up, so the output is checked before it is trusted. If the model mentions a clock time that is not in the plan, the card falls back to a deterministic template. If it skips sections, they are filled from the template. If Ollama is not running, you still get a card. The numbers table at the top of the card is always generated by code.&lt;/li&gt;
&lt;li&gt;GPX files are parsed locally with &lt;code&gt;gpxpy&lt;/code&gt;. GPS altitude is noisy and inflates the climb, so a small filter ignores wiggles under 3 m.&lt;/li&gt;
&lt;li&gt;The UI is Streamlit, and the card is a Jinja2 template with print CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project has 42 pytest tests, and a GitHub Actions workflow runs them. The Ollama calls are mocked in the tests, so they run without a model installed.&lt;/p&gt;

&lt;p&gt;I used AI help while building this: a Qwen draft of the first version, then Claude to review, fix and test it. One real bug it caught was a timezone guess from longitude that put India 30 minutes off, so the form now asks for the UTC offset.&lt;/p&gt;

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

&lt;p&gt;A trail planner has to work in exactly the place where a cloud API doesn't: a ridge or forest with no signal. A closed hosted model would have failed at the one moment the product matters. A local open-weight model works with the laptop offline, and after the one-time model download the card needs no network at all.&lt;/p&gt;

&lt;p&gt;It also keeps your location on your own machine. There is no API key, no per-use cost and no account. Swapping models is a dropdown, so someone with an older laptop can use a smaller Gemma and someone with more RAM can use a larger one. Because the model only writes words, I could keep it small and replaceable instead of trusting it with safety-relevant numbers.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>PlacePal: an offline mock-interview coach I built for a friend, powered by Gemma and Ollama</title>
      <dc:creator>Aakif Kohari</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:48:17 +0000</pubDate>
      <link>https://dev.to/aakif-kohari/placepal-an-offline-mock-interview-coach-i-built-for-a-friend-powered-by-gemma-and-ollama-gi4</link>
      <guid>https://dev.to/aakif-kohari/placepal-an-offline-mock-interview-coach-i-built-for-a-friend-powered-by-gemma-and-ollama-gi4</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;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A batchmate of mine, has campus placement drives coming up and wants practice with real interview questions about &lt;em&gt;their own&lt;/em&gt; projects, not another generic list from the internet.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;PlacePal&lt;/strong&gt;, an offline mock-interview partner. You upload your resume (or paste its text), pick a target role and difficulty, and PlacePal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;writes 5 questions tailored to your resume: 2 technical, 2 about your projects, 1 HR&lt;/li&gt;
&lt;li&gt;scores each answer from 1 to 10, with strengths, gaps and a stronger sample answer&lt;/li&gt;
&lt;li&gt;tracks your average score per topic and tells you which topics to revise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem it solves is simple. A resume has your phone number, email, college and projects, and your interview answers show exactly where you are weak. That is the data you least want to paste into a hosted chatbot. PlacePal never sends it anywhere.&lt;/p&gt;

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

&lt;p&gt;There is no hosted demo, on purpose: the whole point is that PlacePal runs on your own machine. You can try it in a few minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma3:4b
git clone https://github.com/Aakif-Kohari/placepal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;placepal
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once the model is pulled, you can turn Wi-Fi off and it still works.&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/Aakif-Kohari" rel="noopener noreferrer"&gt;
        Aakif-Kohari
      &lt;/a&gt; / &lt;a href="https://github.com/Aakif-Kohari/placepal" rel="noopener noreferrer"&gt;
        placepal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Offline mock-interview coach for campus placements. Runs on a local open-weight model (Gemma via Ollama): resume-aware questions, honest scoring, weak-topic tracking. No cloud, no API key.
    &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;🎯 PlacePal&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;An offline mock-interview partner for campus placements, powered by an open-weight model running on your own laptop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PlacePal reads your resume, asks questions tailored to &lt;em&gt;your&lt;/em&gt; projects and your target role, scores each answer honestly, and tracks which topics keep dragging your scores down. Everything runs locally through &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; with a &lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;Gemma&lt;/a&gt; model. There is no API key, no account, no cloud, and no bill.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Built for the &lt;strong&gt;DEV Hacktoberfest Weekend Challenge: Build for a Friend&lt;/strong&gt; (Oct 2-5, 2026), for a friend preparing for campus placements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why local matters here&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;A resume carries your phone number, email, college and projects. Interview answers carry your weaknesses. That is exactly the data you do not want to paste into a hosted chatbot.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;PlacePal (local open-weight model)&lt;/th&gt;

&lt;th&gt;Typical hosted chatbot&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Resume leaves your machine&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Yes&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Works with Wi-Fi off&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;No&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Cost per practice session&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;Zero&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Credits / subscription&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Swap&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Aakif-Kohari/placepal" 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;&lt;strong&gt;The open-source AI:&lt;/strong&gt; &lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt;, Google's open-weight model, served locally by &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;. The default is &lt;code&gt;gemma3:4b&lt;/code&gt; (about a 3.3 GB download). The UI is Streamlit and resumes are parsed locally with pypdf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt; resume text goes into a prompt along with the role's focus areas and the difficulty. Gemma returns JSON, which I validate and show in the UI. Finished sessions are saved to a local JSON file, and a progress tab aggregates scores by topic.&lt;/p&gt;

&lt;p&gt;Most of the work was making a small local model behave reliably:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Defensive JSON handling.&lt;/strong&gt; Small models sometimes wrap JSON in markdown fences, add chatter, or return a score like &lt;code&gt;"7/10"&lt;/code&gt;. I extract the first valid JSON object, validate and clamp every field, and if the reply is unusable I tell the model what was wrong and retry twice before showing a clear error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoring I can trust a bit more.&lt;/strong&gt; Prompts alone didn't stop a small model from rewarding a one-line answer, so answers under 5 words are capped at 2/10 and under 15 words at 4/10, deterministically in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An honest privacy claim.&lt;/strong&gt; The app checks &lt;code&gt;OLLAMA_HOST&lt;/code&gt; and shows a warning banner if the server is not on the same machine. I also turned off Streamlit's anonymous usage stats so "nothing leaves this laptop" is actually true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests.&lt;/strong&gt; 34 tests run in CI, including the full Streamlit flow using Streamlit's &lt;code&gt;AppTest&lt;/code&gt;. The model call is a single function that tests replace with a fake.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used an AI assistant to help write the code, and I reviewed and tested it myself.&lt;/p&gt;

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

&lt;p&gt;A hosted API would have worked technically. For this project, it would have been the wrong tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by architecture.&lt;/strong&gt; With a local open-weight model, the resume and every answer stay on the laptop. I don't have to trust a privacy policy because there is no server to send the data to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline.&lt;/strong&gt; Placement prep happens in hostels, trains and places with bad Wi-Fi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costs nothing to run.&lt;/strong&gt; My friend can practice 20 rounds without credits, rate limits or a subscription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable.&lt;/strong&gt; The model is one environment variable. &lt;code&gt;PLACEPAL_MODEL=qwen3:4b streamlit run app.py&lt;/code&gt; changes the model without touching code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspectable.&lt;/strong&gt; Every prompt the model sees is in one readable file, &lt;code&gt;placepal/prompts.py&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is real. A 4B model is a more generous and less consistent grader than the biggest hosted models, which is why I added code-level guardrails and documented the limitation. People with more RAM can point &lt;code&gt;PLACEPAL_MODEL&lt;/code&gt; at a larger Gemma and get stricter feedback, which a closed API wouldn't let them choose.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

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