Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-07-22 22:58:28 +05:30
parent d1308bf149
commit bc8bf2007d
99 changed files with 4784 additions and 111 deletions
+47
View File
@@ -298,7 +298,54 @@ Phases 13 complete & verified (see [requirements.md](requirements.md)). `pnpm
DEPLOY: `docs/DEPLOY-MANUAL.md` — 3 no-Git paths: (A) Vercel CLI `vercel --prod` from repo root, Root Dir=apps/web (recommended; keeps SSR+nonce CSP+AI route); (B) self-host Node (`pnpm build``pnpm --filter web start` on Render/Railway/VPS); (C) static export to any host — requires `output:'export'` + DISABLING the nonce middleware/layout headers (security trade-off, no server AI route). SDK ships as source via transpilePackages so "whole project" = build the demo (no npm publish).
AI: `apps/web/src/app/api/ai/edit/route.ts` REFACTORED to a pluggable backend via `AI_EDIT_PROVIDER` (auto|local|huggingface|gemini|none). auto = local→huggingface→gemini. `local` = own Stable Diffusion (AUTOMATIC1111/Forge/SD.Next `/sdapi/v1/img2img`, env LOCAL_SD_URL+denoise/steps/sampler; free+private). `huggingface` = free Inference API instruct-pix2pix (HF_API_TOKEN, HF_IMAGE_MODEL; 503 cold-start handled). `gemini` kept (needs BILLED key for image). MAX_BASE64 lowered to 4M (under Vercel 4.5MB). Server-side fetches → no CSP change. KEY POINT documented in `docs/AI-SETUP.md`: analysis (objects/faces/OCR/embeddings via TF.js/face-api/tesseract/transformers) + Remove Background (@imgly) already run FREE in-browser, no key — only generative pixel edits needed a backend. `.env.example` rewritten with Supabase + all AI options. typecheck + build pass. Did NOT git commit.
- S-runpod (2026-07-18): **RunPod endpoint integration (model-api-spec.docx) — image edits + detection, all server-proxied.**
Planned via an `ultracode` Workflow (5 parallel readers → Opus blueprint). GOAL: make the app talk to the 15 RunPod
endpoints (server still down; wired + typecheck/build-verified, not yet live-tested against real endpoints).
NEW server-only client module `apps/web/src/lib/runpod/{types,base64,client,endpoints}.ts`: `runpodCall` transport
(bearer `RUNPOD_API_KEY`, `{input}` envelope, `/runsync` inline + `/run``/status/{id}` poll under a 55s budget),
`pickOutputImage` (handles image|image_png|images[0]|nested), and one typed `rp*` fn per endpoint. `RunpodError.status`
surfaces as the editor's red error text.
EDIT ROUTE `apps/web/src/app/api/ai/edit/route.ts`: added `'runpod'` provider (auto-preferred when RUNPOD_API_KEY +
an SD URL set). `editRunPod` op→endpoint map: restore→#7 ESRGAN(+face), upscale→#7, colorize→#8 DDColor, prompt→#10
SD img2img, replace-sky→#9 inpaint IF mask else #10 low-strength, magic-eraser/generative-fill→#9 masked inpaint
(400 if no mask). Body now accepts `maskBase64` + `params` (negativePrompt/strength/steps/seed/guidanceScale, all
clamped); image+mask share the ONE ~4MB body cap. RUNPOD_ONLY_OPS (upscale/magic-eraser/generative-fill) 400 on
non-runpod backends.
MASK FLOW (the SD 3.5 ask): client `createDemoAIProvider.generativeEdit` rasterizes `op.mask` (ImageData) → PNG
matched to the downscaled image dims via new `lib/ai/imageEncode.ts maskToBase64`, strips the non-serializable mask
from the wire op, sends `maskBase64`. Output interpreted unchanged (base64→Blob→aiResultUrl→Save), so no UI change
needed to SHOW results. STILL MISSING: a brush-mask UI in PhotoEditor to CREATE masks (magic-eraser/generative-fill
have no button yet + return the 400 until then); replace-sky degrades to img2img until a mask/sky-seg exists.
DETECTION #1: new `apps/web/src/app/api/ai/classify/route.ts` + `lib/ai/runpodYoloProvider.ts` (POSTs image+dims,
normalizes YOLO boxes→DetectedObject fractions 0..1 — `normalizeBox` assumes ultralytics xyxy pixels, VERIFY vs real
endpoint). Gated by `NEXT_PUBLIC_APG_RUNPOD_DETECT=true`, else in-browser COCO-SSD (also the automatic fallback).
ALREADY LOCAL (no RunPod): screenshot #4 / geo #15 (exifr+classify.ts), tag-rename #5 (state), bg-remove #6 (@imgly).
SCAFFOLD ONLY (typed rp* + env, NO route/UI): tilt #2, voice #3, audio-denoise #12; DOC-ONLY: video #13/#14 (need
out-of-band upload+queue, incompatible with Vercel 4.5MB/60s + in-browser bake). All flagged in docs/AI-SETUP.md.
CSP UNCHANGED (server-side fetch bypasses browser CSP; middleware excludes /api/*). ENV: `.env.example` RunPod block;
docs/AI-SETUP.md "Option 0 — RunPod" (op→endpoint table + mask/detection notes) + docs/DEPLOY.md server-env table
(RUNPOD_* never NEXT_PUBLIC). VERIFIED: `pnpm -r typecheck` clean (both pkgs); `pnpm build` passes, both new routes
compiled (/api/ai/edit, /api/ai/classify dynamic), /gallery 199KB, only the pre-existing benign face-api warning.
Did NOT git commit. NEXT: brush-mask UI (unlocks true #9 for eraser/fill + real sky mask); outpaint #11 (client pads
canvas+mask→generative-fill); #5 alias rename map; then Vercel deploy once endpoints are up. VERIFY normalizeBox +
the `{input}`/`output` field names against the live endpoints before trusting detection/edit results.
ADVERSARIAL REVIEW (ultracode Workflow, 3 dims find→verify, 20 agents; 12 CONFIRMED, 5 refuted) — ALL 12 FIXED &
re-verified (typecheck + build pass, both routes compiled, /gallery 199KB): (1) normalizeBox rewritten to handle
object-form xyxy `{x1,y1,x2,y2}`/`{left,top,right,bottom}` (ultralytics tojson shape — was dropped!) + array boxes
keyed correctly (xyxy vs xywh/COCO bbox=[x,y,w,h] vs generic box=xyxy); (2) label priority fixed — string `name`
before numeric `class` index (was returning "0" for ultralytics), empty-string label falls through to class_<id>;
(3) envNum treats blank env ('' → 0) as unset; (4) rpUpscale no longer lets RUNPOD_UPSCALE_SCALE override the
per-request factor (removed the env knob); (5) client envelope: a raw /runsync body with a `status` field but no
`id` is now correctly treated as inline output (was misrouted to poll→throw); (6) poll loop clamps sleep+abort to
the remaining budget so it can't overshoot Vercel 60s; (7) pickOutputImage validates strings under generic
output/result/data keys (looksLikeImageData) so a status/id string isn't returned as an image; (8) auto provider
detects runpod on ANY RUNPOD_*_URL (not just SD) so an upscale/colorize-only deploy works; (9) maskToBase64 sets
imageSmoothingEnabled=false so binary masks stay crisp (no grey halo). Dropped RUNPOD_UPSCALE_SCALE from .env.example.
REFUTED (correctly, no change): status-URL query-string, combined-body-cap rejecting masks, replace-sky client
strength, 'mask' in op undefined-crash, mask-op has no UI button (all non-bugs / already-safe).
## Key files
- RunPod integration (S-runpod): `apps/web/src/lib/runpod/*` (server) + `apps/web/src/app/api/ai/{edit,classify}/route.ts` + `apps/web/src/lib/ai/{runpodYoloProvider,imageEncode}.ts` (client). Env: `RUNPOD_API_KEY` + `RUNPOD_*_URL`.
- Advanced video editor (S-advanced): `packages/photo-sdk/src/lib/videoBake.ts` + `lib/videoTimeline.ts` + `components/editor/VideoEditor.tsx`.
- AI edit backend (S-deploy-ai): `apps/web/src/app/api/ai/edit/route.ts` (env AI_EDIT_PROVIDER).
- SDK: `packages/photo-sdk/src/{components,store,adapters,ai,lib,icons,styles}`.