sloth 用 Gemma 4 在本機夜間整理下載資料夾
My Laptop Is Too Slow to Chat With an AI, So I Gave It the Night Shift
作者開發約 200 行 Python 工具 sloth,透過 Ollama 在本機使用 Gemma 4 夜間閲讀並整理下載資料夾中的文件和圖片,並產生整理報告。
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
My Downloads folder is where files go to be forgotten. invoice (3).pdf. Screenshot 2026-10-12 141502.png. Document1.docx, which could be anything. Every few months I promise myself I'll clean it up, and every few months I don't.
So I built sloth, about 200 lines of Python that do it while I sleep. Every night it goes through my Downloads folder with Gemma 4 running on my laptop. It reads each document, looks at each image, gives the file a name a human would pick, and moves it into a folder. In the morning, a report is waiting:
invoice (3).pdf -> Finance/2026-10-01_acme_cloud_services_invoice.pdf
Document1.docx -> Work/2026-10-01_sprint_meeting_notes_prakhar_meera_jonas.docx
Screenshot 2026-10-12 141502.png -> Screenshots/2026-10-01_error_message_screenshot_python_app.png
export (1).csv -> Finance/2026-10-01_salary_and_transaction_report.csv
VSCodeUserSetup-x64-1.105.1.exe -> Installers/VSCodeUserSetup-x64-1.105.1.exe
scan0001.pdf -> left alone (Gemma wasn't sure)
If I don't like what it did, python sloth.py undo ~/Downloads puts everything back.
Anyone with a Downloads folder gets to be a little lazier, which is everyone. It's especially for people whose laptop, like mine, has no business running AI.
Here's a real run on my test folder. Read the timings, because they're the point:
$ python sloth.py tidy ~/sloth-test
[1/13] 2409.11873v2.pdf -> Reading/2026-10-01_quantization_aware_training_paper.pdf (14s)
[2/13] data.bin -> left alone, unknown type
[3/13] Document1.docx -> Work/2026-10-01_sprint_meeting_notes_prakhar_meera_jonas.docx (13s)
[4/13] e-ticket.pdf -> Personal/2026-10-01_train_ticket_booking_confirmation.pdf (11s)
[5/13] export (1).csv -> Finance/2026-10-01_salary_and_transaction_report.csv (15s)
[6/13] image (2).png -> Images/2026-10-01_quarterly_revenue_by_region_report.png (21s)
[7/13] invoice (3).pdf -> Finance/2026-10-01_acme_cloud_services_invoice.pdf (11s)
[8/13] notes.txt -> Personal/2026-10-01_banana_bread_recipe_personal.txt (11s)
[9/13] photos_backup.zip -> Archives/photos_backup.zip (0s)
[10/13] resume_final2.docx -> Personal/2026-10-01_resume_final_dok_prakhar_a.docx (11s)
[11/13] scan0001.pdf -> left alone, not sure (9s)
[12/13] Screenshot 2026-10-12 141502.png -> Screenshots/2026-10-01_error_message_screenshot_python_app.png (19s)
[13/13] VSCodeUserSetup-x64-1.105.1.exe -> Installers/VSCodeUserSetup-x64-1.105.1.exe (0s)
The folder actually held 15 files. The other two are skipped on purpose: a boarding pass I'd downloaded that day (I might still need it) and a half-finished Ubuntu download.
Code
sloth
Tidies your Downloads folder overnight with a local Gemma model, so you don't have to.
While you sleep, sloth reads each file (or looks at it, for images), gives it a real name, and files it into a folder. In the morning there's a SLOTH_REPORT.md waiting for you, and one command puts everything back if you don't like it.
invoice (3).pdf -> Finance/2026-10-01_acme_cloud_services_invoice.pdf
Screenshot 2026-10-12 141502.png -> Screenshots/2026-10-01_error_message_screenshot_python_app.png
notes.txt -> Personal/2026-10-01_banana_bread_recipe_personal.txt
VSCodeUserSetup-x64-1.105.1.exe -> Installers/VSCodeUserSetup-x64-1.105.1.exe
scan0001.pdf -> left alone (Gemma wasn't sure)
Everything runs on your machine through Ollama. No file, filename, or snippet ever leaves it.
Setup
You need Ollama and Python 3.9+.
ollama pull gemma4:e2b-it-qat pip install -r requirements.txt
Use
python sloth.py tidy ~/Downloads --dry-run # show the plan, move nothing python sloth.py tidy ~/Downloads # do it python sloth.py undo ~/Downloads # put the last run back
Run it every night
Windows (PowerShell)…
How I Built It
The constraint. My laptop has an Intel Core i3-1215U, 8 GB of RAM and no graphics card. While I was testing, Windows had about 1 GB of memory free. Chatting with a model on this machine would be miserable: you type a question and go make tea.
But tidying files isn't a chat. Nobody is waiting for an answer at 2 a.m. That's the whole project: slow inference is fine when nobody's waiting for it.
The model. Gemma 4 E2B (gemma4:e2b-it-qat), served by Ollama. It's the smallest Gemma 4, a 4.3 GB download. The QAT build was trained to keep its quality after being squeezed down to 4 bits, which is what lets it fit in 8 GB. It can also see, so a screenshot gets named after what's in it, not after when I took it.
The pipeline, in the order the script runs it:
-
Skip what I might still need. Anything modified in the last 24 hours stays put, and so does any
.crdownloador.partfile. - Don't think unless you have to. Installers, archives, audio and video are sorted by extension and keep their names. The model is never called for them. A sloth saves its energy.
-
Read a little. The first two pages of a PDF (via pypdf), the text inside a
.docx(which is just a zip of XML), the first 1,500 characters of a text file, or the whole image. - Hand Gemma a form, not a blank page. Ollama can force the reply to match a JSON schema, and the category field is an enum of eight folders. A 4.6B-parameter model can't invent a "Misc Stuff 2" folder, because the schema won't let it.
-
Never trust a model with a date. The
2026-10-01_prefix comes from the file's timestamp. Gemma only supplies the words. -
Write down every move as it happens. If the laptop dies at 3 a.m.,
undostill knows what went where.
The heart of it is a single HTTP request to Ollama:
body = {
"model": "gemma4:e2b-it-qat",
"messages": [message], # prompt, plus the image as base64 if it's a picture
"format": SCHEMA, # category must be one of 8 folders
"think": False,
"stream": False,
"options": {"temperature": 0, "num_ctx": 4096},
}
It uses no framework and no SDK, just the Python standard library plus pypdf.
The one line that made it 7 to 30 times faster. When I ran ollama show on the model, it told me something I didn't expect: Gemma 4 has a thinking mode, and it's on by default. I timed the same three files both ways:
| File | Thinking off | Thinking on | Tokens generated (off / on) |
|---|---|---|---|
invoice (3).pdf |
8.7 s | 59.8 s | 31 / 533 |
export (1).csv |
4.3 s | 60.4 s | 32 / 535 |
| Screenshot of a Python error | 2.7 s | 91.7 s | 23 / 667 |
It picked the same folder every time, and the same name for two of the three. On a CPU, 500 tokens of deliberating over whether an invoice is an invoice costs a full minute per file. So "think": False it is. Even a sloth has limits. (These timings come from a separate test. In full runs, with Windows fighting for memory, it takes 8 to 26 seconds per document and more than a minute for a large photo.)
The bug was in my test, not my code. My first prompt gave Gemma two example names: acme_cloud_invoice and python_import_error. The first run looked perfect. Then I noticed that my test folder contained an Acme Cloud invoice and a screenshot of a Python import error. I'd been grading the model on how well it could copy my examples. I swapped them for examples that match nothing in the folder (dentist_appointment_reminder, github_actions_failed_build). It still put every file in a sensible folder, so it really was reading them. Lesson learned: if your examples look like your test data, your test isn't testing anything.
What it still gets wrong. Some names are clumsy. banana_bread_recipe_personal repeats its own folder, and my résumé came out as resume_final_dok_prakhar_a (I have no idea what "dok" means). A scanned PDF with no text layer gets left alone, because all Gemma can see is the filename. That's the right call, but a smarter version would turn the page into an image and let Gemma look at it.
Why Does Open Innovation Matter?
Look at what's in a Downloads folder. My little test folder alone had a bank export showing a salary, a résumé, a train ticket with a booking number, and an invoice. My real one is worse.
A version of this tool built on a closed API would only work by uploading all of that, every night, to a server I don't control. I wasn't going to make that trade to save ten minutes of dragging files around. With Gemma running in Ollama, no file, filename or snippet ever leaves the laptop. I can turn the Wi-Fi off and it still works.
Then there's cost. It runs every night, on as many files as I've downloaded, for nothing. There's no API key, no rate limit, and no surprise bill if a bug makes it loop.
And there's control, three kinds of it:
- I picked a model that fits my machine. I chose the size (E2B) and the quantization (4-bit QAT) specifically so it would fit in 8 GB of RAM.
- I can swap it. The model is one constant at the top of the file. When a better small model comes out, upgrading is a one-line change.
-
I can share it.
ollama showlists Gemma 4's license as Apache 2.0, so anyone can run sloth without signing up for anything.
Where open beat closed. A hosted frontier model would be faster per file, and it would probably come up with better names. But speed is the one thing this job doesn't need. At 2 a.m., one second per file and fifteen seconds per file both mean "done before I wake up." Once speed stopped mattering, everything that was left (privacy, cost, working offline, no account) pointed to the model on my own laptop.
My Agent Session
TODO: save the session with DevRelay and embed it here, or delete this section.
The Lazy Payoff
Test folders are polite. So I pointed sloth at my real Downloads folder, with --dry-run so it planned everything and moved nothing.
- 72 files were old enough to touch, going back to February.
- 36 would have been filed. Gemma read 31 of them and gave each a name, and 5 were sorted by extension alone.
- 3 were left alone because Gemma wasn't sure what they were. That's exactly what I want it to do when it can't tell.
-
33 were left alone because sloth can't read them yet: 25 Excel files, 6 PowerPoints, an old
.docand an.mpeg. Spreadsheets turned out to be the biggest kind of clutter in my real folder, and my test folder had none. That's the most useful thing the run taught me, and reading.xlsxand.pptxis next on the list. (Two of those "Excel files" were really Office lock files,~$…. Sloth skips those now, and.mpegnow goes toMedia.)
The whole folder took 11.5 minutes on the i3, with no GPU. Documents took 8 to 26 seconds each. The two images took 70 and 106 seconds, because big pictures are slow on a CPU. It's a lot of minutes, and I was asleep for all of them.
The best result was an ebook whose filename was a website prefix followed by six ISBNs. It came out as the_art_of_thinking_clearly_ebook. It also found two receipts and sent both to Finance, and it spotted two editions of the same book, filed under filenames that looked nothing alike, and gave them both the same clean title.
It made mistakes too. Two versions of the same report got identical names, so the only way to tell _v2 apart is the date prefix. El Niño became el_ni_o, because my filename cleaner threw away accented letters (my bug, not Gemma's, and it's fixed now). A WhatsApp photo got a name that just repeated its old filename. And it would have filed my coding agent's instruction file, CLAUDE.md, under Reading. To be fair, that's technically correct.
Opening 34 documents one at a time to work out what they are is exactly the chore I'd been putting off since February. Sloth did it in 11 minutes while I did nothing at all.
Prize Categories
-
Best Use of Gemma: Gemma 4 E2B runs locally through Ollama and does all of the reading. It reads documents, looks at screenshots, and decides each file's name and folder. Vision is what turns
Screenshot 2026-10-12 141502.pngintoerror_message_screenshot_python_app.png.
來源:DEV Community · dev.to