Quiet Pair: let an open model find repetitions, and keep the decision
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady.
What I Built
Quiet Pair finds similar English sentences in a small CSV and puts them into a review queue. It is for the tedious moment when a text column contains the same request written several ways, but deleting a near-match could erase an important difference.
An open sentence model does the searching. The reviewer chooses Same meaning, Different, or Not sure, with undo available. There is no delete button and no automatic merge. If A resembles B and B resembles C, the app does not conclude that A equals C.
The deliberate laziness is avoiding the search through every possible pair. The deliberate slowness is reading before deciding. The output is a decision audit; the original CSV stays intact.
Demo
Try Quiet Pair in your browser.
Choose Try a synthetic example, then Find similar pairs. The first run downloads the model. Read both sentences, make a decision, and download the audit before closing the tab.
!A cancellation request and its negation receive a similarity score of 0.895. The reviewer can mark them Different.
That screenshot captures the most useful result from testing: “I want to cancel my subscription” and “Do not cancel my subscription” ranked highest. A confident-looking similarity score must not become an irreversible action.
Code
Source code, synthetic fixtures and tests, with the original application under the MIT License.
How I Built It
The core is all-MiniLM-L6-v2, an Apache-2.0 open sentence model, running through Transformers.js 3.8.1 and ONNX Runtime Web. A worker loads pinned q8 weights and performs WebAssembly inference. Mean-pooled, normalized embeddings produce cosine scores; a separate review journal records individual decisions.
The model is essential: exact string matching would miss paraphrases. It is also fallible. Scores rank candidates rather than certify duplicates, and the similarity floor only filters what appears in the queue. Lowering it reveals more pairs without silently judging the rest.
The exported audit includes original texts, row numbers, verdicts, scores, a model revision and a source-text fingerprint. Formula-like cells receive a protective prefix for spreadsheet export. English matching, 150 rows and short cells keep the scope small; even these cells can exceed the model's token limit.
Six Node tests passed for parsing, ranking, independent decisions, undo, export and source preservation. An automated UI check in the Codex in-app browser on Windows also ran the real model and exercised all decisions, undo and a four-row audit download. Twelve synthetic rows produced 66 pairs and four candidates at a 0.72 floor. The UI reported 1.68 seconds initialization and 0.25 seconds for embeddings in that single run. Cache state and hardware were not measured, so this is no cold-load benchmark, human user study or accuracy evaluation.
Why Does Open Innovation Matter?
Open weights let the application run inference in the user's browser without an inference account, API key or per-request inference bill. A pinned model revision and readable scoring code also make the source of each suggestion inspectable. The audit records which model produced it, rather than hiding that choice behind a changing service.
The application has no CSV upload endpoint. It does download model and runtime files from Hugging Face and jsDelivr, whose suppliers receive normal connection metadata. Those dependencies remain trusted software, and initial network access is required. Offline reloading has not been verified; synthetic or non-sensitive input is appropriate while evaluating this preview.
The useful saving is attention spent finding candidates. How much time it saves in real work is still unmeasured. For now, the design goal is concrete: let an open model do the repetitive search, while keeping the final decision visible and reversible.
I built a background remover that never sees your photo (and it does GIFs and videos too)!
When you’re the only engineer in the family, you automatically become the unpaid IT department, video producer, and resident graphic designer, because to relatives, "computers" is just one big subject (and that includes everything to do with mobile phones too... somehow!). So whenever someone needed a transparent PNG or a quick cutout, it fell on me, and I’d get stuck in the same annoying loop. I'd hunt down a "free" background remover (whatever showed up first on Google), upload the photo, wait, and then get held hostage by a "Buy Credits" button. My only options were settling for a blurry, postage-stamp-sized preview, or making a whole new account if I was desperate enough for the high-res version. Worse, somewhere in that mess, a family photo would get shipped off to a sketchy server I know nothing about.
For a product shot, that's annoying. For a passport photo, a signature, or a client's photo, it's a bit more than annoying.
So I added a background remover to Fizzdoc, my open-source toolkit where every tool runs inside the browser tab. It now does:
- Photos: Remove Background, saved at the photo's own resolution as PNG, JPG or WebP.
- Animated GIFs: Remove GIF Background, every frame, same timing, same loop.
- Videos: Remove Video Background, every frame, with the sound kept.
- WhatsApp stickers: WhatsApp Sticker Maker, a 512 × 512 WebP with a white outline, kept under 100 KB, with words in fun fonts and emoji you drag into place.
You can keep the background clear, or put white, any colour, a blur or another photo behind. It's free, there's no sign-up, no watermark, and no limit on how many photos you do. The size limit comes from your device's memory, not from me.
And the photo never leaves your device. Not "we delete it after an hour". It just never goes anywhere.
Below is how it works, and what broke along the way.
The rule: nothing gets uploaded, and you can check
!The Remove Background page. The badge under the title says what happens to your photo: 0 bytes uploaded.
Fizzdoc is a static site on Cloudflare Pages. There's no backend, so there's nothing that could receive a file. The page also ships a Content Security Policy with connect-src 'self', which means the browser itself blocks the page from talking to any other website.
That rule shaped everything below. No CDN for the model, no hosted inference API, no "just this one request". Open DevTools, go to the Network tab, remove the background, and you'll see the model files coming from fizzdoc.com and nothing going out.
Picking a model
I wanted three things:
1. Good edges on hair and fur, because that's where background removers usually show their seams.
2. Small enough to download once into a browser.
3. A licence that lets anyone use the result, including for work.
I went with BiRefNet (MIT licence), the lite variant, using the 512 × 512 ONNX export by studioludens. I store its big weight tensors as 16-bit floats and cast them back to 32-bit when the model loads, which halves the download to about 100 MB without changing the maths it runs.
For phones there's a second model, U²-Net small (Apache-2.0), just 4.6 MB. I learned this one the hard way: someone sent me a screenshot of an early version on a 6 GB Android phone, where Chrome killed the tab at 5% ("Aw, Snap!"). A browser tab on a phone gets far less memory than the phone has, and when it runs out there's no error to catch, the tab just dies. So now phones always use the small model, and the page says so ("for the cleanest edges on hair and fur, use a laptop"). If the big model ever crashes a tab on a laptop too, the page remembers it for 30 days and uses the small one there.
And for laptops with a graphics chip there's the opposite: a Sharper edges (hair, fur) button. It reruns the photo through a 1024 × 1024 export of the same BiRefNet-lite model (onnx-community, MIT). It's a one-time 135 MB download and needs WebGPU, so it's never offered on phones. If the device can't manage it, you keep the result you already had.
Running it: WebGPU when it can, CPU when it can't
The model runs with ONNX Runtime Web inside a Web Worker, so the page never freezes.
- If the device has a graphics chip with WebGPU, the model runs there. This is the fast path.
- If WebGPU isn't there (or the driver says no), the same model runs on the CPU through WebAssembly.
- If that fails too, usually because the device ran out of memory, the small U²-Net model takes over.
So the chain is GPU, then the same model on CPU, then the small model. Nobody gets an error just because their laptop is old.
Two fun problems with "self-host everything"
Cloudflare Pages has a 25 MiB limit per file. The model is about 100 MB and ONNX Runtime's WebGPU build is a 27 MB .wasm. So both live on the server as 20 MiB parts: the models are split by a small script when I add them, and the runtime is split at build time. The worker downloads the parts, joins them, and keeps the result in the browser's Cache Storage, so the next time it starts straight from there, even with the internet off. The build also fails if any file it writes goes over 25 MiB, after one deploy failed on it.
A runtime that exists in pieces. ONNX Runtime normally fetches its .wasm as one file. Mine exists just as parts on the server, so the worker joins them from Cache Storage and hands the bytes to the runtime directly with ort.env.wasm.wasmBinary. It needs no extra hosting and no change to the security policy.
The part I'm proudest of: full resolution from a 512 px model
!Top: the page loading the model once, and the options panel. Bottom: the original photo, the cut-out, and a new background in one tap.
The model looks at your photo squeezed to 512 × 512 and returns a soft mask. If you stretch that mask back over a 4000 × 3000 photo, the edges look like they were cut with a butter knife.
So the mask goes through two classic image-processing filters, both plain arithmetic on typed arrays in the worker:
1. Fast guided filter (He and Sun, 2015). It uses the photo itself as a guide to snap the blurry mask onto the real edges, so hair follows the actual strands. The fit is computed on a smaller copy (up to 1280 px) and then applied to every pixel of the full photo in one pass.
2. Blur-fusion foreground estimation (Forte, 2021). Edge pixels are a mix of your subject and the old background. Put a cut-out on a new colour without fixing that, and you get a faint halo of the old background. This step estimates the subject's true colour at the edges, so the new background looks like it was always there.
By default the result is saved at your photo's own size: your own pixels, with a cleaner mask.
When the AI gets it almost right
It's an AI model, so a busy background or a subject that blends into it can confuse it. For photos there's a small set of touch-ups:
- Erase / Restore brush, with Undo, Redo and Zoom for careful work on a phone.
- Tap to remove and Tap to keep: one tap picks the whole connected area of a similar colour and removes it, or brings it back.
- Shadow and a white Outline, if you want the cut-out to stand out.
- Crop: the whole photo, fit to the subject, or a square around the subject for online shop listings.
- Hold to see the original, to compare before and after.
GIFs: every frame, same rhythm
Animated GIFs are sneaky. Many frames aren't full pictures, just small patches drawn over the previous frame, with rules ("disposal methods") about what to clear afterwards.
- gifuct-js (MIT) decodes the frames, and Fizzdoc composes each one into a full picture the way a browser would show it.
- Each frame goes through the same model (in a faster mode, since there can be dozens).
- gifenc (MIT) writes the new GIF, keeping every frame's delay and the loop.
One catch: a GIF pixel is either fully see-through or fully solid. So on a clear background the edges are a little sharper than in a PNG. Pick a colour or a photo behind and the soft edges are back.
Videos: every frame, sound kept
!Remove Video Background: every frame gets a new background, and the sound is kept.
For video, Mediabunny (MPL-2.0) reads the file and the browser's own WebCodecs encoder writes the new one. Every frame goes through the model and gets its new background, and the soundtrack is carried over.
The output is MP4 (H.264) if the browser can handle it; otherwise, it's WebM (VP9). Before you start, the page shows a preview frame and an estimate of how long the whole clip will take on that device.
What does "no background" mean for a video? Truly see-through video would need the encoder library to start helper workers from blob: URLs, which my page's security policy blocks, and most players can't show it anyway. So "None" gives you a green screen, which any video editor removes in one click. I chose to keep the policy strict rather than loosen it for one feature.
Stickers: words, emoji, and the last step in WhatsApp
!The WhatsApp Sticker Maker turns any photo into a 512 × 512 sticker with a white outline, under 100 KB.
The WhatsApp Sticker Maker starts from the same cut-out. It squares it to 512 × 512, adds a white outline, and keeps the WebP under 100 KB by lowering the quality step by step until it fits.
On top of that, you can add words in five styles (Funny, Cute, Cozy, BIG, and Serious) and emojis. Each one is a layer you drag, pinch, resize and rotate, on a phone or with a mouse. The fonts are self-hosted like everything else: Bangers, Kalam, Teko and Inter, with Baloo 2 covering Hindi letters. Emoji are drawn with your device's own emoji font.
One fun bug on the way: Vite inlines small files as data: URLs, and a few of the font files were small enough. My own CSP (default-src 'self') refused them, and the end-to-end test that fails on any CSP violation caught it before it shipped. Fonts are now always separate files.
One limit, though. A web page can't add a sticker to WhatsApp, and a sticker shared from the browser arrives as a normal photo. So instead of a "Share to WhatsApp" button that doesn't do what it says, the page shows WhatsApp's own steps: save the sticker, then in any chat tap Stickers › Create and pick it. On iPhone there's a "Save to Photos" button, because downloads go to Files and WhatsApp picks stickers from Photos.
What it's like on low-end phones
!The same tool on a phone, in dark mode. Phones use the small 4.6 MB model so the tab doesn't crash.
I care about this a lot because many people open Fizzdoc on Android phones.
- Phones always get the small model, so it works rather than crashes. Edges are a bit softer than on a laptop, which is a trade I'll take every time.
- The worker keeps the page responsive while it thinks.
- The model downloads once (the page shows the progress in MB). After that it starts right away, and it keeps working with Wi-Fi and mobile data off, which is also the easiest way to check that nothing is uploaded.
- Videos give you a time estimate first: short clips are fine, long ones are a laptop job.
Things it doesn't do (yet)
- Truly transparent video (see above, green screen instead).
- Many photos in one go: the background remover takes one photo at a time.
- Several photos in one sticker. That's next.
Credits
None of this would exist without these people and projects. Thank you:
| Project | What it does in Fizzdoc | Licence |
|---|---|---|
| BiRefNet by Peng Zheng and co-authors | The background model | MIT |
| birefnet-lite-512 by studioludens | The 512 px ONNX export | MIT |
| BiRefNet_lite-ONNX by onnx-community | The 1024 px export for Sharper edges | MIT |
| U²-Net by Xuebin Qin and co-authors | The small model for phones | Apache-2.0 |
| ONNX Runtime Web by Microsoft | Runs the models on WebGPU or WebAssembly | MIT |
| gifuct-js by Matt Way | Reads animated GIFs | MIT |
| gifenc by Matt DesLauriers | Writes animated GIFs | MIT |
| Mediabunny by Vanilagy | Reads and writes videos | MPL-2.0 |
| Kaiming He and Jian Sun | The (fast) guided filter | Paper |
| Marco Forte | Blur-fusion foreground estimation | Paper |
The full licence texts are in Fizzdoc's third-party licences.
Try it, break it, tell me
- Photo: fizzdoc.com
- GIF: fizzdoc.com
- Video: fizzdoc.com
- WhatsApp sticker: fizzdoc.com
- Code (Apache-2.0): kingrishabdugar/fizzdoc
It's part of a bigger toolkit of 68 free tools (PDF, Word, Excel, PowerPoint, images and audio), all running in your browser, in 16 languages. If something looks off on your device, there's a "Report it" link on every tool. And if you like it, a star on GitHub genuinely makes my day.
Followup Desk: local AI for a more careful customer follow-up
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle.
What I Built
A furniture customer leaves a note about a sofa, a narrow doorway, and a delivery date. Another customer is comparing prices. A third has asked not to be contacted. By the next shift, a salesperson has to reconstruct what each person needed and which promises still need an answer.
Followup Desk is a local-first workspace for that small, specific problem. It connects a reception record to a human-confirmed follow-up plan, a dated action queue, and an outcome timeline. Its experimental AI helps the associate review some passages about fit, delivery, price comparison, service, and comfort before choosing a next step.
The potential buyer is an independent furniture or appliance retailer that wants a lightweight preparation tool for its associates. A paid version would have to earn its place by reducing the time spent reconstructing a conversation and preventing forgotten commitments. That is a product hypothesis, not a validated business result: this beta has no paying customers, sales-lift study, or production deployment with real customer data.
The current release is a fictional-data prototype. Its useful unit is one reviewable next action for one customer.
Demo
Try the English Followup Desk beta.
Start with the six fictional records. Manual planning works immediately. The optional AI requires an explicit download click: approximately 87 MB of model weights plus about 27 MB of runtime and other assets on the tested setup. Download size and first-run time matter for this audience, so they are disclosed before enabling it.
A short walkthrough:
1. Open Sam Rivera's record and review the original reception note alongside confirmed facts.
2. Enable local AI and inspect the quoted passage supporting the price-comparison preparation cue. The wording of the question and strategy is a fixed template.
3. Confirm that the cue is still relevant before adopting the strategy. Then review the date, permitted channel, preparation checklist, and draft in a separate plan confirmation.
4. Record an outcome or reschedule the task. The next action changes without accumulating duplicate reminders, and the timeline retains the outcome.
5. Open Taylor Chen's record. The no-contact instruction blocks the AI action and customer-contact workflow.
Copying a draft only copies it to the clipboard. Nothing is sent. Changing an original fact makes the existing confirmed plan require review again. A no-reply outcome does not lower the customer's stage or create daily retries.
Code
Followup Desk source on GitHub, published under the MIT License.
Read the verification report.
The repository includes the application, tests, model documentation, privacy limitations, and synthetic evaluation evidence. The shipped application source matches the tested beta; public-release documentation explains the verification boundary.
How I Built It
The app uses JavaScript and Vite, with a browser worker for inference. The model is Xenova's ONNX conversion of nli-deberta-v3-xsmall, derived from the Apache-2.0 cross-encoder model. It runs through Transformers.js and ONNX Runtime using browser WASM. The conversion revision and runtime assets are pinned.
The model performs natural-language inference. It compares source sentences with five fixed preparation hypotheses and returns entailment, neutral, and contradiction scores. The app retains the original sentence as evidence. A suggestion needs sentence entailment of at least 0.80, a margin of at least 0.30 over the other labels, and a full-note contradiction score below 0.50. These are exploratory thresholds, not calibrated accuracy guarantees.
This is actual learned-model inference. Questions, suggested strategies, and draft messages come from disclosed, editable templates. The model never sets a budget, date, customer stage, or contact permission. It does not predict purchase readiness, conversion, wealth, or customer value.
What testing changed
Earlier generative experiments fabricated details and handled the required structure unreliably. The shipped approach narrows the AI's job to source-supported preparation cues and leaves factual fields and decisions with the associate.
The final source passed 58 automated tests, including consent and channel gates, date boundaries, changed-record review, backup validation, malicious text handling, and model-output contracts. Mocked contract tests check software behavior; they do not establish model quality.
For actual inference, a frozen 16-note synthetic evaluation produced seven supported suggestions and nine abstentions. Some abstentions were real misses. This small set is not a statistical accuracy estimate. A supplemental four-note retraction test exposed two stale historical cues. Conservative explicit resolution/retraction markers now pause AI, and adopting a strategy requires a current-relevance confirmation. Those safeguards cannot detect every paraphrase, so reviewing the full note remains necessary.
The public app also completed real browser WASM inference. Casey's comfort/material passage and Sam's competitor-price passage produced source-backed cues. Jordan's note abstained because the full-note check vetoed an otherwise strong sentence result. The thresholds were not loosened to manufacture a successful demo. In that one browser environment, these inference calls took approximately 1.2–1.6 seconds; that is an observation, not a cross-device performance promise.
Boundaries of this beta
Records are stored in localStorage in the current browser. They are not encrypted, synchronized, or protected as a production CRM database. Clearing site data can erase them, and JSON backups contain the reception text. Please use fictional or appropriately authorized de-identified test records.
The application has no remote-inference or outbound-messaging API, and the tested inference ran locally. Model/runtime downloads still contact external asset providers. A complete network privacy audit, offline cold-start/cache verification, final browser backup restore, and mobile-width browser QA remain incomplete. The test report calls out these gaps instead of treating unit tests as a substitute.
Why Does Open Innovation Matter?
Open components make the AI behavior inspectable and replaceable. The model revision, label scores, fixed hypotheses, thresholds, and synthetic failures can all be examined. A developer can change the model or decision policy and rerun the same evaluation rather than depending on an opaque hosted response.
Local inference also removes a per-request hosted-model charge. No application remote-inference endpoint is implemented; the tested inference ran locally. A complete network audit remains pending. It still has real costs: a substantial first download, device compute, browser compatibility work, and maintenance. Offline operation has not been established.
For a small retail tool, the trade-off is concrete. A narrow local classifier can support one part of preparing a conversation, while a person reviews the evidence and decides what to do. The current model misses too much to replace that review. Publishing those limitations is part of making the prototype useful to the next person who builds on it.
This write-up was generated by an AI assistant from the project's source and verification records, without human text editing. The project was developed with AI assistance. The demo and evaluation use synthetic customer records.
Mentions
@SparkLLM Testing on small GPU limits turned up a bug in onnxruntime-web: at the default 128 MiB buffer binding limit, common on phones, long one-pass prompts came back as all zeros. No error. I sent the fix and @onnxruntime merged it. Should ship in 1.32. onnxruntime#33760
ONNX Runtime 10月27日的补丁修了编译报错:同时启用 OpenVINO 和 Python 时,旧版可能构建失败。 自己编译它来部署模型的,可以核对这项修复。官方也写明,另一项 WASM 改动只修测试,不改变运行行为;别把补丁当成推理提速。 microsoft/onnxruntime
Unstructured; Supabase: Postgres development platform; yt-dlp | GitHub Curated Picks | 2026-10-23 GitHub Curated Picks reviews 14 source-verified repositories selected for developer usefulness, not popularity position. Each pick is checked against its GitHub repository, README, release evidence, and recent commit; pick numbers are editorial order. The compact card keeps rank, signal, why it matters, and next check together while the ledger preserves direct URLs and release evidence. Treat the list as an educational review surface, not software endorsement, and verify license and maintenance before adoption. Chapters: 00:00 2026-10-23 | GitHub Curated Picks 00:05 Pick #1 Unstructured 00:30 Pick #2 Supabase 00:44 Pick #3 yt-dlp 01:01 Pick #4 Langchain 01:27 Pick #5 Awesome Mac 01:42 Pick #6 Trivy 01:56 Pick #7 Vite 02:14 Pick #8 Jellyfin 02:32 Pick #9 Black 02:51 Pick #10 Coolify 03:13 Pick #11 Doris 03:24 Pick #12 Onnxruntime 03:36 Pick #13 Fluentui 03:49 Pick #14 Server Source ledger: github.com/trending api.github.com github.com/Unstructured-IO/unstructured/blob/main… github.com/Unstructured-IO/unstructured/commit/49… github.com/Unstructured-IO/unstructured/releases/… api.github.com github.com/supabase/supabase/blob/master/README.md github.com/supabase/supabase/commit/2193f2acdf8ef… api.github.com github.com/yt-dlp/yt-dlp/blob/master/README.md github.com/yt-dlp/yt-dlp/commit/9b58cb33d0cd3e823… api.github.com langchain-ai/langchain github.com/langchain-ai/langchain/commit/b84fa61e… github.com/langchain-ai/langchain/releases/tag/la… api.github.com github.com/jaywcjlove/awesome-mac/blob/master/REA… github.com/jaywcjlove/awesome-mac/commit/965f263f… api.github.com github.com/aquasecurity/trivy/blob/main/README.md github.com/aquasecurity/trivy/commit/0231990f702f… api.github.com github.com/vitejs/vite/blob/main/README.md github.com/vitejs/vite/commit/a236886026c3a5de068… api.github.com github.com/jellyfin/jellyfin/blob/master/README.md github.com/jellyfin/jellyfin/releases/tag/v12.3 api.github.com github.com/psf/black/blob/main/README.md github.com/psf/black/commit/f33c3e3c66263d4a3a0e1… api.github.com coollabsio/coolify github.com/coollabsio/coolify/commit/0b2e931a4258… api.github.com github.com/apache/doris/blob/master/README.md github.com/apache/doris/commit/6e5a8929fbaba2ed2a… api.github.com microsoft/onnxruntime github.com/microsoft/onnxruntime/commit/fe7700a7e… api.github.com microsoft/fluentui github.com/microsoft/fluentui/commit/ea1a99bf2bc5… api.github.com nextcloud/server github.com/nextcloud/server/commit/fc9b07d9591f1f… Unstructured-IO/unstructured supabase/supabase yt-dlp/yt-dlp jaywcjlove/awesome-mac aquasecurity/trivy vitejs/vite jellyfin/jellyfin psf/black apache/doris Informational and educational purposes only. Not investment advice, product endorsement, or professional guidance.
Their temp fix also fails to work with xcode cloud, creating new levels of pain but there seems to be a way of making xcode cloud aware of a bash script that can declare the minos version for an ext library. onnxruntime-extensions#977 t.co
This seems like something that should just be patched into the current library version, considering the PR that fixes it is already merged. The xcode run script work around is also not reliable, also it's Microsoft lol. onnxruntime#27396
Quiet Pair: let an open model find repetitions, and keep the decision This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady. What I Built Quiet Pair finds similar English sentences in a small CSV and puts them into a review queue. It is for the tedious moment when a text column contains the same request written several ways, but deleting a near-match could erase an important difference. An open sentence model does the searching. The reviewer chooses Same meaning, Different, or Not sure, with undo available. There is no delete button and no automatic merge. If A resembles B and B resembles C, the app does not conclude that A equals C. The deliberate laziness is avoiding the search through every possible pair. The deliberate slowness is reading before deciding. The output is a decision audit; the original CSV stays intact. Demo Try Quiet Pair in your browser. Choose Try a synthetic example, then Find similar pairs. The first run downloads the model. Read both sentences, make a decision, and download the audit before closing the tab. !A cancellation request and its negation receive a similarity score of 0.895. The reviewer can mark them Different. That screenshot captures the most useful result from testing: “I want to cancel my subscription” and “Do not cancel my subscription” ranked highest. A confident-looking similarity score must not become an irreversible action. Code Source code, synthetic fixtures and tests, with the original application under the MIT License. How I Built It The core is all-MiniLM-L6-v2, an Apache-2.0 open sentence model, running through Transformers.js 3.8.1 and ONNX Runtime Web. A worker loads pinned q8 weights and performs WebAssembly inference. Mean-pooled, normalized embeddings produce cosine scores; a separate review journal records individual decisions. The model is essential: exact string matching would miss paraphrases. It is also fallible. Scores rank candidates rather than certify duplicates, and the similarity floor only filters what appears in the queue. Lowering it reveals more pairs without silently judging the rest. The exported audit includes original texts, row numbers, verdicts, scores, a model revision and a source-text fingerprint. Formula-like cells receive a protective prefix for spreadsheet export. English matching, 150 rows and short cells keep the scope small; even these cells can exceed the model's token limit. Six Node tests passed for parsing, ranking, independent decisions, undo, export and source preservation. An automated UI check in the Codex in-app browser on Windows also ran the real model and exercised all decisions, undo and a four-row audit download. Twelve synthetic rows produced 66 pairs and four candidates at a 0.72 floor. The UI reported 1.68 seconds initialization and 0.25 seconds for embeddings in that single run. Cache state and hardware were not measured, so this is no cold-load benchmark, human user study or accuracy evaluation. Why Does Open Innovation Matter? Open weights let the application run inference in the user's browser without an inference account, API key or per-request inference bill. A pinned model revision and readable scoring code also make the source of each suggestion inspectable. The audit records which model produced it, rather than hiding that choice behind a changing service. The application has no CSV upload endpoint. It does download model and runtime files from Hugging Face and jsDelivr, whose suppliers receive normal connection metadata. Those dependencies remain trusted software, and initial network access is required. Offline reloading has not been verified; synthetic or non-sensitive input is appropriate while evaluating this preview. The useful saving is attention spent finding candidates. How much time it saves in real work is still unmeasured. For now, the design goal is concrete: let an open model do the repetitive search, while keeping the final decision visible and reversible.
reuse-rs: real time speech denoising in plain Rust (no ML interface) reuse-rs runs NVIDIA's Real-time RE-USE speech enhancement model (streaming Mamba) in plain Rust. It cleans mono audio (8 to 48 kHz) one 20 ms frame at a time, so it works on a live mic. I load straight from NVIDIA's model.safetensors. let mut denoiser = Denoiser::load("model.safetensors", 4)?; let clean = denoiser.process(&noisy_chunk)?; on my apple M3 air 16gig, time per 20 ms frame (under 20 ms): |Layers|reuse-rs (CPU)|oRT (WebGPU)| |:-|:-|:-| |4|8.4 ms|16.9 ms| |6|11.5 ms|17.4 ms| |8|14.7 ms|20.6 ms| - About 150mb memory (oRT Wepgpu -> so works via metal in my mac: about 420 MB). - it match a float64 torch reference to 1.5e-6. - 4 layers sounds the same as 8 to my auditory perception :-P: 16.4 vs 16.7 dB SI-SDR demo videos (before/after with spectrograms) are in the reamde if you are curious :) I spent months trying to make this work on the GPU through ONNX before trying the CPU (started with this:onnxruntime#27796 ). If you're curious how that went, and why the CPU wins for tiny streaming frames, I wrote it up here: I forced a speech model onto the GPU for months. The CPU was faster. But I m still thinking if I should take the burn path... but this solves my problems at least... - GitHub: altunenes/re-use-rs - crates.io: crates.io Limitations: weights are NVIDIA's non commercial license (my code is MIT/Apache ), speed is only measured on an M3 (the table is 16 kHz; 48 kHz is about 3 times the work, so for live audio resampling to 16 kHz is the fast option), and it struggles when the heavy background noise is other people talking.
ONNX Runtime 1.31.0 (Oct 9) highlights core/plugin compatibility. Matching an API name is not enough: contributed-operator schemas must agree. Version the runtime and execution provider together. github.com/microsoft/onnxruntime/releases/tag/v1.…
I built a background remover that never sees your photo (and it does GIFs and videos too)! When you’re the only engineer in the family, you automatically become the unpaid IT department, video producer, and resident graphic designer, because to relatives, "computers" is just one big subject (and that includes everything to do with mobile phones too... somehow!). So whenever someone needed a transparent PNG or a quick cutout, it fell on me, and I’d get stuck in the same annoying loop. I'd hunt down a "free" background remover (whatever showed up first on Google), upload the photo, wait, and then get held hostage by a "Buy Credits" button. My only options were settling for a blurry, postage-stamp-sized preview, or making a whole new account if I was desperate enough for the high-res version. Worse, somewhere in that mess, a family photo would get shipped off to a sketchy server I know nothing about. For a product shot, that's annoying. For a passport photo, a signature, or a client's photo, it's a bit more than annoying. So I added a background remover to Fizzdoc, my open-source toolkit where every tool runs inside the browser tab. It now does: - Photos: Remove Background, saved at the photo's own resolution as PNG, JPG or WebP. - Animated GIFs: Remove GIF Background, every frame, same timing, same loop. - Videos: Remove Video Background, every frame, with the sound kept. - WhatsApp stickers: WhatsApp Sticker Maker, a 512 × 512 WebP with a white outline, kept under 100 KB, with words in fun fonts and emoji you drag into place. You can keep the background clear, or put white, any colour, a blur or another photo behind. It's free, there's no sign-up, no watermark, and no limit on how many photos you do. The size limit comes from your device's memory, not from me. And the photo never leaves your device. Not "we delete it after an hour". It just never goes anywhere. Below is how it works, and what broke along the way. The rule: nothing gets uploaded, and you can check !The Remove Background page. The badge under the title says what happens to your photo: 0 bytes uploaded. Fizzdoc is a static site on Cloudflare Pages. There's no backend, so there's nothing that could receive a file. The page also ships a Content Security Policy with connect-src 'self', which means the browser itself blocks the page from talking to any other website. That rule shaped everything below. No CDN for the model, no hosted inference API, no "just this one request". Open DevTools, go to the Network tab, remove the background, and you'll see the model files coming from fizzdoc.com and nothing going out. Picking a model I wanted three things: 1. Good edges on hair and fur, because that's where background removers usually show their seams. 2. Small enough to download once into a browser. 3. A licence that lets anyone use the result, including for work. I went with BiRefNet (MIT licence), the lite variant, using the 512 × 512 ONNX export by studioludens. I store its big weight tensors as 16-bit floats and cast them back to 32-bit when the model loads, which halves the download to about 100 MB without changing the maths it runs. For phones there's a second model, U²-Net small (Apache-2.0), just 4.6 MB. I learned this one the hard way: someone sent me a screenshot of an early version on a 6 GB Android phone, where Chrome killed the tab at 5% ("Aw, Snap!"). A browser tab on a phone gets far less memory than the phone has, and when it runs out there's no error to catch, the tab just dies. So now phones always use the small model, and the page says so ("for the cleanest edges on hair and fur, use a laptop"). If the big model ever crashes a tab on a laptop too, the page remembers it for 30 days and uses the small one there. And for laptops with a graphics chip there's the opposite: a Sharper edges (hair, fur) button. It reruns the photo through a 1024 × 1024 export of the same BiRefNet-lite model (onnx-community, MIT). It's a one-time 135 MB download and needs WebGPU, so it's never offered on phones. If the device can't manage it, you keep the result you already had. Running it: WebGPU when it can, CPU when it can't The model runs with ONNX Runtime Web inside a Web Worker, so the page never freezes. - If the device has a graphics chip with WebGPU, the model runs there. This is the fast path. - If WebGPU isn't there (or the driver says no), the same model runs on the CPU through WebAssembly. - If that fails too, usually because the device ran out of memory, the small U²-Net model takes over. So the chain is GPU, then the same model on CPU, then the small model. Nobody gets an error just because their laptop is old. Two fun problems with "self-host everything" Cloudflare Pages has a 25 MiB limit per file. The model is about 100 MB and ONNX Runtime's WebGPU build is a 27 MB .wasm. So both live on the server as 20 MiB parts: the models are split by a small script when I add them, and the runtime is split at build time. The worker downloads the parts, joins them, and keeps the result in the browser's Cache Storage, so the next time it starts straight from there, even with the internet off. The build also fails if any file it writes goes over 25 MiB, after one deploy failed on it. A runtime that exists in pieces. ONNX Runtime normally fetches its .wasm as one file. Mine exists just as parts on the server, so the worker joins them from Cache Storage and hands the bytes to the runtime directly with ort.env.wasm.wasmBinary. It needs no extra hosting and no change to the security policy. The part I'm proudest of: full resolution from a 512 px model !Top: the page loading the model once, and the options panel. Bottom: the original photo, the cut-out, and a new background in one tap. The model looks at your photo squeezed to 512 × 512 and returns a soft mask. If you stretch that mask back over a 4000 × 3000 photo, the edges look like they were cut with a butter knife. So the mask goes through two classic image-processing filters, both plain arithmetic on typed arrays in the worker: 1. Fast guided filter (He and Sun, 2015). It uses the photo itself as a guide to snap the blurry mask onto the real edges, so hair follows the actual strands. The fit is computed on a smaller copy (up to 1280 px) and then applied to every pixel of the full photo in one pass. 2. Blur-fusion foreground estimation (Forte, 2021). Edge pixels are a mix of your subject and the old background. Put a cut-out on a new colour without fixing that, and you get a faint halo of the old background. This step estimates the subject's true colour at the edges, so the new background looks like it was always there. By default the result is saved at your photo's own size: your own pixels, with a cleaner mask. When the AI gets it almost right It's an AI model, so a busy background or a subject that blends into it can confuse it. For photos there's a small set of touch-ups: - Erase / Restore brush, with Undo, Redo and Zoom for careful work on a phone. - Tap to remove and Tap to keep: one tap picks the whole connected area of a similar colour and removes it, or brings it back. - Shadow and a white Outline, if you want the cut-out to stand out. - Crop: the whole photo, fit to the subject, or a square around the subject for online shop listings. - Hold to see the original, to compare before and after. GIFs: every frame, same rhythm Animated GIFs are sneaky. Many frames aren't full pictures, just small patches drawn over the previous frame, with rules ("disposal methods") about what to clear afterwards. - gifuct-js (MIT) decodes the frames, and Fizzdoc composes each one into a full picture the way a browser would show it. - Each frame goes through the same model (in a faster mode, since there can be dozens). - gifenc (MIT) writes the new GIF, keeping every frame's delay and the loop. One catch: a GIF pixel is either fully see-through or fully solid. So on a clear background the edges are a little sharper than in a PNG. Pick a colour or a photo behind and the soft edges are back. Videos: every frame, sound kept !Remove Video Background: every frame gets a new background, and the sound is kept. For video, Mediabunny (MPL-2.0) reads the file and the browser's own WebCodecs encoder writes the new one. Every frame goes through the model and gets its new background, and the soundtrack is carried over. The output is MP4 (H.264) if the browser can handle it; otherwise, it's WebM (VP9). Before you start, the page shows a preview frame and an estimate of how long the whole clip will take on that device. What does "no background" mean for a video? Truly see-through video would need the encoder library to start helper workers from blob: URLs, which my page's security policy blocks, and most players can't show it anyway. So "None" gives you a green screen, which any video editor removes in one click. I chose to keep the policy strict rather than loosen it for one feature. Stickers: words, emoji, and the last step in WhatsApp !The WhatsApp Sticker Maker turns any photo into a 512 × 512 sticker with a white outline, under 100 KB. The WhatsApp Sticker Maker starts from the same cut-out. It squares it to 512 × 512, adds a white outline, and keeps the WebP under 100 KB by lowering the quality step by step until it fits. On top of that, you can add words in five styles (Funny, Cute, Cozy, BIG, and Serious) and emojis. Each one is a layer you drag, pinch, resize and rotate, on a phone or with a mouse. The fonts are self-hosted like everything else: Bangers, Kalam, Teko and Inter, with Baloo 2 covering Hindi letters. Emoji are drawn with your device's own emoji font. One fun bug on the way: Vite inlines small files as data: URLs, and a few of the font files were small enough. My own CSP (default-src 'self') refused them, and the end-to-end test that fails on any CSP violation caught it before it shipped. Fonts are now always separate files. One limit, though. A web page can't add a sticker to WhatsApp, and a sticker shared from the browser arrives as a normal photo. So instead of a "Share to WhatsApp" button that doesn't do what it says, the page shows WhatsApp's own steps: save the sticker, then in any chat tap Stickers › Create and pick it. On iPhone there's a "Save to Photos" button, because downloads go to Files and WhatsApp picks stickers from Photos. What it's like on low-end phones !The same tool on a phone, in dark mode. Phones use the small 4.6 MB model so the tab doesn't crash. I care about this a lot because many people open Fizzdoc on Android phones. - Phones always get the small model, so it works rather than crashes. Edges are a bit softer than on a laptop, which is a trade I'll take every time. - The worker keeps the page responsive while it thinks. - The model downloads once (the page shows the progress in MB). After that it starts right away, and it keeps working with Wi-Fi and mobile data off, which is also the easiest way to check that nothing is uploaded. - Videos give you a time estimate first: short clips are fine, long ones are a laptop job. Things it doesn't do (yet) - Truly transparent video (see above, green screen instead). - Many photos in one go: the background remover takes one photo at a time. - Several photos in one sticker. That's next. Credits None of this would exist without these people and projects. Thank you: | Project | What it does in Fizzdoc | Licence | |---|---|---| | BiRefNet by Peng Zheng and co-authors | The background model | MIT | | birefnet-lite-512 by studioludens | The 512 px ONNX export | MIT | | BiRefNet_lite-ONNX by onnx-community | The 1024 px export for Sharper edges | MIT | | U²-Net by Xuebin Qin and co-authors | The small model for phones | Apache-2.0 | | ONNX Runtime Web by Microsoft | Runs the models on WebGPU or WebAssembly | MIT | | gifuct-js by Matt Way | Reads animated GIFs | MIT | | gifenc by Matt DesLauriers | Writes animated GIFs | MIT | | Mediabunny by Vanilagy | Reads and writes videos | MPL-2.0 | | Kaiming He and Jian Sun | The (fast) guided filter | Paper | | Marco Forte | Blur-fusion foreground estimation | Paper | The full licence texts are in Fizzdoc's third-party licences. Try it, break it, tell me - Photo: fizzdoc.com - GIF: fizzdoc.com - Video: fizzdoc.com - WhatsApp sticker: fizzdoc.com - Code (Apache-2.0): kingrishabdugar/fizzdoc It's part of a bigger toolkit of 68 free tools (PDF, Word, Excel, PowerPoint, images and audio), all running in your browser, in 16 languages. If something looks off on your device, there's a "Report it" link on every tool. And if you like it, a star on GitHub genuinely makes my day.
Followup Desk: local AI for a more careful customer follow-up This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle. What I Built A furniture customer leaves a note about a sofa, a narrow doorway, and a delivery date. Another customer is comparing prices. A third has asked not to be contacted. By the next shift, a salesperson has to reconstruct what each person needed and which promises still need an answer. Followup Desk is a local-first workspace for that small, specific problem. It connects a reception record to a human-confirmed follow-up plan, a dated action queue, and an outcome timeline. Its experimental AI helps the associate review some passages about fit, delivery, price comparison, service, and comfort before choosing a next step. The potential buyer is an independent furniture or appliance retailer that wants a lightweight preparation tool for its associates. A paid version would have to earn its place by reducing the time spent reconstructing a conversation and preventing forgotten commitments. That is a product hypothesis, not a validated business result: this beta has no paying customers, sales-lift study, or production deployment with real customer data. The current release is a fictional-data prototype. Its useful unit is one reviewable next action for one customer. Demo Try the English Followup Desk beta. Start with the six fictional records. Manual planning works immediately. The optional AI requires an explicit download click: approximately 87 MB of model weights plus about 27 MB of runtime and other assets on the tested setup. Download size and first-run time matter for this audience, so they are disclosed before enabling it. A short walkthrough: 1. Open Sam Rivera's record and review the original reception note alongside confirmed facts. 2. Enable local AI and inspect the quoted passage supporting the price-comparison preparation cue. The wording of the question and strategy is a fixed template. 3. Confirm that the cue is still relevant before adopting the strategy. Then review the date, permitted channel, preparation checklist, and draft in a separate plan confirmation. 4. Record an outcome or reschedule the task. The next action changes without accumulating duplicate reminders, and the timeline retains the outcome. 5. Open Taylor Chen's record. The no-contact instruction blocks the AI action and customer-contact workflow. Copying a draft only copies it to the clipboard. Nothing is sent. Changing an original fact makes the existing confirmed plan require review again. A no-reply outcome does not lower the customer's stage or create daily retries. Code Followup Desk source on GitHub, published under the MIT License. Read the verification report. The repository includes the application, tests, model documentation, privacy limitations, and synthetic evaluation evidence. The shipped application source matches the tested beta; public-release documentation explains the verification boundary. How I Built It The app uses JavaScript and Vite, with a browser worker for inference. The model is Xenova's ONNX conversion of nli-deberta-v3-xsmall, derived from the Apache-2.0 cross-encoder model. It runs through Transformers.js and ONNX Runtime using browser WASM. The conversion revision and runtime assets are pinned. The model performs natural-language inference. It compares source sentences with five fixed preparation hypotheses and returns entailment, neutral, and contradiction scores. The app retains the original sentence as evidence. A suggestion needs sentence entailment of at least 0.80, a margin of at least 0.30 over the other labels, and a full-note contradiction score below 0.50. These are exploratory thresholds, not calibrated accuracy guarantees. This is actual learned-model inference. Questions, suggested strategies, and draft messages come from disclosed, editable templates. The model never sets a budget, date, customer stage, or contact permission. It does not predict purchase readiness, conversion, wealth, or customer value. What testing changed Earlier generative experiments fabricated details and handled the required structure unreliably. The shipped approach narrows the AI's job to source-supported preparation cues and leaves factual fields and decisions with the associate. The final source passed 58 automated tests, including consent and channel gates, date boundaries, changed-record review, backup validation, malicious text handling, and model-output contracts. Mocked contract tests check software behavior; they do not establish model quality. For actual inference, a frozen 16-note synthetic evaluation produced seven supported suggestions and nine abstentions. Some abstentions were real misses. This small set is not a statistical accuracy estimate. A supplemental four-note retraction test exposed two stale historical cues. Conservative explicit resolution/retraction markers now pause AI, and adopting a strategy requires a current-relevance confirmation. Those safeguards cannot detect every paraphrase, so reviewing the full note remains necessary. The public app also completed real browser WASM inference. Casey's comfort/material passage and Sam's competitor-price passage produced source-backed cues. Jordan's note abstained because the full-note check vetoed an otherwise strong sentence result. The thresholds were not loosened to manufacture a successful demo. In that one browser environment, these inference calls took approximately 1.2–1.6 seconds; that is an observation, not a cross-device performance promise. Boundaries of this beta Records are stored in localStorage in the current browser. They are not encrypted, synchronized, or protected as a production CRM database. Clearing site data can erase them, and JSON backups contain the reception text. Please use fictional or appropriately authorized de-identified test records. The application has no remote-inference or outbound-messaging API, and the tested inference ran locally. Model/runtime downloads still contact external asset providers. A complete network privacy audit, offline cold-start/cache verification, final browser backup restore, and mobile-width browser QA remain incomplete. The test report calls out these gaps instead of treating unit tests as a substitute. Why Does Open Innovation Matter? Open components make the AI behavior inspectable and replaceable. The model revision, label scores, fixed hypotheses, thresholds, and synthetic failures can all be examined. A developer can change the model or decision policy and rerun the same evaluation rather than depending on an opaque hosted response. Local inference also removes a per-request hosted-model charge. No application remote-inference endpoint is implemented; the tested inference ran locally. A complete network audit remains pending. It still has real costs: a substantial first download, device compute, browser compatibility work, and maintenance. Offline operation has not been established. For a small retail tool, the trade-off is concrete. A narrow local classifier can support one part of preparing a conversation, while a person reviews the evidence and decides what to do. The current model misses too much to replace that review. Publishing those limitations is part of making the prototype useful to the next person who builds on it. This write-up was generated by an AI assistant from the project's source and verification records, without human text editing. The project was developed with AI assistance. The demo and evaluation use synthetic customer records.