BLA
BLA (Blind LLM Agents) is the open-source Blue Defense MCP and CLI built to protect software artifacts against automated AI reverse-engineering workflows.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Strip photo metadata and blur faces entirely in the browser. Pick a face-detection model and a blur method; the image never leaves your machine.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Remove metadata + face anonymization.
Upload a photo, pick a face-detection model and a blur method, and get back an
anonymized image with all metadata stripped.
Everything runs in the browser. There is no backend, no upload, and no API
call — the image never leaves the machine it was opened on.
Also reachable at the deploy URLs it is served from:
• Vercel — https://privacy-processor-urbanistai.vercel.app
• GitHub Pages — https://kartikdagreat.github.io/privacy-processor-urbanistai/查看完整 README ↗Remove metadata + face anonymization.
Upload a photo, pick a face-detection model and a blur method, and get back an anonymized image with all metadata stripped.
Everything runs in the browser. There is no backend, no upload, and no API call — the image never leaves the machine it was opened on.
Live: https://anonymize.kartikgounder.com
Also reachable at the deploy URLs it is served from:
npm install
npm run fetch-models # one-time: downloads ~33 MB of models into public/
npm run dev # http://localhost:5173
npm run fetch-models is required before the first run. The model weights and
wasm runtimes are gitignored rather than committed, so a fresh clone needs this
step once. It is safe to re-run; existing files are skipped.
npm run build # production build into dist/
npm run preview # serve the build
npm run typecheck # tsc, no emit
dist/ is a fully static directory. Any static host will do — there is nothing
to deploy server-side.
The original design for this app called for a FastAPI service doing detection with OpenCV and MediaPipe. This build does the same work client-side:
| Stage | Where it runs |
|---|---|
| Decode + EXIF orientation | createImageBitmap |
| Face detection | MediaPipe Tasks (wasm) and OpenCV.js (wasm) |
| Blurring | Hand-written kernels over ImageData |
| Metadata stripping | Canvas re-encode to PNG |
The interface is built around verification rather than a single "done": the result is one large frame you wipe between original and anonymized, with the blurred regions marked, and a contact sheet that runs the same photo through every detector so you can see which one caught the most.
Metadata stripping is a property of the pipeline, not a separate step. A
<canvas> holds pixels and nothing else, so anything re-encoded from one carries
no EXIF, GPS, maker notes, or colour profile. Both the Original preview and the
downloaded result are rendered from re-encoded pixels, so even the "before" image
on screen is already clean.
| UI label | id | Runtime |
|---|---|---|
| Run All (cumulative) | run_all | orchestration only |
| MediaPipe | mediapipe | BlazeFace short-range, MediaPipe Tasks |
| MediaPipe Full Range | mediapipe_full | BlazeFace full-range, MediaPipe Tasks |
| OpenCV DNN SSD | opencv_dnn | res10 SSD Caffe model, OpenCV.js |
| Haar Cascade | haar | haarcascade_frontalface_default, OpenCV.js |
| YuNet | yunet | face_detection_yunet_2023mar.onnx, OpenCV.js |
Run All chains the five models cumulatively: each one detects on the output of the previous stage, so a face already blurred by MediaPipe is no longer a face by the time YuNet looks. Coverage adds up instead of competing, which is the point — it maximizes the chance that every face is caught by at least one model.
box, gaussian, median, pixelate. Kernel size follows the original
pipeline: k = max(23, (side / 5) | 1), so a given face gets roughly the same
blur strength it would have had server-side.
Box and Gaussian use moving-sum passes, so their cost does not grow with kernel size. Median uses a sliding 256-bin histogram (Huang's method), which is O(kernel) per pixel rather than O(kernel²).
"Take the tour" in the empty state runs a four-step walkthrough that does the real work rather than pointing at the UI: it loads the hard sample photo, runs Run All to chain every detector, then runs all five separately and narrates the result using the numbers that actually came back.
The closing narration is generated from those numbers, never hardcoded. It adapts its headline depending on whether the chain beat the best single detector, and explains each empty-handed model for the right reason — only the Caffe SSD rescales to 300x300; the MediaPipe models come up short because they expect faces closer to the camera.
Three freely-licensed samples ship in public/samples/ so the tool can be tried
without hunting for an image. They were chosen by running the app's own
detectors over a pool of Wikimedia Commons candidates and keeping one photo
where every model agrees (5 faces), one where they disagree sharply (51 faces —
Haar finds 43, YuNet 51, the DNN 0 because it downsamples to 300x300), and one
of candid profiles. Attribution is in
public/samples/CREDITS.md and shown in the app.
Swapping one means dropping a file in that directory and updating the matching
entry in src/lib/samples.ts.
Model files are fetched lazily and cached for the session — nothing downloads until a detector that needs it is actually run. Picking an OpenCV-backed model pulls in the 11 MB OpenCV.js runtime on first use; MediaPipe models are much smaller. Subsequent runs reuse the loaded detectors.
src/
lib/
assets.ts Paths to everything under public/
blur.ts Box / Gaussian / median / pixelate kernels
image.ts Decode, re-encode, metadata stripping
pipeline.ts Detect -> blur -> encode, shared by both UI surfaces
apiError.ts Turns failures into messages that name the model
types.ts Model and blur-method registries
detect/
index.ts Orchestration, including the run_all chain
mediapipe.ts MediaPipe Tasks detectors
opencv.ts Haar, DNN SSD, YuNet via OpenCV.js
components/ Header, ImageUpload, CompareView, selectors, ComparisonGrid
pages/Index.tsx The single page
scripts/
fetch-models.mjs Downloads models and runtimes into public/
The build is fully static, so both targets are just file hosting. Both deploy
automatically on push to main.
| Target | Trigger | Base path |
|---|---|---|
Vercel (canonical, anonymize.kartikgounder.com) | GitHub integration | / |
| GitHub Pages | .github/workflows/deploy.yml | /privacy-processor-urbanistai/ |
The two differ only in where they are rooted. vite.config.ts reads VITE_BASE
(defaulting to /), and the Pages workflow sets it to the repo path. Because
src/lib/assets.ts resolves model paths against import.meta.env.BASE_URL,
the same source builds correctly for both.
Neither target commits the model weights — both run npm run fetch-models
during the build.
anonymize.kartikgounder.com points at the Vercel deployment. DNS is on
Cloudflare:
| Type | Name | Target | Proxy |
|---|---|---|---|
| CNAME | anonymize | cname.vercel-dns.com | DNS only (grey cloud) |
The record is deliberately not proxied, matching how the apex
kartikgounder.com is configured. Turning Cloudflare's orange proxy on is the
usual cause of a stuck certificate or a redirect loop, since Vercel terminates
TLS itself.
Vercel's CLI warns that the nameservers are Cloudflare's rather than
ns1/ns2.vercel-dns.com. That warning is safe to ignore — a CNAME on
third-party DNS is a supported setup and nothing needs to move.
To point a subdomain at GitHub Pages instead, CNAME it to
kartikdagreat.github.io and drop VITE_BASE from the workflow — a custom
domain serves from the root, so the base path has to go back to /.
Link to the final presentation recording: https://columbia.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ea280966-1dc6-4e27-9e76-b44400fdf038