<?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: Dhanush Koyi</title>
    <description>The latest articles on DEV Community by Dhanush Koyi (@koyidhanush).</description>
    <link>https://dev.to/koyidhanush</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%2F4160415%2Fb5a11dc3-c895-4eb4-9c14-d455e701e2e8.png</url>
      <title>DEV Community: Dhanush Koyi</title>
      <link>https://dev.to/koyidhanush</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/koyidhanush"/>
    <language>en</language>
    <item>
      <title>Screenshot Séance: I Built a Local AI to Find the Screenshots That Still Need Me</title>
      <dc:creator>Dhanush Koyi</dc:creator>
      <pubDate>Mon, 26 Oct 2026 07:00:04 +0000</pubDate>
      <link>https://dev.to/koyidhanush/screenshot-seance-i-built-a-local-ai-to-find-the-screenshots-that-still-need-me-2pld</link>
      <guid>https://dev.to/koyidhanush/screenshot-seance-i-built-a-local-ai-to-find-the-screenshots-that-still-need-me-2pld</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;Taking a screenshot is easy. Coming back to it is apparently a separate hobby.&lt;/p&gt;

&lt;p&gt;A return label, a concert ticket, a recipe, a discount code. Each one comes with a tiny promise: “I’ll deal with this later.”&lt;/p&gt;

&lt;p&gt;Then later arrives, and the useful thing is somewhere between a meme and three screenshots of the same conversation.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Screenshot Séance&lt;/strong&gt;, or &lt;strong&gt;séance.&lt;/strong&gt;, around that unfinished business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find the few screenshots that still need you; let the rest go.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Séance uses Gemma 4 running locally through Ollama to read a screenshot folder and sort it into five buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Needs you&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Something to do: return an item, attend an appointment, use a code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Let go&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Memes, duplicates, finished things, or expired deadlines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Keep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Something worth keeping for its own sake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sensitive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Something flagged as containing passwords, card details, IDs, or recovery codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Not sure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Something that needs a human glance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Choose a folder, let it process, and come back to a smaller set of decisions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;“Do it all for me”&lt;/strong&gt; button puts actionable items on your list, keeps the keepsakes, and moves eligible clutter into a release folder. Anything marked as sensitive or uncertain awaits you.&lt;/p&gt;

&lt;p&gt;Letting go is reversible. Files move into &lt;code&gt;_released_by_seance&lt;/code&gt; beside the source folder; the app never permanently deletes them. Undo brings them back.&lt;/p&gt;

&lt;p&gt;There is also &lt;strong&gt;Old Ambrose&lt;/strong&gt;, an elderly sloth tarot reader who introduces the experience through captions. Your screenshots are the spirits, and some of them have unfinished business.&lt;/p&gt;

&lt;p&gt;Yes, I gave the screenshot folder a haunted-house theme.&lt;/p&gt;

&lt;p&gt;Every spooky label has a plain-language counterpart. The Daylight skin keeps things straightforward if you prefer your file management without the séance.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://screenshot-seance.vercel.app/" rel="noopener noreferrer"&gt;Try Screenshot Séance →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start a sorting run, explore the morning results, and try &lt;strong&gt;“Do it all for me.”&lt;/strong&gt; You can also review individual items, explore the list, and try the release and undo options.&lt;/p&gt;

&lt;p&gt;The hosted demo uses &lt;strong&gt;12 synthetic screenshots&lt;/strong&gt; and recorded classifications from the actual local pipeline. Sorting is an accelerated replay, and actions are simulated in browser memory.&lt;/p&gt;

&lt;p&gt;It does not access your screenshot folder, move your files, or run Gemma on Vercel.&lt;/p&gt;

&lt;p&gt;The full application runs on your own computer with Ollama. The public demo lets you explore the experience without installing the model or sharing personal screenshots.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/dkoyi/ScreenshotSeance" rel="noopener noreferrer"&gt;View Screenshot Séance on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dkoyi/ScreenshotSeance/blob/main/README.md" rel="noopener noreferrer"&gt;Read the README and setup instructions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application code is MIT licensed. The repository includes the backend, frontend, synthetic screenshots, benchmark script, tests, and browser demo implementation.&lt;/p&gt;

&lt;p&gt;The README explains how to install the prerequisites, pull &lt;code&gt;gemma4:e4b&lt;/code&gt; through Ollama, and launch the local application.&lt;/p&gt;

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

&lt;p&gt;The frontend uses &lt;strong&gt;React, TypeScript, Vite, Tailwind CSS, and Motion&lt;/strong&gt;. A local &lt;strong&gt;FastAPI&lt;/strong&gt; backend handles the screenshot workflow, &lt;strong&gt;SQLite&lt;/strong&gt; stores progress, and &lt;strong&gt;Ollama&lt;/strong&gt; serves the open-weight &lt;strong&gt;Gemma 4&lt;/strong&gt; model.&lt;/p&gt;

&lt;p&gt;The pipeline works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scan the folder.&lt;/strong&gt; Record image metadata, hashes, and local thumbnails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch near-duplicates.&lt;/strong&gt; Use perceptual hashes to identify copies before spending another model call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read one image at a time.&lt;/strong&gt; Send a resized screenshot to Gemma through Ollama’s &lt;code&gt;/api/chat&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the result.&lt;/strong&gt; Request structured JSON, check the response, and retry invalid output once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply local rules.&lt;/strong&gt; Resolve sensitivity, uncertainty, and deadlines before assigning the final bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save progress.&lt;/strong&gt; Persist the work so an interrupted run can resume.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Gemma interprets the screenshot: what it contains, whether it suggests an action, and whether there is a deadline or sensitive information.&lt;/p&gt;

&lt;p&gt;Ordinary Python code handles the rules around those predictions. A sensitivity flag takes priority over an actionable label. Low-confidence results go to “Not sure.” If the model flags something as actionable but cannot identify an action, it also gets held for review.&lt;/p&gt;

&lt;p&gt;Those checks still depend on what the model notices. Sensitivity detection can miss things, which is one reason reversible file moves and human review matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The unattended part needs to survive interruptions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The worker records progress in SQLite and can resume after a restart. After the initial sort, a watcher can detect newly added screenshots.&lt;/p&gt;

&lt;p&gt;The computer needs to stay awake to keep processing. If it sleeps or the app closes, saved progress resumes the work afterward.&lt;/p&gt;

&lt;p&gt;The useful results become a list. Calendar export produces an &lt;code&gt;.ics&lt;/code&gt; file with all-day events for dated items and to-dos for undated ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choosing the model involved a tradeoff.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In an initial benchmark of ten real screenshots on a laptop with an RTX 2060, 6 GB VRAM, and 32 GB RAM, I compared two models with thinking disabled and images capped at a 1024-pixel longest side:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Median per image&lt;/th&gt;
&lt;th&gt;Valid JSON on first attempt&lt;/th&gt;
&lt;th&gt;Card-number examples caught&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemma4:e4b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3.39 seconds&lt;/td&gt;
&lt;td&gt;9/10&lt;/td&gt;
&lt;td&gt;2/2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemma4:e2b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2.16 seconds&lt;/td&gt;
&lt;td&gt;10/10&lt;/td&gt;
&lt;td&gt;1/2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The smaller model was faster, but it missed one of the two sensitive card/bank examples. I chose &lt;code&gt;e4b&lt;/code&gt; as the default.&lt;/p&gt;

&lt;p&gt;This is a small local benchmark, not a general accuracy claim. A separate run on the 12 synthetic samples recorded a median API latency of 11.64 seconds, so the earlier timing is not a speed promise.&lt;/p&gt;

&lt;p&gt;For this workflow, processing time can be flexible. I care more about reducing the attention the folder asks of me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation covered the model pipeline and the surrounding application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The live synthetic run finished with 11 images classified by the model, one duplicate identified without a model call, and zero processing errors. That confirms the run completed; it does not establish perfect classification accuracy.&lt;/p&gt;

&lt;p&gt;The backend has &lt;strong&gt;24 passing tests&lt;/strong&gt;, including fake-model pipeline tests for listing, calendar export, release and restore, autopilot, and interrupted runs. The normal frontend build and hosted demo build also passed.&lt;/p&gt;

&lt;p&gt;I used &lt;strong&gt;GitHub Copilot&lt;/strong&gt; during development. For transparency about this article, I also used &lt;strong&gt;ChatGPT to draft and revise the write-up from my project notes and repository&lt;/strong&gt;. The benchmark figures describe the documented local runs; they are separate from the AI assistance used to prepare this post.&lt;/p&gt;

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

&lt;p&gt;Screenshots are an awkward thing to send to a hosted model.&lt;/p&gt;

&lt;p&gt;A folder can contain jokes, payment details, recovery codes, private messages, and something you forgot was there. Asking someone to upload that collection would change the kind of product I was building.&lt;/p&gt;

&lt;p&gt;Running Gemma locally through Ollama lets screenshot classification happen on the same machine as the files. Once the dependencies and model are installed, the local application can work offline.&lt;/p&gt;

&lt;p&gt;There is no inference account to create and no per-image API bill. There are still hardware and electricity costs, but a long sorting run does not accumulate usage charges from a hosted model provider.&lt;/p&gt;

&lt;p&gt;Open weights also give me a practical set of models to choose from. I can compare them on this task, change the configured Ollama model, and keep the surrounding application under my control.&lt;/p&gt;

&lt;p&gt;The application code is available too. Someone can inspect the rules, change the confidence threshold, adjust how deadlines are handled, or see exactly what “Let go” does before trusting it with a folder.&lt;/p&gt;

&lt;p&gt;That combination made the idea practical: local inference for private images, inspectable behavior, and the freedom to let the machine work at its own pace.&lt;/p&gt;

&lt;p&gt;The challenge’s &lt;strong&gt;Slow and Steady&lt;/strong&gt; theme fits the workflow. Sorting can take time while I do something else. The part that needs my attention should be smaller by the time I return.&lt;/p&gt;

&lt;p&gt;I still have to return the shoes myself. I would just like to find the label before the deadline.&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 4 runs locally through Ollama and performs the screenshot understanding at the core of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of GitHub Copilot&lt;/strong&gt; — I used GitHub Copilot during development of Screenshot Séance.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;What’s hiding in your screenshot folder: forgotten to-dos, memes, or a little of everything?&lt;/p&gt;

&lt;p&gt;I’d love to hear what you would want a tool like this to handle—and what you would always want to review yourself. Questions about the local setup or how it works are welcome too.&lt;/p&gt;

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