<?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: thedarkking01</title>
    <description>The latest articles on DEV Community by thedarkking01 (@thedarkking01).</description>
    <link>https://dev.to/thedarkking01</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%2F1266753%2F5f33a1b8-7b77-4371-b6fd-9d6b22024486.png</url>
      <title>DEV Community: thedarkking01</title>
      <link>https://dev.to/thedarkking01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thedarkking01"/>
    <language>en</language>
    <item>
      <title>FolderZen-an-AI-Powered-File-Organizer</title>
      <dc:creator>thedarkking01</dc:creator>
      <pubDate>Sat, 24 Oct 2026 12:38:48 +0000</pubDate>
      <link>https://dev.to/thedarkking01/folderzen-an-ai-powered-file-organizer-nin</link>
      <guid>https://dev.to/thedarkking01/folderzen-an-ai-powered-file-organizer-nin</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;FolderZen&lt;/strong&gt; is a local AI-powered file organizer that turns a folder full of cryptically named documents — &lt;code&gt;doc_12.pdf&lt;/code&gt;, &lt;code&gt;final_v3.docx&lt;/code&gt;, &lt;code&gt;scan_04.pdf&lt;/code&gt; — into a clean, categorized structure with meaningful names, without ever sending your files to the cloud.&lt;/p&gt;

&lt;p&gt;You point it at a messy folder. It reads the content of your PDFs, Word documents, and text files, asks a local AI model what each one actually &lt;em&gt;is&lt;/em&gt;, and suggests a descriptive filename, a category, and a destination folder. You review every suggestion in an editable table, preview the exact paths before anything moves, then approve and apply.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who gets to be lazier:&lt;/strong&gt; anyone whose Downloads folder looks like a crime scene. Students with &lt;code&gt;assignment_FINAL_v3_REAL.docx&lt;/code&gt;. Freelancers with &lt;code&gt;invoice_copy2.pdf&lt;/code&gt;. Anyone who has spent 10 minutes hunting for a file they definitely saved &lt;em&gt;somewhere&lt;/em&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Scan&lt;/td&gt;
&lt;td&gt;Detects all files, reads metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Extract&lt;/td&gt;
&lt;td&gt;Reads text from PDF, DOCX, TXT (up to 1500 chars)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. AI suggest&lt;/td&gt;
&lt;td&gt;Sends text to local &lt;code&gt;gemma3:1b&lt;/code&gt; via Ollama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Review&lt;/td&gt;
&lt;td&gt;Editable table — approve, reject, or edit each suggestion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Preview&lt;/td&gt;
&lt;td&gt;Shows exact destination paths before touching anything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Apply&lt;/td&gt;
&lt;td&gt;Moves approved files; never overwrites; blocks path traversal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Report&lt;/td&gt;
&lt;td&gt;Success / failure summary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;blockquote&gt;
&lt;p&gt;📹 &lt;em&gt;Add your screen recording or GIF here — record with OBS, ShareX, or Windows Game Bar (Win+G) pointing at the Streamlit app on &lt;code&gt;localhost:8501&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sample results from the included &lt;code&gt;sample_files/&lt;/code&gt; folder:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Messy filename&lt;/th&gt;
&lt;th&gt;AI suggestion&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc_12.pdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PythonInterviewNotes.pdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tech&lt;/td&gt;
&lt;td&gt;Contains Python interview prep notes covering data structures and algorithms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scan_04.pdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Electricity_Bill_October.pdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;td&gt;Appears to be a utility bill with account number and amount due&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;final_v3.docx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FolderZen_Project_Proposal.docx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Work&lt;/td&gt;
&lt;td&gt;Contains a project proposal with objectives and timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resume_draft.docx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Jane_Doe_Resume.docx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Personal&lt;/td&gt;
&lt;td&gt;Resume document listing skills and work experience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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/thedarkking01" rel="noopener noreferrer"&gt;
        thedarkking01
      &lt;/a&gt; / &lt;a href="https://github.com/thedarkking01/FolderZen-an-AI-Powered-File-Organizer" rel="noopener noreferrer"&gt;
        FolderZen-an-AI-Powered-File-Organizer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;FolderZen 🗂️&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Local AI-powered file organizer. No cloud. No API keys. Your files stay on your machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;FolderZen scans a messy folder, reads document content, and uses a local AI model (via Ollama) to suggest meaningful filenames, categories, and destinations — then lets you review and approve every change before anything moves.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick start&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 1. Clone&lt;/span&gt;
git clone https://github.com/YOUR_USERNAME/FolderZen.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; FolderZen

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 2. Create virtual environment&lt;/span&gt;
python -m venv .venv
.venv&lt;span class="pl-cce"&gt;\S&lt;/span&gt;cripts&lt;span class="pl-cce"&gt;\a&lt;/span&gt;ctivate      &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Windows&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; source .venv/bin/activate  # macOS / Linux&lt;/span&gt;

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 3. Install dependencies&lt;/span&gt;
pip install -r requirements.txt

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 4. Pull the AI model (one-time)&lt;/span&gt;
ollama pull gemma3:1b

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; 5. Run&lt;/span&gt;
streamlit run app.py&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Generate sample files (optional)&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;python create_samples.py&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then point the app at the &lt;code&gt;sample_files/&lt;/code&gt; folder.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run tests&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pytest tests/ -v&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&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;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Scan&lt;/td&gt;
&lt;td&gt;Detects all files, reads metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Extract&lt;/td&gt;
&lt;td&gt;Reads text from PDF, DOCX, TXT (up&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/thedarkking01/FolderZen-an-AI-Powered-File-Organizer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Project structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FolderZen/
├── app.py               # Streamlit UI — all 4 steps
├── file_scanner.py      # Folder scanning and metadata
├── document_reader.py   # PDF, DOCX, TXT text extraction
├── ai_organizer.py      # Ollama prompt + JSON response parser
├── file_operations.py   # Safe move/rename with collision detection
├── create_samples.py    # Generates demo files
├── requirements.txt
└── tests/
    ├── test_scanner.py          # 6 tests
    └── test_file_operations.py  # 9 tests — 15 passing total
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick start:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/thedarkking01/FolderZen-an-AI-Powered-File-Organizer
&lt;span class="nb"&gt;cd &lt;/span&gt;FolderZen

python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
.venv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate        &lt;span class="c"&gt;# Windows&lt;/span&gt;
&lt;span class="c"&gt;# source .venv/bin/activate   # macOS / Linux&lt;/span&gt;

pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
ollama pull gemma3:1b
streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run tests:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest tests/ &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;&lt;strong&gt;Open-source AI used:&lt;/strong&gt; &lt;a href="https://ollama.com/library/gemma3" rel="noopener noreferrer"&gt;Gemma 3 1B&lt;/a&gt; by Google, running locally via &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The core AI loop lives in &lt;code&gt;ai_organizer.py&lt;/code&gt;. For each readable file, FolderZen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extracts up to 1500 characters of text using PyMuPDF (PDF) or python-docx (DOCX)&lt;/li&gt;
&lt;li&gt;Sends a structured prompt to &lt;code&gt;gemma3:1b&lt;/code&gt; via the Ollama Python client&lt;/li&gt;
&lt;li&gt;Parses the model's JSON response — category, suggested filename, destination folder, and a one-sentence reason&lt;/li&gt;
&lt;li&gt;Falls back gracefully if the model returns malformed output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The prompt is deliberately minimal to keep the 1B model fast and on-task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a file organizer. Given a document snippet, return ONLY a JSON object with:
- "category": one of [Work, Finance, Personal, Education, Legal, Medical, Tech, Other]
- "suggested_name": descriptive filename without extension
- "destination": short folder path
- "reason": one sentence explaining why
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Temperature is set to &lt;code&gt;0.2&lt;/code&gt; so suggestions are consistent rather than creative. The 1B model processes each file in roughly 3–8 seconds on an RTX 2050 with 4 GB VRAM — no internet required.&lt;/p&gt;

&lt;p&gt;The file operations layer (&lt;code&gt;file_operations.py&lt;/code&gt;) is intentionally separate from the AI layer and handles three safety concerns independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collision detection&lt;/strong&gt; — &lt;code&gt;_unique_path()&lt;/code&gt; appends &lt;code&gt;_1&lt;/code&gt;, &lt;code&gt;_2&lt;/code&gt; … rather than overwriting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path traversal prevention&lt;/strong&gt; — &lt;code&gt;_no_traversal()&lt;/code&gt; resolves both paths and checks &lt;code&gt;relative_to()&lt;/code&gt; before any move executes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character sanitisation&lt;/strong&gt; — strips &lt;code&gt;&amp;lt; &amp;gt; : " / \ | ? *&lt;/code&gt; from filenames and folder names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The UI is Streamlit with &lt;code&gt;st.data_editor&lt;/code&gt; for the review table, so users can edit the AI's suggestions inline before approving them. Nothing moves until the user explicitly clicks &lt;strong&gt;Apply approved changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full stack:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;Streamlit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI runtime&lt;/td&gt;
&lt;td&gt;Ollama (local)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI model&lt;/td&gt;
&lt;td&gt;Gemma 3 1B (open-weight)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF reading&lt;/td&gt;
&lt;td&gt;PyMuPDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOCX reading&lt;/td&gt;
&lt;td&gt;python-docx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File ops&lt;/td&gt;
&lt;td&gt;pathlib + shutil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;pytest — 15 tests, all passing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;A closed-API version of this tool would have a fundamental problem: to organize your files, it would need to read your files. That means your electricity bills, your resume, your medical documents, your contracts — all uploaded to a third-party server to be processed.&lt;/p&gt;

&lt;p&gt;With an open-weight model running locally via Ollama, none of that happens. The text extracted from your documents goes to a process running on your own GPU and never leaves your machine. There is no API key to leak, no usage bill, no terms of service that change what happens to your data next quarter.&lt;/p&gt;

&lt;p&gt;Open innovation also made the 1B model size possible. Gemma 3 1B is small enough to run on a laptop GPU with 4 GB VRAM and still produce useful, structured output. That's only possible because Google released the weights openly — a closed-API equivalent would require a network round-trip and a paid account just to categorize a text file.&lt;/p&gt;

&lt;p&gt;For a tool that touches personal documents, local-first isn't a nice-to-have. It's the only honest architecture.&lt;/p&gt;




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

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Save and embed your DevRelay session here using the &lt;code&gt;agent_session&lt;/code&gt; tag, or remove this section.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;I tested FolderZen on the included &lt;code&gt;sample_files/&lt;/code&gt; folder with 12 mixed files — PDFs, DOCXs, TXTs, an empty file, and a file with no extension.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual organization&lt;/strong&gt; (rename + sort into folders by hand): ~8 minutes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FolderZen&lt;/strong&gt; (scan → suggestions → review → apply): ~2.5 minutes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scan: instant&lt;/li&gt;
&lt;li&gt;AI suggestions for 12 files: ~60 seconds on RTX 2050&lt;/li&gt;
&lt;li&gt;Review and approve: ~45 seconds&lt;/li&gt;
&lt;li&gt;Apply + report: instant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI got 10 out of 12 filenames right without any editing. The two it got wrong were files with very short content (under 50 chars) — it suggested generic names instead of something specific. That's expected for a 1B model with minimal context, and the editable review table exists exactly for those cases.&lt;/p&gt;

&lt;p&gt;The real payoff isn't the 5-minute saving on 12 files. It's that the review step forces you to look at every file before it moves — the human stays in the loop, and the AI handles the tedious part of reading and naming.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;🏆 Best Use of Open-Source AI&lt;/li&gt;
&lt;li&gt;🛠️ Most Useful Developer Tool&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>I Built an AI Expense Tracker for Freelancers — No Cloud, No API Key, No Data Leaks</title>
      <dc:creator>thedarkking01</dc:creator>
      <pubDate>Sun, 18 Oct 2026 18:01:55 +0000</pubDate>
      <link>https://dev.to/thedarkking01/i-built-an-ai-expense-tracker-for-freelancers-no-cloud-no-api-key-no-data-leaks-5fjn</link>
      <guid>https://dev.to/thedarkking01/i-built-an-ai-expense-tracker-for-freelancers-no-cloud-no-api-key-no-data-leaks-5fjn</guid>
      <description>&lt;h1&gt;
  
  
  I Built FreelanceFlow: A Local-First AI Receipt Manager for Freelancers
&lt;/h1&gt;

&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;FreelanceFlow is a &lt;strong&gt;privacy-first AI business assistant&lt;/strong&gt; for freelancers. It turns a folder of scattered receipts into an organized financial dashboard — without uploading a single file to the cloud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem it solves:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every freelancer I know has the same pain: receipts scattered across email, phone photos, and random folders. At the end of the month they either spend hours manually entering everything into a spreadsheet, or they hand a mess to their accountant and hope for the best. Neither is good.&lt;/p&gt;

&lt;p&gt;FreelanceFlow fixes this with a simple workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upload&lt;/strong&gt; a receipt photo or PDF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI extracts&lt;/strong&gt; the merchant, date, amount, currency, and expense category&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You review and correct&lt;/strong&gt; before anything is saved — no blind trust in the model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard shows&lt;/strong&gt; income, expenses, net cash flow, and category breakdowns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invoice tracker&lt;/strong&gt; flags unpaid and overdue invoices automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly report&lt;/strong&gt; generates an AI-written summary and a downloadable CSV&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for this:&lt;/strong&gt;&lt;br&gt;
Freelance developers, designers, consultants, and solo founders who hate admin work. The recurring pain is real — recording expenses, chasing invoices, and preparing records for an accountant. A Pro tier at ₹249/month (roughly $3) for higher document limits and invoice reminders is a realistic starting point to validate.&lt;/p&gt;


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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Local-first app — runs entirely on your machine.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To run it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Pull the AI model&lt;/span&gt;
ollama pull gemma3:4b
ollama serve

&lt;span class="c"&gt;# 2. Backend&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;backend
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
.&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python seed.py        &lt;span class="c"&gt;# loads sample data&lt;/span&gt;
uvicorn main:app &lt;span class="nt"&gt;--reload&lt;/span&gt;

&lt;span class="c"&gt;# 3. Frontend&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; — the dashboard loads with seeded sample data immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you'll see:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboard with income/expense cards, a monthly bar chart, and a category pie chart&lt;/li&gt;
&lt;li&gt;Receipts page — upload any JPG, PNG, or PDF and watch the AI fill in the form&lt;/li&gt;
&lt;li&gt;Invoice tracker with color-coded paid / unpaid / overdue status&lt;/li&gt;
&lt;li&gt;Reports page — pick a month, generate an AI summary, download CSV&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/thedarkking01" rel="noopener noreferrer"&gt;
        thedarkking01
      &lt;/a&gt; / &lt;a href="https://github.com/thedarkking01/FreelanceFlow-AI-Business-Assistant" rel="noopener noreferrer"&gt;
        FreelanceFlow-AI-Business-Assistant
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a privacy-focused AI assistant that helps freelancers manage receipts, invoices, expenses, and monthly financial reports without manually entering every transaction
    &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;FreelanceFlow — AI Business Assistant&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;A local-first AI receipt and expense manager for freelancers.&lt;br&gt;
Upload receipts → AI extracts the details → review → track invoices → generate monthly reports.&lt;br&gt;
Everything runs on your machine. No data leaves your device.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Built for the &lt;strong&gt;Hacktoberfest 2026 Open-Source AI Challenge&lt;/strong&gt;.&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&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;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;Feature&lt;/th&gt;

&lt;th&gt;Description&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Smart Receipt Scanner&lt;/td&gt;

&lt;td&gt;Upload JPG, PNG, or PDF — OCR + Gemma extracts merchant, date, amount, category&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Human-in-the-loop Review&lt;/td&gt;

&lt;td&gt;AI suggestions are editable before saving — no blind trust in model output&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;AI Expense Categorization&lt;/td&gt;

&lt;td&gt;Software, Hardware, Travel, Food, Office Supplies, Marketing, Other&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Financial Dashboard&lt;/td&gt;

&lt;td&gt;Income, expenses, net cash flow, category pie chart, monthly bar chart&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Invoice Tracker&lt;/td&gt;

&lt;td&gt;Record invoices, auto-detect overdue, mark as paid, delete&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Monthly Report Generator&lt;/td&gt;

&lt;td&gt;AI-written summary + CSV export — fallback summary if Ollama is offline&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Privacy by Design&lt;/td&gt;

&lt;td&gt;All OCR, AI inference, and storage happen locally — zero telemetry&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;&lt;br&gt;
&lt;p&gt;&lt;/p&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack&lt;/h2&gt;
&lt;/div&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;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Layer&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&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/thedarkking01/FreelanceFlow-AI-Business-Assistant" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;strong&gt;Project structure at a glance:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;freelanceflow/
├── backend/
│   ├── main.py              # FastAPI entry point
│   ├── database.py          # SQLAlchemy models
│   ├── models.py            # Pydantic validation schemas
│   ├── seed.py              # Sample data loader
│   ├── routes/
│   │   ├── receipts.py      # Upload → OCR → AI → confirm
│   │   ├── invoices.py      # Invoice CRUD + overdue detection
│   │   ├── dashboard.py     # Financial aggregations (pure Python math)
│   │   └── reports.py       # AI monthly summary + CSV export
│   └── services/
│       ├── ocr.py           # Tesseract + pdfplumber
│       ├── ai_extractor.py  # Ollama + Gemma structured extraction
│       └── categorizer.py   # Keyword-based category fallback
├── frontend/
│   └── src/
│       ├── pages/           # Dashboard, Receipts, Invoices, Reports
│       ├── components/      # Sidebar navigation
│       └── api/             # Axios client
└── tests/                   # 23 tests — validators, math, report logic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;h3&gt;
  
  
  The AI pipeline
&lt;/h3&gt;

&lt;p&gt;The core AI workflow is a three-stage pipeline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1 — OCR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the AI sees anything, the document is converted to plain text. PDFs go through &lt;code&gt;pdfplumber&lt;/code&gt; for clean text extraction. Images (JPG, PNG) go through Tesseract OCR. This keeps the pipeline debuggable — you can inspect the raw text at any point.&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="c1"&gt;# services/ocr.py
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;extract_text_from_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;extract_text_from_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&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;Stage 2 — Structured AI extraction with Gemma&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The OCR text is sent to a locally running Gemma 3 4B model via Ollama. The prompt asks for a strict JSON response with defined fields — merchant, date, amount, currency, category, tax. Ollama's &lt;code&gt;format: "json"&lt;/code&gt; parameter constrains the output to valid JSON.&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="c1"&gt;# services/ai_extractor.py
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434/api/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;json&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;model&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;gemma3:4b&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;prompt&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;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&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;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;,&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&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;{}&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;Every field is then validated and sanitized — dates are checked with &lt;code&gt;date.fromisoformat()&lt;/code&gt;, amounts must be positive floats, categories must be from the allowed set. If Ollama is offline, the endpoint returns an empty scaffold so the user can fill it in manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3 — Keyword fallback categorization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If Gemma returns "Other" for the category, a keyword-based categorizer runs over the merchant name and raw OCR text as a second pass:&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="c1"&gt;# services/categorizer.py
&lt;/span&gt;&lt;span class="n"&gt;_KEYWORDS&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;Software&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;saas&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;subscription&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;adobe&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;github&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;aws&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="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uber&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;ola&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;flight&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;hotel&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;airbnb&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;Food&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;swiggy&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;zomato&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;restaurant&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;cafe&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;coffee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This catches common cases even when the AI is uncertain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human-in-the-loop review&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI output is never saved directly. Every upload returns a pre-filled editable form. The user corrects any mistakes, then clicks "Confirm &amp;amp; Save." Only confirmed records enter the expense ledger. This is the most important design decision in the whole app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Financial calculations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All arithmetic — totals, category breakdowns, net cash flow, monthly trends — is done in Python with SQLAlchemy queries. The AI is never asked to do math. This is a hard rule: AI for understanding documents, Python for numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monthly reports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The report endpoint aggregates the month's data in Python, then sends a structured prompt to Gemma asking for a 3–4 sentence professional summary. If Ollama is unavailable, a rule-based fallback generates a plain-English summary from the same numbers — so the feature always works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech stack
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vite + React + TailwindCSS + Recharts&lt;/td&gt;
&lt;td&gt;Fast dev, great charts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python FastAPI&lt;/td&gt;
&lt;td&gt;Async, auto-docs, Pydantic validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Ollama + Gemma 3 4B&lt;/td&gt;
&lt;td&gt;Local inference, no API key, open-weight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCR&lt;/td&gt;
&lt;td&gt;Tesseract + pdfplumber&lt;/td&gt;
&lt;td&gt;Handles both images and PDFs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;SQLite via SQLAlchemy&lt;/td&gt;
&lt;td&gt;Zero config, local file, portable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;Three things that a closed API simply cannot give you:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Privacy is a real feature, not a marketing claim&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a freelancer uploads a receipt, it contains their client's name, the amount they were paid, what software they use, where they travel. With a closed cloud API, that data leaves the device. With Ollama + Gemma running locally, the receipt text never touches an external server. The only network call the app makes is to &lt;code&gt;localhost:11434&lt;/code&gt;. That's a meaningful difference for anyone working with confidential client information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. It works offline and costs nothing to run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No API key. No monthly inference bill that scales with usage. No rate limits. No service going down and breaking your app. Once Gemma is pulled, the app runs indefinitely on your own hardware. For a bootstrapped side project targeting price-sensitive freelancers, this matters enormously — the marginal cost of an AI-powered feature is zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. You can inspect, replace, and improve the model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With a closed API you accept whatever the provider ships. With Ollama you can swap &lt;code&gt;gemma3:4b&lt;/code&gt; for &lt;code&gt;llama3.2&lt;/code&gt;, &lt;code&gt;mistral&lt;/code&gt;, or any other compatible model in one line. You can test different models against your receipt test set and pick the one that performs best for your use case. That kind of control is only possible with open-weight models.&lt;/p&gt;




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

&lt;p&gt;I tested FreelanceFlow against a set of 20 synthetic receipts covering different formats — printed PDFs, handwritten-style images, multi-line receipts, and receipts with tax lines.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Merchant name accuracy&lt;/td&gt;
&lt;td&gt;17/20 correct (85%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date extraction accuracy&lt;/td&gt;
&lt;td&gt;19/20 correct (95%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amount extraction accuracy&lt;/td&gt;
&lt;td&gt;18/20 correct (90%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category accuracy (AI + keyword fallback)&lt;/td&gt;
&lt;td&gt;16/20 correct (80%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average processing time per receipt&lt;/td&gt;
&lt;td&gt;~4–6 seconds on CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receipts needing manual correction&lt;/td&gt;
&lt;td&gt;~25%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 25% manual correction rate is honest and expected. The human-in-the-loop design exists precisely because the model isn't perfect. The goal isn't 100% accuracy — it's to eliminate 75–80% of manual data entry while keeping the user in control of the rest.&lt;/p&gt;

&lt;p&gt;Failures were mostly on low-quality images (blurry phone photos) and receipts with unusual formatting. PDF extraction was consistently more reliable than image OCR.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Structured output prompting is worth the effort.&lt;/strong&gt; Asking Gemma to return JSON with &lt;code&gt;format: "json"&lt;/code&gt; and a clear field-by-field prompt description dramatically improved consistency compared to asking for free-form text and parsing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fallback matters more than you think.&lt;/strong&gt; Ollama wasn't running during one of my test sessions and the whole upload flow broke silently. Adding graceful degradation — empty scaffold for manual entry, rule-based report summary — made the app usable even without the AI layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OCR quality is the real bottleneck.&lt;/strong&gt; The AI extraction is only as good as the text it receives. A blurry phone photo produces garbage OCR output, and no amount of prompt engineering fixes that. Preprocessing images (contrast, deskew) before OCR would be the highest-leverage improvement.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;Image preprocessing before OCR (contrast enhancement, deskew) to improve accuracy on phone photos&lt;/li&gt;
&lt;li&gt;Recurring expense detection — flag when the same merchant appears every month&lt;/li&gt;
&lt;li&gt;Invoice reminder notifications — email or desktop notification when due dates approach&lt;/li&gt;
&lt;li&gt;Multi-currency support with exchange rate conversion for international freelancers&lt;/li&gt;
&lt;li&gt;Export to PDF for accountant-ready monthly reports&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Running the Tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;backend
.&lt;span class="se"&gt;\v&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest ..&lt;span class="se"&gt;\t&lt;/span&gt;ests&lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;23 passed in 10.15s

tests/test_validators.py   — 9 tests  (Pydantic model validation)
tests/test_reports.py      — 7 tests  (month filtering, AI fallback, CSV)
tests/test_dashboard.py    — 7 tests  (expense totals, net cash flow, overdue)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  devchallenge #hf26challenge #python #react #opensource
&lt;/h1&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>TouchGrass AI — I Built an AI Whose Only Goal Is to Get You Away From the Computer</title>
      <dc:creator>thedarkking01</dc:creator>
      <pubDate>Sat, 10 Oct 2026 16:25:05 +0000</pubDate>
      <link>https://dev.to/thedarkking01/touchgrass-ai-i-built-an-ai-whose-only-goal-is-to-get-you-away-from-the-computer-4179</link>
      <guid>https://dev.to/thedarkking01/touchgrass-ai-i-built-an-ai-whose-only-goal-is-to-get-you-away-from-the-computer-4179</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;TouchGrass AI&lt;/strong&gt; is an open-source AI experiment designed to solve an unusual problem: getting people to stop using AI and go outside.&lt;/p&gt;

&lt;p&gt;You tell it three things — how much time you have, your energy level, and what you're into. Gemma generates a personalized outdoor mission and sends you out the door. When you come back, you reflect on what you found.&lt;/p&gt;

&lt;p&gt;The core loop:&lt;/p&gt;

&lt;p&gt;The screen is intentionally the &lt;strong&gt;shortest&lt;/strong&gt; part of the experience. No feeds, no notifications, no reason to stay. Just a mission and a door.&lt;/p&gt;

&lt;p&gt;It's for anyone who spends too much time on a screen — which, if you're reading this, is probably you.&lt;/p&gt;

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

&lt;p&gt;The app has 4 screens:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Preferences&lt;/td&gt;
&lt;td&gt;Pick your time (15m → 2h+), energy (Low/Medium/High), and interest (Nature, Fitness, Explore, Photo, Surprise)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. AI Mission&lt;/td&gt;
&lt;td&gt;Gemma generates a title, one-sentence scene-setter, and 3 specific tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Go outside&lt;/td&gt;
&lt;td&gt;A minimal screen that just says: go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Reflect&lt;/td&gt;
&lt;td&gt;Two text fields — what did you find, how did it go&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🔗 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/thedarkking01/TouchGrass-AI" rel="noopener noreferrer"&gt;https://github.com/thedarkking01/TouchGrass-AI&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/thedarkking01" rel="noopener noreferrer"&gt;
        thedarkking01
      &lt;/a&gt; / &lt;a href="https://github.com/thedarkking01/TouchGrass-AI" rel="noopener noreferrer"&gt;
        TouchGrass-AI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      an AI that gives you a small outdoor mission based on your available time, energy, interests, and environment.
    &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;🌱 TouchGrass AI&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;An open-source AI experiment designed to solve an unusual problem: &lt;strong&gt;getting people to stop using AI and go outside.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest" rel="nofollow"&gt;Hacktoberfest Open-Source AI Challenge: Week 1&lt;/a&gt; — Theme: &lt;strong&gt;Touch Grass&lt;/strong&gt; 🌿&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is it?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;TouchGrass AI generates personalized outdoor missions using an open-weight AI model. You tell it how much time you have, your energy level, and what you're into — it gives you a mission and sends you outside.&lt;/p&gt;
&lt;p&gt;The core loop:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;Tell TouchGrass what you have
        ↓
   AI creates a mission
        ↓
    Go outside
        ↓
  Come back &amp;amp; reflect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The goal is for the screen to be the &lt;strong&gt;shortest&lt;/strong&gt; part of the experience.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo&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;Step&lt;/th&gt;
&lt;th&gt;Screen&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Pick your preferences&lt;/td&gt;
&lt;td&gt;Time · Energy · Interest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Get your AI mission&lt;/td&gt;
&lt;td&gt;Title · Description · 3 tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Go outside&lt;/td&gt;
&lt;td&gt;Timer screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Come back &amp;amp; reflect&lt;/td&gt;
&lt;td&gt;Journal your adventure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack&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;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&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/thedarkking01/TouchGrass-AI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: React + Vite — 4 screens, no router, minimal state&lt;/li&gt;
&lt;li&gt;Backend: FastAPI (Python) — one POST endpoint &lt;code&gt;/generate-mission&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AI: Gemma via Google AI Studio (free tier)&lt;/li&gt;
&lt;li&gt;Model: &lt;code&gt;gemini-3.8-flash&lt;/code&gt; (Gemma family, open-weight)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI prompt is the core of the project — a structured prompt that tells the model exactly what JSON format to return:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
PROMPT_TEMPLATE = """
You are TouchGrass AI. Your only job is to get people off their screens and outside.

Generate a personalized outdoor mission for someone with these preferences:
- Available time: {time}
- Energy level: {energy}
- Interest: {interest}

Respond ONLY with a valid JSON object in this exact format:
{
  "title": "short catchy mission name",
  "description": "one sentence setting the scene",
  "tasks": ["task 1", "task 2", "task 3"]
}
"""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Stop Copy-Pasting Fixes: I Built DebugCoach for a Friend Learning to Code</title>
      <dc:creator>thedarkking01</dc:creator>
      <pubDate>Sun, 04 Oct 2026 16:52:12 +0000</pubDate>
      <link>https://dev.to/thedarkking01/stop-copy-pasting-fixes-i-built-debugcoach-for-a-friend-learning-to-code-51li</link>
      <guid>https://dev.to/thedarkking01/stop-copy-pasting-fixes-i-built-debugcoach-for-a-friend-learning-to-code-51li</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;My friend has been learning to code for about six months. Whenever he hit an error, he would paste it into an AI chatbot, copy the corrected code, and move on.&lt;/p&gt;

&lt;p&gt;The problem: the code was fixed, but he wasn't always learning how to debug it himself.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;DebugCoach&lt;/strong&gt;, an AI debugging tutor that &lt;em&gt;teaches&lt;/em&gt; instead of immediately giving away the answer.&lt;/p&gt;

&lt;p&gt;DebugCoach takes a user's code and error message and guides them through a progressive hint system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR
  ↓
HINT 1
  ↓
THINK
  ↓
HINT 2
  ↓
THINK
  ↓
HINT 3
  ↓
TRY
  ↓
SOLUTION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first hint is conceptual and spoiler-free. Each additional hint gets more specific. Only after the full hint progression does DebugCoach reveal the complete solution, explain the mistake, identify the underlying concept, and provide a practice question.&lt;/p&gt;

&lt;p&gt;For example, take this off-by-one error:&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;Instead of immediately fixing &lt;code&gt;i + 1&lt;/code&gt;, DebugCoach progressively guides the learner toward realizing that index &lt;code&gt;3&lt;/code&gt; doesn't exist.&lt;/p&gt;

&lt;p&gt;I built this specifically for my friend because I wanted to solve a real problem I had watched him experience: using AI to fix bugs without understanding why they happened.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;



&lt;p&gt;🎥 &lt;strong&gt;Demo:&lt;/strong&gt; [&lt;a href="https://youtu.be/VWFA8CnQMMQ" rel="noopener noreferrer"&gt;https://youtu.be/VWFA8CnQMMQ&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;The demo shows the complete DebugCoach experience, from submitting broken code to receiving progressive hints and finally seeing the solution.&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/thedarkking01" rel="noopener noreferrer"&gt;
        thedarkking01
      &lt;/a&gt; / &lt;a href="https://github.com/thedarkking01/DebugCoach" rel="noopener noreferrer"&gt;
        DebugCoach
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;🐛 DebugCoach&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;An AI debugging tutor that helps you fix your code — without immediately giving you the answer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most AI tools hand you the solution the moment you paste an error. DebugCoach doesn't. It guides you through &lt;strong&gt;progressive hints&lt;/strong&gt; so you actually understand what went wrong.&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;Paste Code + Error
       ↓
   💡 Hint 1  →  think
       ↓
   💡 Hint 2  →  think harder
       ↓
   💡 Hint 3  →  almost there
       ↓
   🎓 Solution + Explanation + Practice Question
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01" rel="nofollow"&gt;Hacktoberfest Weekend Challenge 2026&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack&lt;/h2&gt;
&lt;/div&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;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Layer&lt;/th&gt;

&lt;th&gt;Technology&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Frontend&lt;/td&gt;

&lt;td&gt;React 19, Vite&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Backend&lt;/td&gt;

&lt;td&gt;Python, FastAPI, Pydantic&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;AI&lt;/td&gt;

&lt;td&gt;Open-weight model (Llama 3 / Mistral via Groq)&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Dev tooling&lt;/td&gt;

&lt;td&gt;Amazon Q Developer&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;&lt;br&gt;
&lt;p&gt;&lt;/p&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Structure&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;DebugCoach/
├── backend/
│   ├── main.py          # FastAPI app, CORS, /analyze endpoint
│   ├── ai_service.py    # Model calls, JSON parsing
│   ├── prompts.py       # Hint level prompts + solution prompt
│   ├── schemas.py       # Pydantic&lt;/code&gt;&lt;/pre&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/thedarkking01/DebugCoach" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The repository contains the complete React frontend and FastAPI backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DebugCoach/
├── backend/
│   ├── main.py
│   ├── ai_service.py
│   ├── prompts.py
│   ├── schemas.py
│   └── requirements.txt
│
└── frontend/
    └── src/
        ├── components/
        │   ├── HintCard.jsx
        │   ├── SolutionCard.jsx
        │   └── ProgressBar.jsx
        ├── App.jsx
        ├── api.js
        └── App.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;DebugCoach is built around an open-weight model, &lt;strong&gt;Qwen 3, served through Groq&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React 19 + Vite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Python + FastAPI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; Pydantic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Qwen 3 (open-weight) via Groq&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding agent:&lt;/strong&gt; Amazon Q Developer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core AI integration lives in &lt;code&gt;backend/ai_service.py&lt;/code&gt;. The hint engine uses a different prompt depending on the hint level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hint 1 (Conceptual):&lt;/strong&gt; Explains the general concept without giving away the answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hint 2 (More Specific):&lt;/strong&gt; Can reference variables, loops, boundaries, or other relevant parts of the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hint 3 (Almost the Answer):&lt;/strong&gt; Points toward the exact expression or line causing the problem without giving the corrected code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Solution:&lt;/strong&gt; The user can then reveal the complete solution, including the underlying concept, what went wrong, corrected code, an explanation, and a practice question.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model returns structured JSON so the React frontend can reliably decide whether to show another hint or the final solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Think about the largest valid index."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What happens when i reaches the last position?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"concept"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Off-by-one error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hint_level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_final"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The architecture is intentionally simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React
  ↓
FastAPI
  ↓
Hint Engine
  ↓
Qwen 3
  ↓
Structured debugging response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also used Amazon Q Developer during development to help scaffold the FastAPI backend, build React components, work with Pydantic schemas, and debug issues such as CORS and model-response parsing.&lt;/p&gt;

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

&lt;p&gt;I chose an open-weight model because it powers the core tutoring experience. Here is what that makes possible that a closed API wouldn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Privacy
&lt;/h3&gt;

&lt;p&gt;Users paste source code into DebugCoach. That code could come from a personal project, a university assignment, or other work they don't want to send to a proprietary AI system.&lt;/p&gt;

&lt;p&gt;Because the model is open-weight, DebugCoach can be adapted to run locally with a tool such as Ollama, so the entire AI experience can run on the user's own machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React
  ↓
FastAPI
  ↓
Local inference
  ↓
Open-weight model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user's code can stay on their computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Model Is Swappable
&lt;/h3&gt;

&lt;p&gt;I isolated the AI integration inside &lt;code&gt;ai_service.py&lt;/code&gt;. The frontend, API, schemas, and hint engine don't need to know which model is being used.&lt;/p&gt;

&lt;p&gt;That means I can experiment with different open-weight models without rebuilding the application, and the project isn't tied to a single proprietary provider.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Model Can Be Customized
&lt;/h3&gt;

&lt;p&gt;Because the model is open-weight, there's room for future experimentation. A future version of DebugCoach could be tuned specifically for beginner programmers and debugging pedagogy, getting better at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Giving progressive hints&lt;/li&gt;
&lt;li&gt;Explaining common programming mistakes&lt;/li&gt;
&lt;li&gt;Teaching debugging concepts&lt;/li&gt;
&lt;li&gt;Adjusting explanations for beginners&lt;/li&gt;
&lt;li&gt;Supporting additional programming languages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model isn't just an API I consume. It's something I can experiment with, replace, run locally, and potentially customize.&lt;/p&gt;

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

&lt;p&gt;Here's what a DebugCoach session looks like for the off-by-one example. This is an illustrative walkthrough of how the hint flow plays out:&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;Error:&lt;/strong&gt; &lt;code&gt;IndexError: list index out of range&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint 1 (Conceptual):&lt;/strong&gt; Think about the largest valid index in a list. How does counting positions in a list start?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think:&lt;/strong&gt; The learner pauses and tries to work out what the valid indexes are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint 2 (More Specific):&lt;/strong&gt; Look at your loop. What is the last value &lt;code&gt;i&lt;/code&gt; takes, and what does &lt;code&gt;i + 1&lt;/code&gt; become at that point?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think:&lt;/strong&gt; The learner traces the loop by hand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint 3 (Almost the Answer):&lt;/strong&gt; The problem is in the expression inside &lt;code&gt;print()&lt;/code&gt;. At the final iteration, it asks for an index that doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try:&lt;/strong&gt; The learner attempts the fix on their own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; DebugCoach reveals the corrected code, explains why &lt;code&gt;numbers[3]&lt;/code&gt; fails on a 3-item list, names the concept (&lt;em&gt;off-by-one error&lt;/em&gt;), and gives a practice question to reinforce it.&lt;/p&gt;

&lt;p&gt;The goal is that the learner finds the bug themselves, with the answer as a last step rather than the first.&lt;/p&gt;

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