<?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: Abhinav Amrute</title>
    <description>The latest articles on DEV Community by Abhinav Amrute (@abhinav_amrute).</description>
    <link>https://dev.to/abhinav_amrute</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%2F4161668%2F9b7b2e79-bf1a-4bb2-a0f2-432fbd47d7d6.png</url>
      <title>DEV Community: Abhinav Amrute</title>
      <link>https://dev.to/abhinav_amrute</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abhinav_amrute"/>
    <language>en</language>
    <item>
      <title>SlothSort</title>
      <dc:creator>Abhinav Amrute</dc:creator>
      <pubDate>Fri, 23 Oct 2026 15:33:01 +0000</pubDate>
      <link>https://dev.to/abhinav_amrute/slothsort-1gfe</link>
      <guid>https://dev.to/abhinav_amrute/slothsort-1gfe</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;SlothSort&lt;/strong&gt; is a lazy person's file butler. It watches your Downloads folder (or any folder you point it at), reads what's actually inside each file, and then renames it with a sensible name, sorts it into the right folder, and archives anything stale, all by itself and all on your own machine.&lt;/p&gt;

&lt;p&gt;No more &lt;code&gt;Screenshot 2026-10-12 at 11.42.07 (3).png&lt;/code&gt;, &lt;code&gt;final_FINAL_v2.pdf&lt;/code&gt;, or a Downloads folder with 900 mystery files. You drop things in, SlothSort files them away overnight, and in the morning you get a short digest of what it moved and why. If it isn't confident about a file, it leaves it alone and flags it, and every move can be undone with one command.&lt;/p&gt;

&lt;p&gt;Anyone who has ever said "I'll clean this up later" gets to be a little lazier.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Video demo: [add your video link here]&lt;/li&gt;
&lt;li&gt;Deployed link (if any): [add link here]&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;[Add your GitHub repo link here. On DEV you can embed it directly with the &lt;code&gt;{% embed https://github.com/your-username/slothsort %}&lt;/code&gt; tag.]&lt;/p&gt;

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

&lt;p&gt;SlothSort is built around a &lt;strong&gt;local open-weight model served through Ollama&lt;/strong&gt;, so the whole pipeline runs without a network connection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; [your open-weight model, e.g. a small Qwen, Gemma or Llama variant] running locally via [Ollama / llama.cpp]. I picked a small model on purpose, since classifying and naming files doesn't need a giant one, and a small model keeps the laptop quiet and the battery happy (very sloth-appropriate).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watcher:&lt;/strong&gt; a lightweight Python script using &lt;code&gt;watchdog&lt;/code&gt; that notices new files and queues them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content extraction:&lt;/strong&gt; plain-text readers for PDFs, docs and text files, plus [a local vision model / OCR] for images and screenshots. Nothing is uploaded anywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision step:&lt;/strong&gt; the model gets the extracted text, the filename, and my folder rules, and returns a small JSON object: &lt;code&gt;{ "new_name": ..., "folder": ..., "confidence": ... }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety rails:&lt;/strong&gt; anything below a confidence threshold is skipped, nothing is ever deleted (only moved), and every action is written to a log so &lt;code&gt;slothsort undo&lt;/code&gt; can reverse it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Morning digest:&lt;/strong&gt; one short summary of what was filed, generated by the same local model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The folder rules live in a plain config file, so changing how SlothSort behaves means editing a few lines, not retraining anything.&lt;/p&gt;

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

&lt;p&gt;Sorting your files means the tool has to &lt;em&gt;read your files&lt;/em&gt;: tax documents, invoices, medical reports, private screenshots. That is exactly the kind of data I don't want to send to a server I don't control.&lt;/p&gt;

&lt;p&gt;Running an open-weight model locally made that possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by default:&lt;/strong&gt; file contents never leave my machine, so there is nothing to trust a third party with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline:&lt;/strong&gt; it runs on a plane, on bad Wi-Fi, or with the router unplugged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero running cost:&lt;/strong&gt; no per-file API charges, so I can let it process thousands of files without watching a bill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable and tunable:&lt;/strong&gt; I can change models as better open ones appear, adjust prompts and rules, and even fine-tune on my own naming style, none of which a closed API would let me do on my terms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No surprises:&lt;/strong&gt; the model version I tested with is the model version I keep running. It can't change under me or disappear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a "set it up once and forget it" tool, that reliability matters as much as the privacy.&lt;/p&gt;

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

&lt;p&gt;[Optional: embed your DevRelay session here with the &lt;code&gt;agent_session&lt;/code&gt; tag, or paste a link to it.]&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Files processed so far: [number]&lt;/li&gt;
&lt;li&gt;Time I used to spend tidying per week: [X minutes]&lt;/li&gt;
&lt;li&gt;Time I spend now: [near zero, plus a 10-second glance at the morning digest]&lt;/li&gt;
&lt;li&gt;Used by: [me / a friend / my team] this week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[Replace these with your real numbers, or delete this section if you'd rather not include it.]&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>ReceiptBox</title>
      <dc:creator>Abhinav Amrute</dc:creator>
      <pubDate>Tue, 13 Oct 2026 11:52:57 +0000</pubDate>
      <link>https://dev.to/abhinav_amrute/receiptbox-1o3g</link>
      <guid>https://dev.to/abhinav_amrute/receiptbox-1o3g</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;&lt;strong&gt;ReceiptBox&lt;/strong&gt; is a local-first invoice and receipt sorter for freelancers.&lt;/p&gt;

&lt;p&gt;Every freelancer knows the end-of-quarter scramble: a downloads folder full of &lt;code&gt;IMG_4821.jpg&lt;/code&gt;, &lt;code&gt;invoice (3).pdf&lt;/code&gt; and screenshots of payment confirmations, and an accountant waiting for a tidy spreadsheet. ReceiptBox fixes that.&lt;/p&gt;

&lt;p&gt;You drop a folder of messy receipts and invoices onto it. It then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads each file (photo, scan or PDF) with a local vision-language model&lt;/li&gt;
&lt;li&gt;Extracts vendor, date, total, tax, currency and a likely expense category&lt;/li&gt;
&lt;li&gt;Renames and files each document, e.g. &lt;code&gt;2026-09-14_Figma_USD-15.00_software.pdf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Exports a clean CSV that an accountant (or a tax tool) can open straight away&lt;/li&gt;
&lt;li&gt;Flags anything it is unsure about for a quick human check, instead of guessing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for it?&lt;/strong&gt; Freelance designers, developers, writers and consultants who handle their own books, and the small bookkeepers who serve them. The pitch is a one-time license or a small monthly fee (think $5-10/month) for something that saves a few hours every quarter and never uploads client paperwork anywhere.&lt;/p&gt;

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

&lt;p&gt;No hosted link: the whole point is that it runs on your own machine. Here is a typical run from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ receiptbox sort ./inbox --out ./sorted

Scanning 14 files...
 [ok]    IMG_4821.jpg        -&amp;gt; 2026-09-14_Figma_USD-15.00_software.jpg
 [ok]    invoice (3).pdf     -&amp;gt; 2026-09-02_Hetzner_EUR-4.51_hosting.pdf
 [ok]    scan0007.png        -&amp;gt; 2026-08-29_Uber_INR-342.00_travel.png
 [check] receipt_blurry.jpg  -&amp;gt; confidence 0.41, moved to ./sorted/_needs_review
 ...

Done: 13 sorted, 1 needs review
Wrote ./sorted/expenses_2026-Q3.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the resulting CSV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date,vendor,total,currency,tax,category,confidence,file
2026-09-14,Figma,15.00,USD,0.00,software,0.97,2026-09-14_Figma_USD-15.00_software.jpg
2026-09-02,Hetzner,4.51,EUR,0.72,hosting,0.95,2026-09-02_Hetzner_EUR-4.51_hosting.pdf
2026-08-29,Uber,342.00,INR,16.29,travel,0.93,2026-08-29_Uber_INR-342.00_travel.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;I'm not linking a repo for this post, so here are the core pieces inline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Schema for extraction (Pydantic):&lt;/strong&gt;&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;

&lt;span class="n"&gt;Category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;software&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hosting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;travel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;equipment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;office&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;marketing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;education&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Receipt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&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;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ISO 4217
&lt;/span&gt;    &lt;span class="n"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Extraction with a local VLM through Ollama:&lt;/strong&gt;&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are an accounting assistant. Read this receipt or invoice
and return ONLY JSON matching the schema. If a field is unreadable, lower
your confidence instead of guessing.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Receipt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;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;qwen2.5vl:7b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;images&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Receipt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_json_schema&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;  &lt;span class="c1"&gt;# constrained JSON output
&lt;/span&gt;        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Receipt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sorting, renaming and the review lane:&lt;/strong&gt;&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;

&lt;span class="n"&gt;THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_needs_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;THRESHOLD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_needs_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PDFs are rasterized page by page (first page for receipts, all pages for multi-page invoices) with &lt;code&gt;pdf2image&lt;/code&gt; before being passed to the model.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; an open-weight vision-language model, Qwen2.5-VL 7B, served locally through &lt;strong&gt;Ollama&lt;/strong&gt;. It reads photos, scans and screenshots directly, so there is no separate OCR step to tune.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured output:&lt;/strong&gt; Ollama's JSON-schema constrained decoding plus Pydantic validation. The model cannot return a malformed record, and bad values get caught before they reach the CSV.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence-gated workflow:&lt;/strong&gt; the model reports a confidence score and anything below the threshold goes to a &lt;code&gt;_needs_review&lt;/code&gt; folder. For money data, "I'm not sure" is a feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plumbing:&lt;/strong&gt; Python, &lt;code&gt;pdf2image&lt;/code&gt; for PDFs, SQLite for a local index (so re-running never duplicates files), and a small Typer CLI. A drag-and-drop desktop wrapper is the next step for non-technical users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware:&lt;/strong&gt; it runs on a laptop with 16 GB RAM. A quantized build keeps it usable without a dedicated GPU, just slower.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Privacy is the product.&lt;/strong&gt; Receipts and invoices reveal who your clients are, what you charge and how you live. Many freelancers are under NDAs, and a lot of them simply do not want their financial paperwork sitting on someone else's server. With an open-weight model, ReceiptBox works with the Wi-Fi off. That is a real selling point, and a closed API can't offer it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The economics work.&lt;/strong&gt; A closed vision API charges per image, which punishes exactly the heavy, bursty usage of tax season, and it makes a $5/month price point risky. Local inference costs the user electricity, so my marginal cost per customer is effectively zero and the business can stay small and sustainable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No lock-in, and room to specialize.&lt;/strong&gt; I can swap in a newer or smaller model as soon as one is better, pin a version so extraction doesn't silently change mid-quarter, and fine-tune on region-specific formats (GST invoices in India, VAT receipts in the EU, handwritten rickshaw slips) that general-purpose APIs handle unevenly. If a vendor changes pricing or deprecates a model, my product doesn't break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where closed would have been better:&lt;/strong&gt; a frontier hosted model probably has higher raw accuracy on very bad photos. The review lane and confidence threshold are how I make up for that, and for this use case, "private and cheap with a human check on the hard 5%" beats "slightly more accurate but uploads everything."&lt;/p&gt;

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

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Pocket Naturalist</title>
      <dc:creator>Abhinav Amrute</dc:creator>
      <pubDate>Thu, 08 Oct 2026 18:10:03 +0000</pubDate>
      <link>https://dev.to/abhinav_amrute/pocket-naturalist-2e38</link>
      <guid>https://dev.to/abhinav_amrute/pocket-naturalist-2e38</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;&lt;strong&gt;Pocket Naturalist&lt;/strong&gt; is an offline field guide that helps you learn the plants and trees around you without staring at a screen.&lt;/p&gt;

&lt;p&gt;You snap one photo of a leaf, bark, or flower, then put the phone back in your pocket. A local vision-language model identifies the likely species, and a short spoken note plays in your earbuds: the name, one interesting fact, and a "look for this next" prompt, like the shape of the bark or the berries nearby. The screen is only used for the single photo, and everything else is audio.&lt;/p&gt;

&lt;p&gt;It's for casual hikers, parents on weekend walks, and anyone who has wondered "what &lt;em&gt;is&lt;/em&gt; that tree?" but didn't want to stop and search. It works with no signal, which is where most good trails are.&lt;/p&gt;

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

&lt;p&gt;Coming soon. I'll add a short video of a real trail walk after my first field test.&lt;/p&gt;

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

&lt;p&gt;Coming soon. The repo will be open-source and linked here.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; a small open-weight vision-language model (such as a Gemma or Qwen-VL variant), quantized to run on a laptop or recent phone-class device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inference:&lt;/strong&gt; fully local through &lt;code&gt;llama.cpp&lt;/code&gt; / Ollama. No API calls and no network needed after the initial model download.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-to-speech:&lt;/strong&gt; an open-source offline TTS engine (such as Piper) reads the result aloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent logic:&lt;/strong&gt; a lightweight loop that takes the photo, produces a species guess with a confidence level, adds a short fact, and generates a "look for this next" prompt so the walk keeps going.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety rail:&lt;/strong&gt; the app never says anything is safe to eat. If confidence is low, it says "I'm not sure, here are two possibilities" instead of guessing. Foraging is deliberately out of scope.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It works where the trail has no signal.&lt;/strong&gt; A closed API can't identify a plant from a ridgeline with zero bars. A local open-weight model can.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your photos and location stay on your device.&lt;/strong&gt; Nobody's walking habits get uploaded to a server they don't control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing per scan.&lt;/strong&gt; With no API fees, you can scan 200 leaves on one walk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can be fine-tuned for a region.&lt;/strong&gt; Because the weights are open, a local nature club could tune the model on regional flora and share it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Models are swappable.&lt;/strong&gt; As better small open models appear, upgrading means changing one line instead of rewriting around a new vendor.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Coming soon. I'll save my build session with DevRelay and link it here.&lt;/p&gt;

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

&lt;p&gt;Open-weight models, local inference.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Submission hactoberfest</title>
      <dc:creator>Abhinav Amrute</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:31:54 +0000</pubDate>
      <link>https://dev.to/abhinav_amrute/submission-hactoberfest-2b03</link>
      <guid>https://dev.to/abhinav_amrute/submission-hactoberfest-2b03</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;h2&gt;
  
  
  Demo
&lt;/h2&gt;

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

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

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

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

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

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