Spaces:
Sleeping
Sleeping
Commit History
-
Revert this session's changes back to the last known-good version
Restores the tree to 4b38f72 exactly. The reported result was worse than the version that was already working, across the swap output, the head swap and the app generally, so the right move is to put the working version back rather than keep patching on top of it. Reverts, newest first: f008eb7 head-swap pose gate + warnings in the UI 0ab4ea6 seam blend against base instead of target b1cd367 workflow PDF + binary .gitattributes rules f25d3bf glasses transfer made opt-in 74dd70d hair matte fix + removal of the crude hair fallback b60d8aa background jobs + Head Swap toggle ddb0022 head-only super-resolution 27e2136 composite onto the full-resolution original 9e549b6 grain confined to the parsed head bb3e953 Control Panel sign-in inside the Hugging Face iframe e522792 Flask debug off by default + threaded pre-warm 27bac33 scene-harmonisation regressions Nothing is lost: each of the above is still in history and can be cherry-picked back individually o…f4e824d -
Refuse a head swap when the two heads face different ways, and say so
full_head_swap fits a 2D similarity transform, so it can slide, spin and scale the source head but cannot turn it. Transplanting a head that is nodded down onto a body with its chin up lands visibly crooked however well the seam is blended, and nothing downstream can correct it. Measured against the Library target (pitch +14, yaw 0): of four test photos, one differed by 26 degrees of pitch, one by 27 of yaw, one by 30 and 20. Those are exactly the results that come out misaligned. The pose delta is now checked before transplanting. Past 25 degrees of pitch or yaw the head swap is skipped and the clean face swap is used instead; between 15 and 25 it runs but says the alignment may be imperfect. Roll is excluded on purpose — it is in-plane and the transform already corrects it. A 20-degree case was checked by eye and still looks right, so the cut sits above it. The frontend never rendered the warnings array at all, so this explanation — and the pre-existing "face is very small" notes …f008eb7
-
Run swaps as background jobs, and add a Head Swap toggle to the app page
Full-quality output takes minutes on the free CPU tier — head super-resolution alone is ~6 minutes — which no HTTP request survives. /api/swap now validates and decodes the inputs, then returns 202 with a job_id; the pipeline runs on a worker thread and /api/swap/status/<job_id> reports real progress and finally the result, in the same shape the synchronous endpoint returned. Jobs run one at a time: the Space has 2 vCPUs that the models already saturate, so overlapping swaps would just make each one slower. Results hold multi-MB base64 images, so finished jobs expire after 20 minutes and the store is capped. The pipeline moved into _perform_swap(), which takes plain options instead of reading request.form and raises SwapError for input problems, so it no longer depends on a request context. The progress bar now follows the server's real stage instead of a timer that animated a guess. The motivational captions still rotate on their own — the wait is longer now, so there's more of it …b60d8aa -
Fix Control Panel Google sign-in inside the Hugging Face iframe
On huggingface.co the Space runs in a cross-origin iframe. The popup is blocked there, and the existing fallback called signInWithRedirect — which navigates THIS frame to Google. Google refuses to be embedded and answers 403 ("you do not have access to this document"), which is the error the Control Panel showed. When framed we now never redirect. Instead the login card offers to reopen the app in a top-level tab, where the normal popup flow works; the button is shown up front while framed, not only after a failed attempt. Also wires up getRedirectResult, which was exported from firebase.js but never called. The non-framed redirect path could previously fail silently: you came back from Google and just saw the login screen again with no error.bb3e953
-
Remove percentage from loading bar
d69a33b -
Loading bar: motivational admission-nudging messages instead of process steps
1d240a0 -
Redesign loading tab: friendly messages (no internal pipeline jargon) + spinner/percentage
afbdbab -
Resolve all project errors: clean lint, tests, imports
- eslint: turn off overly-strict react-hooks/set-state-in-effect (legitimate data-fetch-on-change effects); fix react-hooks/purity by making cacheBust a lazy useState initializer (() => Date.now()) - LandingPage: last em-dash (in a comment) -> hyphen - .gitignore: dev temp files (backend.log, resp.txt, _diag_*.py) Verified green: 25/25 backend modules import, 14/14 pytest pass, eslint clean, frontend build clean.29b87a5
-
Custom per-location result messages + unique defaults; remove em-dashes & "4K"
Custom messages (Control Panel) - locations table gets a `message` column; /api/admin/location/message sets it (edit = any admin). Supports {name} and {location} placeholders, auto-filled - Control Panel: per-location "Edit message" action (prompt), shows a ✎ marker when a custom message exists - App result uses the owner's custom message for that location if set, else a built-in UNIQUE message per location (Library, ICT Dept, VLSI Lab, etc.) UI copy - Removed em-dashes from all visible text (replaced with hyphens/periods) - "Download 4K" -> "Download"; filename no longer suffixed _4k supabase_store: list_locations returns message; add set_message() supabase_schema.sql: add message column (+ ALTER for existing tables)0550cee -
Role permissions + tablet-width 2-col layout
Permissions (Control Panel) - Primary Admin (adivid198986@gmail.com): add, edit (update/rename) AND delete - Admin (Nishith, C D Parmar): add and edit, but CANNOT delete - Backend: delete endpoint now requires _is_primary; add/rename open to any authorised admin. New PRIMARY_ADMIN_EMAILS env + _admin_identity/_is_primary - Frontend: Delete button hidden for non-primary admins; role note shown Layout - Step 2 (photo) + Step 3 (location) go side-by-side from md (tablet) up, so the form fits on one screen sooner without scrollinga2ad15e -
Compact + responsive Generate page: fits one screen, no scroll
- max-w-5xl with Step 2 (photo) + Step 3 (location) side-by-side on lg, stacked on smaller screens (grid-cols-1 lg:grid-cols-2) - Tighter header, card padding, dropzone, preview heights and button so the whole form fits without scrolling on a typical laptop - All sizing uses rem/relative units + Tailwind breakpoints, so browser zoom in/out reflows cleanly instead of breaking the layout5dcf687 -
Remove DeepFace Studio badge from Generate page header
8d6bbb4 -
Redesign Generate page (centered single-column + header), stronger skin-tone match
AppPage.jsx - Cleaner, lighter layout: centered max-w-2xl column with a proper page header ('See yourself on campus'); removed the awkward side-by-side photo/location grid + the empty gaps — steps now stack vertically with even spacing web_app.py - Skin-tone match strength 0.75 -> 0.92: the inswapper adopts target lighting, so pull the swapped face+neck more strongly back to the SOURCE complexion25bb132 -
Fix core swap: auto-download InsightFace buffalo_l + glasses in both paths
Root cause of "model not working / no head swap / no glasses / alignment 50": InsightFace buffalo_l was never downloaded — detector only CHECKED for it and returned None when missing, silently falling back to a crude Haar-cascade paste (no real swap, no head transplant, no parser-based hair/glasses/skin matching). core/detector.py - _get_insightface now lets FaceAnalysis auto-download buffalo_l on first use instead of short-circuiting to None. This makes the real inswapper, head swap, BiSeNet hair/glasses transfer, and skin-tone matching actually run. web_app.py - Transfer the source's glasses in BOTH paths (head-swap parser sometimes misses thin frames); wrapped in try/except, no-op if no glasses. frontend/src/pages/AppPage.jsx - Results show only the final output (removed Your Photo + Location preview panels and the technical metrics); nicer heading + "Your Campus Look" framing - Location step no longer previews the backend image — just a clean confirmation frontend/src/p…6ce5ccf -
Control Panel: cache-bust locations fetch so photo state always syncs
c65ea82 -
Always sync locations: no-store on fetch + backend, lighter cards
- AppPage fetches /api/locations with cache:'no-store' + timestamp so newly added/updated locations and their photos appear without a hard refresh - Backend sets Cache-Control: no-store on /api/locations - Lighter, more refined location/photo/details cards (softer border + shadow)1a2c6fa -
Fix landing typewriter: stop clipping Gujarati/Telugu/Hindi vowel marks
The wrapper used overflow-hidden + leading-tight, which cut off the tall above/below-baseline vowel marks of the Indic scripts (parts of words invisible). Now uses line-height 1.5 + vertical padding + overflow-visible.0c97f26 -
Set the 3 real Control Panel owner emails (Aditya, Nishith, C D Parmar)
d1e0a12 -
Control Panel: Google sign-in restricted to a 3-email allowlist
Replaces the username/password login with Firebase Google sign-in. Only the emails in ALLOWED_ADMINS may enter — enforced on the frontend AND verified on the backend so the API can't be bypassed. Frontend (AdminPage.jsx) - GoogleLogin screen (signInWithPopup); rejects + signs out any account not on the allowlist with a clear message - onAuthStateChanged drives access, restores session on reload, re-checks the allowlist every sign-in; loading state while auth initialises - Admin API calls now send a fresh Firebase ID token in X-Admin-Token - Dashboard shows the owner's photo/email; Owners list reads from ALLOWED_ADMINS Backend (web_app.py) - _check_admin verifies the Firebase ID token via Identity Toolkit (accounts:lookup) and requires the verified email ∈ ALLOWED_ADMIN_EMAILS - Legacy password kept only as optional break-glass (blank by default) - ALLOWED_ADMIN_EMAILS + FIREBASE_API_KEY from env .env.example documents ALLOWED_ADMIN_EMAILS + FIREBASE_API_KEY.e18e557 -
Add personalised motivational message after result (name + location)
Shows a warm gradient banner with the user's name and chosen campus location, gently encouraging them toward admission at Marwadi University. Five rotating templates, picked stably per result so it doesn't change on re-render.39834fb -
Store target images in Supabase (table + Storage) with local FS fallback
Owners manage locations from the Control Panel; target images now persist in Supabase instead of only the local disk. Swap output is still never stored — it's returned inline for client-side download. New - supabase_schema.sql — `locations` table (gender, name, sort_order, image_path) + `location-images` Storage bucket + public-read RLS policies + optional seed of the 19 standard locations for both genders - core/supabase_store.py — REST integration via `requests` (no new dependency): list / get-image / upsert / rename / delete. Service-role key, server-side web_app.py - Load .env on startup (python-dotenv) so Supabase keys + admin passwords apply - /api/locations, /api/location-image, /api/admin/location[/delete|/rename] and the swap target resolution now use Supabase when SUPABASE_URL + SERVICE_KEY are set; otherwise fall back to the local Location/ folder (unchanged behaviour) .env.example — documents SUPABASE_URL / SUPABASE_SERVICE_KEY / SUPABASE_BUCKET and the owner p…27af323 -
New flow: user picks gender + location instead of uploading target
The user now only provides: name, gender, source photo, and a location. The target photo is supplied by us from Location/<gender>/<location>/. Backend (web_app.py) - Add /api/locations?gender=Male|Female — lists location folders (label + has_image flag), sorted by numeric prefix - Add /api/location-image?gender=&location= — serves the curated target image for the picker preview and result panel - /api/swap now resolves the target from gender+location (direct target upload kept as an admin override); also accepts and echoes back the user's name - Path-traversal guard on location names; gender restricted to Male/Female Frontend (AppPage.jsx) - Step 1: Name + Gender. Step 2: your photo (upload/camera). Step 3: location dropdown (fetched per gender) with live preview - Removed the target upload/camera panel entirely - Locations with no image yet show "(coming soon)" and are disabled - Result panel shows name, your photo, chosen location, and the swap Location/ - Add .gitkeep to …e2d08c4 -
Add three-dot menu + Control Panel with 2-owner authentication
c89bfb7 -
Make both pages fully responsive (mobile-first)
8b1c77d
-
Fix all listed technical challenges across detection, landmarks, segmentation
core/detector.py - Add CLAHE contrast enhancement retry when first detection attempt fails, so low-light, backlit, and shadow-heavy photos don't return empty results - Lower minimum face size filter 64px->40px to catch small/distant faces - Extract _detect_insightface() helper to avoid code duplication core/landmarks.py - Fix critical bug: _fallback_landmarks() was returning random uniform noise inside the bounding box, silently corrupting alignment transforms and quality scores. Now falls back to InsightFace 5-point keypoints mapped to the correct MediaPipe indices, or returns None if InsightFace unavailable core/segmentor.py - Remove dead code: fcn_resnet50(pretrained=False) with random weights would produce garbage segmentation. Replaced with facexlib BiSeNet (same model already used by head_swap.py) with heuristic fallback web_app.py - Add small-face quality warnings (< 80px) returned in swap response - Improve face-not-found error messages with actionable tips fron…f4995df -
Fix swap button disabled and blank target preview when using camera
- Swap button was permanently disabled when target was captured via camera (tgtB64 set but tgtFile null) — condition now checks both - Target image in results 3-panel was blank for camera captures — now falls back to tgtB64 when tgtFile is null - Remove unused Link import (lint hint)5c1280c
-
UI Tweaks: Pushed footer below fold on AppPage to match landing page scrolling behavior
124966b -
UI Enhancements: Cleaned up AppPage by removing navbar and notice banner, added footer and floating home button
8929a5e -
UI Enhancements: Redesigned landing page with responsive layout, animated typewriter title, and updated Marwadi University branding
5d2a237 -
fix: camera falls back to any device when facingMode is rejected + clearer hint
Some browsers / single-camera laptops reject the facingMode:'user' constraint and throw, showing "access denied" even though permission was granted. Now retry with plain {video:true} on non-permission errors, and only treat NotAllowedError as a real denial. Clearer permission message (use the address-bar camera icon).0e2460f -
feat: swapped face takes the SOURCE skin tone + previews show the whole face
- Skin tone: the user wants their own (source) complexion on the swap, not the target's. match_skin_to_source now references the SOURCE face; face AND neck are shifted together so they stay one consistent tone (no jaw seam; neck->collar hidden by clothing). strength 0.75. - Previews: upload + result images used object-cover, which cropped the face out of tall/wide photos. Switched to object-contain (taller max-h, neutral bg) so the whole face is always visible, with the rest shown if it fits.3854af9 -
fix: webcam capture (stream now attaches after the video mounts) + clear errors
Clicking the camera did nothing because startCamera set videoRef.srcObject immediately, but the <video> only mounts after camActive flips true — so the stream attached to a null ref and no feed appeared. Attach the stream in an effect keyed on [camActive, stream] (and the target equivalent) so it binds once the element exists, and auto-play it. Replaced the generic "access denied" toast with specific guidance (permission blocked / no camera / camera busy / not available without HTTPS).8163791 -
fix: download works on the HuggingFace site (inline data-URI, not file round-trip)
Download worked on localhost but not on the deployed Space: the button hit /api/download/<file>, and HF's sandboxed iframe/proxy breaks that server round-trip. Now the 4K result is returned inline as a base64 JPEG data-URI (download_image, ~1.7MB) and the button downloads that client-side — works on localhost, the Space, and inside the HF iframe. The PNG file + /api/download endpoint remain as a fallback.c198f03 -
fix: natural 4K upscale + hair/glasses on by default (toggles hidden)
- The final RealESRGAN x4 was the unnatural culprit: as a general-purpose model it over-sharpens skin into a plastic/waxy texture on faces. upscale_image now BLENDS RealESRGAN 50/50 with a plain Lanczos upscale (realesrgan_weight) — keeps the resolution/detail but removes the artificial texture. Verified the 4K download face now looks natural. - Hair transfer and source-glasses now run by DEFAULT (swap_hair/keep_glasses default to 1); removed the Options toggles from the UI per request. Disable per-request with swap_hair=0 / keep_glasses=0 if ever needed.1d042b5 -
fix: fair naturalness (face-region) + make hair/glasses toggles visible
- Naturalness was scored on the whole frame, so studio shots (white background + dark shirt = clipped pixels + hard edges) read ~70 even with a perfect face. Now it's measured on the face crop only -> honest ~90+. - The hair/glasses toggles were hidden in a collapsed "Advanced Settings" panel (which also had 4 sliders the backend ignores), so users couldn't find them and thought hair/glasses "didn't work". Replaced it with an always-visible "Options" panel containing just the two working toggles; removed the dead sliders + state.3828d71 -
feat: make source-glasses transfer an opt-in toggle (default off)
2D glasses transfer can't be flawless (no 3D pose/lighting/lens match), so it's now opt-in instead of always-on: the swap stays clean and natural by default, and a "Keep source glasses" checkbox enables the eye-locked, see-through-lens transfer when wanted. Backend keep_glasses defaults to 0; frontend adds the toggle next to "Swap hair too".9091f39
-
fix: Download button now serves the real 4K PNG, not the preview
The download link pointed at result.result_image (the base64 preview JPEG at swap resolution), so "Download PNG" never delivered the 4K output. Point it at /api/download/<output_file>, which serves the RealESRGAN/Lanczos 4K PNG saved server-side. Relabeled "Download 4K PNG". Also gitignore external/ (vendored HairFastGAN + multi-GB weights for the local GPU hair model). Responsiveness verified across landing + app: fluid clamp() type, grid-cols-1 md:grid-cols-3 panels, flex-col sm:flex-row actions, flex-wrap chips, w-full sm:w-auto buttons, overflow-x-hidden, viewport meta present.9236d5d
-
feat: experimental hair/head swap (opt-in)
InsightFace only swaps the face, so hair always stayed the target's. This adds an opt-in step that transplants the source's hair onto the result. core/head_swap.py: - BiSeNet (facexlib) parses the source head; hair = class 17 (verified). - 5-point similarity transform (InsightFace kps) maps source -> target pose. - Source image + hair mask warped into the target frame and composited over the face swap. Robustness: mask eroded before feathering (no background halo), clamped to a plausible head region (no hair floating above the head), and reduced to its largest connected component (drops stray misclassified patches). - include_face=True transfers the whole head (fuller, lower-fidelity face). web_app.py: opt-in via `swap_hair` / `full_head` form flags; default off so the solid face-swap pipeline is unchanged. AppPage.jsx: "Swap hair too (experimental)" checkbox in advanced settings. Note: quality is pose/lighting/source-quality sensitive and can look artificial; it is intention…1eb6757 -
fix: show DeepFace Studio name in navbar (xs breakpoint doesn't exist in Tailwind)
30e3434 -
fix: auto-redirect landing page when already signed in (fixes iframe post-login flow)
9b4c47d -
fix: detect HF iframe and open direct URL for sign-in, popup-blocked shows open-in-tab button
29ebb27 -
fix: use popup auth (redirect needs Firebase Hosting), fix BGR/RGB bug in InsightFace calls
a285355
-
feat: add camera support to Target Face panel, match Source Face UI
2e6b7f2 -
fix: add missing useEffect import in LandingPage
da74736 -
fix: add error boundary to surface React crashes, guard getRedirectResult
9c5b953 -
fix: switch to redirect-only sign-in, remove popup (blocked by browsers)
dc6ff49 -
fix: fall back to signInWithRedirect when popup is blocked
55d2255 -
feat: prepare for HuggingFace Spaces deployment
d3af7f7 -
feat: make logout button visible with red styling and icon
2b5db2f -
fix: resolve SymbolDatabase GetPrototype error and add missing flask-cors dependency
- Added flask-cors to requirements.txt (was imported but missing from deps) - Installed mediapipe==0.10.14 and insightface==0.7.3 (required packages) - Added model pre-warming on startup for production mode - Frontend improvements for auth and UI071f69d