Commit History
-
docs: update README tags
d2c1be4 -
Add hackathon submission tags, demo video, and launch post to README
Track: Backyard AI Prizes/badges: Best Use of Modal, Best Demo, Tiny Titan, Off Brand Links: Loom demo video + X launch post Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>2989b7e
-
Reduce multi-animal merging: 768px + side-by-side layout cue
The distilled klein (guidance 1.0, 4 steps, 512px) fused adjacent animals into one with 3+ subjects. Two fixes that work without CFG: - Generate at 768×768 (was 512) so each subject has room to form - build_prompt adds ", side by side, each a separate full-body character" when >1 animal, nudging a distinct-subjects layout Verified on 4- and 5-animal prompts: subjects now render as a distinct row of full-body characters (4 reliable; 5 still occasionally drops the oddest one). 768px adds ~a few seconds on the A100 Space — within budget. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>9d5c943 -
Allow up to 5 animals in reward prompts (was 3)
- _join_animals: generalize the Oxford-style join to any count (1–5) - build_subject: animals[:5] (places stay [:3]) - start_level: selected_animals cap raised to 5 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>47ef589 -
Show full calculation in wrong-answer feedback
On an incorrect answer, display "❌ 15 + 9 = 24" (the question expression plus the correct answer) instead of just "❌ Answer: 24", so kids see the whole equation. Captures state["question"] before it's overwritten. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>898db0e -
Replace chicken 🐔 with sheep 🐑 (baby lamb) in the animal picker
Updated both ANIMAL_EMOJIS (app.py) and ANIMAL_MAP (image_generator) in sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>d5b9763 -
Dedupe reward generation: reuse pre-gen in the on-demand fallback
When the player finished a level before the background pre-generation completed, the on-demand fallback generated the SAME prompt again — two generations for one reward (visible in the logs; wasted a ZeroGPU call). - image_generator: add a single-slot cache keyed by reward_id (level). generate_reward_image(..., reward_id=level); inside the gen lock, a matching reward_id returns the cached image instead of regenerating. A different reward_id always regenerates, so rewards stay varied. - app.py: pass reward_id=level from both pregenerate_image and generate_on_demand. Verified: same reward_id → reused (0.0s, identical image); new id → fresh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>ec4a4b3 -
Prompt: repeat "a cute" per animal for clearer multi-animal scenes
Split _join into _join_animals / _join_places. Animals now read "puppy, a cute kitten and a cute bunny" so the model renders each as a distinct cute subject (helps 2–3 animal rewards). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>01c4239 -
Fix place picker to 6 columns (was hardcoded to 5)
The #place-picker grid was still repeat(5, 52px) from the old 10-place layout, so 18 places wrapped as 5/row. Now repeat(6) → clean 3×6 grid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>aa5f2e5 -
Add boat + space shuttle places (18 total → 3 rows of 6)
Brings the place picker to a clean 3×6 grid. Both PLACE_EMOJIS (app.py) and PLACE_MAP (image_generator) updated in sync — verified 18/18, order matches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>7e55dd0 -
Expand picker: 24 animals (lookalike-grouped) + 16 places
- Animals +12: mouse, wolf, bear, pig, cow, pony, chicken, otter, octopus, bee, ladybug, dragon — reordered into lookalike groups (pets · canines/bears · big cats · farm · water/amphibian · bugs · mythical) - Places +6: canyon, castle, theme park, tent, disco ball, circus - Kept ANIMAL_EMOJIS/PLACE_EMOJIS (app.py picker) and ANIMAL_MAP/PLACE_MAP (image_generator prompts) in identical key + order — verified no fallbacks The style LoRA generalizes to the new animals/places (trained on the original 12×10 but it's a style adapter, so new subjects still render in the cozy look). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>e5752bc
-
README: app flow screenshots + hackathon note; fix gen concurrency
README: - Add picker → solve → reward screenshots (real in-app LoRA reward) - Note this is a submission to the HF "Small Models, Big Adventures" hackathon image_generator.py — fix concurrent-generation crash (surfaced locally on MPS): - _pipe_lock: publish the pipeline only once fully built (with LoRA), so the pregenerate + on-demand handlers can't double-load and apply the LoRA twice (was crashing with a meta-tensor error / duplicate peft_config) - _gen_lock: serialize inference — one device can't run two forward passes at once. ZeroGPU serializes @GPU calls in production; locally we must do it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>36cd8ec -
Docs: publish LoRA trainer + add README fine-tuning story
Task #3 — training/lora_trainer/: the reproducible Modal + ai-toolkit setup (run_modal.py, numzoo_klein.yaml, README with repro steps + the gotchas we hit). Task #4 — README: new "Custom AI art: the NumZoo LoRA" section with before/after panda (photoreal → cozy), a LoRA gallery, the Qwen-Image dataset story, training summary, and a link to the published HF LoRA (goumsss/numzoo-flux2-klein-lora). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>6805506 -
Integrate trained NumZoo LoRA into the app
- Bundle the step-1250 FLUX.2-klein-4B style LoRA (lora/numzoo_klein.safetensors, 88MB via Git LFS) — chosen for strongest style + clean multi-animal, no overfit - Load it in _load_pipeline_cpu() after from_pretrained (module/CPU scope, outside the ZeroGPU budget); bulletproof try/except falls back to base model - build_prompt() now prepends the "NUMZOO" trigger and appends "no text" (the distilled 4-step klein otherwise renders the trigger word as a literal sign) - Add peft to requirements.txt (required by load_lora_weights) Local MPS test: cozy NumZoo style renders correctly, no trigger text, multi-animal works. All 10 Puppeteer checks pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>35bc0e8 -
Fix ZeroGPU initialisation: spaces before torch, two-phase pipeline load, guidance_scale
Three correctness fixes informed by the BFL reference starter app: 1. Import `spaces` before `torch` — ZeroGPU patches CUDA init at import time; loading torch first can cause silent GPU mis-behaviour on HF Spaces. Also unifies the public API to a single @GPU-decorated function using the same no-op shim pattern as the reference. 2. Two-phase pipeline loading — `_load_pipeline_cpu()` runs at module scope (outside the @GPU budget) so weights are in CPU RAM before the first ZeroGPU call. `get_pipeline()` just does `.to(device)` inside @GPU, which takes ~1s and removes the cold-start timeout risk on first generation. 3. Fix `guidance_scale=1.0` everywhere — the previous `0.0` on local runs was a copy-paste from schnell; klein-4B distilled uses 1.0 in all envs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>66c36b4 -
Prep captions for LoRA training: trigger word + content-only
- Add TRIGGER='NUMZOO' and split generation prompt (styled) from training caption (trigger + content, no style words) per BFL style-LoRA guidance - Add --captions-only to rewrite .txt captions without re-generating images - Rewrite all 54 captions to "NUMZOO. <content>" format Trigger word will be prepended by the app at inference once the LoRA is trained (done at integration time, not now). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>47fb1ee -
Regenerate training image 011 — replace human girl with chibi butterfly
The original butterfly scene rendered a chibi human girl as the main subject (NUMZOO_STYLE's "chibi character with big sparkling eyes" pulls toward a humanoid when the only animal is a faceless butterfly). Regenerated with the butterfly itself as the chibi character + a no-humans negative prompt. Caption (.txt) unchanged — still app-aligned. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>c80b403 -
Switch dataset model to Qwen-Image + add 54-image training set (LFS)
scripts/generate_dataset.py: - Use Qwen/Qwen-Image (fal-ai provider) — beat FLUX.1-dev on multi-animal accuracy in side-by-side tests; FLUX.2-dev is edit-only so unusable for t2i - Add a 4-attempt retry loop for transient fal-ai 504 timeouts - Drop the --provider flag (single model now) training/: - 54 generated images + caption .txt files, tracked via Git LFS - All 12 app animals solo, all 10 places, plus 2–3 animal and 2–3 place combos - Captions share the app's exact build_subject prefix + NUMZOO_STYLE suffix Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>38bba68
-
Dataset: FLUX.2-dev + app-aligned prompts with multi-animal/place combos
image_generator.py: - Extract build_subject(animals, places) → "A cute {animals} {places}" shared core; build_prompt now = build_subject + ", " + NUMZOO_STYLE - Add _join() helper for the 1–3 phrase joining scripts/generate_dataset.py: - Switch model to FLUX.2-dev (via fal-ai provider, HF Pro credits) - Rebuild prompts programmatically from the app's exact ANIMAL_MAP / PLACE_MAP using the shared build_subject — captions are byte-identical in structure to live app prompts, just with a rich scene-detail clause - 54 curated scenes: all 12 animals solo, all 10 places, plus deliberate 2–3 animal and 2–3 place combinations mirroring multi-emoji selections Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>18bda20 -
Docs: update CLAUDE.md + README for FLUX.2-klein-4B
- Reflect model switch (FLUX.1-schnell → FLUX.2-klein-4B) everywhere - Document persistent cache behaviour + path-bump recovery pattern - Note NUMZOO_STYLE shared constant between app and dataset generator Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>2b1f846 -
Make HF cache setup bulletproof — never crash import, fall back to ephemeral
The /data mount keeps getting poisoned: the cache root itself became a file (rmtree → [Errno 5] I/O error), then makedirs crashed at import time and took the whole app down. - _force_remove(): handles file/dir/symlink/broken paths, never raises - _setup_persistent_cache(): probes /data; on ANY failure (poisoned path, I/O error) returns False and the app uses the ephemeral container cache instead — slower cold start but always works - _predownload_model(): blocking pre-download, never raises - Bump cache path to /data/hf_cache_v4 - Import can no longer crash from cache setup Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>68b5356 -
Fix poisoned HF cache: fresh path + self-healing wipe
The /data/hf_cache tree was poisoned by partial downloads — xet and huggingface_hub left files where directories belong, causing [Errno 20] Not a directory on every generation attempt. - Bump cache path to /data/hf_cache_v3 to escape the poisoned tree - Set HF_HOME + HF_HUB_CACHE explicitly (no per-call cache_dir) - Validate cache by checking for model_index.json in a snapshot - If invalid, shutil.rmtree the whole subtree before re-downloading so every attempt starts from clean ground (xet/.locks/blobs can create real dirs) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>a108fbc -
Fix cache cleanup: wrap removals in try/except, also clear .locks placeholder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>fb5e5c4 -
Fix HF Spaces startup: restore spaces import + clear stale cache placeholders
- import spaces at top level (was missing, caused NameError on @spaces.GPU) - restore sys.unraisablehook for asyncio GC bug suppression - remove stale placeholder files before snapshot_download to prevent [Errno 20] Not a directory errors on re-deploy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>291f11c -
Restore startup pre-download for FLUX.2-klein-4B on HF Spaces
Model is downloaded to /data/hf_cache at startup (once, then cached). Subsequent restarts skip the download — cold start is fast. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1f6e488 -
Fix: restore @spaces.GPU decorator required by ZeroGPU
Decorator was accidentally dropped during model refactor. ZeroGPU fails at startup with "No @spaces.GPU function detected" without it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>885e6f8 -
Upgrade image model to FLUX.2-klein-4B + align training pipeline
image_generator.py: - Replace FLUX.1-schnell with FLUX.2-klein-4B (Apache 2.0, better quality) - Use Flux2KleinPipeline, guidance_scale=1.0, float16 on MPS - Share NUMZOO_STYLE constant so live prompts match training captions exactly - Log generation time (✅ Generated in Xs) scripts/generate_dataset.py: - Switch to FLUX.1-dev via HF Inference API (fal-ai provider, HF Pro token) - Import NUMZOO_STYLE from image_generator — single source of truth - Add --count N flag to generate a subset (e.g. --count 5 for a test run) - Load GEMINI_API_KEY / HF_TOKEN from .env via python-dotenv Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>0a993a9 -
Restore icons in status bar and enforce consistent panel width
- Status bar: restored 👤 🎮 📚 ✅ icons alongside new Level: X format - CSS: added width:100% + box-sizing:border-box to .gradio-group and its .form so all steps (welcome / picker / game) render at identical width Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9b756bd
-
Improve level experience: better status bar + level 5+ harder difficulty
- Status bar now shows: Username | Level: X | Mode | X / 5 (dropped score, added level number) - math_engine: add level 5+ "Hard Mix" — additions/subtractions use 2-digit numbers (10–99), multiplications use tables 6–12 - MATH_LEVEL_NAMES: add entry 5 → "Mix +" - _math_level() cap raised from 4 to 5; _picker_level_label() updated to match Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>ba16816 -
add samples and banner
853e8c0 -
Add banner image to app header with styled title
- Load samples/panda-frog-fox-wave.jpeg as base64 at startup and render as a 190px rounded banner with slight brightness/saturation filter so it doesn't distract from the game - Dark gradient overlay on the bottom half keeps the title legible - "🦁 NumZoo" rendered in bold 900-weight white with a purple glow text-shadow; subtitle in soft italic white underneath - Replaces the plain Markdown title/subtitle components Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9ba71f1 -
Fix wrong-answer feedback; add numeric keyboard on mobile
- Wrong answer now shows the correct answer for the question the user just failed (was accidentally showing the new question's answer because state["answer"] was overwritten before formatting the string) - Added MutationObserver JS to stamp inputmode="numeric" + pattern on the answer Textbox so mobile devices open a numeric keypad Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>fa90153 -
Fix My Collection title card in dark mode
Replace hardcoded light gradient + dark text with a semi-transparent purple tint (rgba) + border + light violet text (#a78bfa) that reads correctly on both light and dark Gradio themes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>4066e23 -
Revert emoji pre-selection to 1 animal + 1 place
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>53af839 -
Improve UI workflow: clean quiz, collection title card, no spinners
- Hide question, answer input and Check button when a level is complete — the quiz is over, only the reward panel is relevant - Explicitly reset quiz visibility + hide reward_panel when start_level is called, fixing a latent bug where the previous level's reward panel would persist into the next level - Replace Gradio's default loading spinner on answer checks with show_progress="hidden" — eliminates the per-answer glitch/flash (generation progress is shown via our own LOADER_HTML instead) - "My Collection" rendered as a styled pill title card (purple gradient, centered) instead of a plain bold div Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>8196f62 -
Remove streak from prompt; support up to 3 animals and places
- build_prompt() no longer takes a streak argument — mood/extras tiers removed in favour of a single fixed style (NUMZOO_STYLE) - All selected places (up to 3) are now included in the prompt, same as animals — previously only one random place was picked - Pre-selection in the emoji picker bumped from 2 → 3 for both animals and places so users start with a richer default selection - Removed unused streak variable from pregenerate_image and generate_on_demand call sites Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>4b81168 -
Fix collection display: replace JS polling with server-side render
The previous collection mechanism relied on JavaScript polling a hidden gr.HTML element for JSON payloads. In Gradio 6, scripts injected via gr.HTML innerHTML are not executed, so the polling loop never started and the collection was invisible. Rewrote the collection as server-side rendered HTML: - _render_collection() builds the HTML directly in Python - _add_locked() / _unlock_item() manage coll_items gr.State - Removed _coll(), COLLECTION_HTML, collection_trigger entirely - Added ZOOM_MODAL_HTML as a static element (always in DOM) - Updated all function signatures and event wiring accordingly Also removed dead `style = random.choice(STYLES)` line in image_generator.py that would have caused NameError on generation. Updated Puppeteer test: answers 5 questions (ANSWERS_PER_LEVEL=5), asserts locked placeholder appears immediately after "Let's go!", confirms collection persists after level completion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>a2af9f2 -
Add training dataset generator + fix MPS dtype for local inference
- scripts/generate_dataset.py: generates 80 kawaii scene images using Gemini 3.1 Flash Image (Nano Banana 2) — 8 categories × 10 animals, square 1:1 output, supports --start N resume and --dry-run preview, loads GEMINI_API_KEY from .env via python-dotenv - image_generator.py: use float16 on MPS (bfloat16 unsupported) and enable_sequential_cpu_offload to avoid OOM on local Apple Silicon Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>3311574 -
Remove startup model pre-caching — let from_pretrained cache in container
The persistent storage placeholder-file issue was fundamental: HF Spaces git-backed storage creates FILE placeholders at every intermediate directory path (blobs/, refs/, snapshots/, .locks/) on each mount. Removing them destroyed access to the cached content behind them, forcing a full 57.8 GB re-download on every cold start — the opposite of the intended behaviour. New approach: remove snapshot_download at startup entirely. from_pretrained downloads to the container's local ~/.cache/huggingface/hub/ on first use. The Python process (and _pipe global) survive between ZeroGPU GPU-slot releases, so the model loads once per container lifetime. Increased @spaces.GPU duration to 120s to cover first-run download + load + generate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>9e11bdb -
Fix .locks dir placeholder — also repair cache_root/.locks/models--*/
snapshot_download uses {cache_root}/.locks/models--{model}/ for per-blob lock files. The storage was mounting that path as a placeholder file too. Extend _repair_hf_cache to also fix the .locks subtree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>c1afda8
-
Fix: repair entire HF cache tree of placeholder files at startup
Root cause: HF Spaces persistent storage mounts placeholder FILES at every intermediate path that should be a directory (models--.../blobs/, models--.../refs/, models--.../snapshots/, etc.). snapshot_download fails silently to write refs/main (needed for revision resolution), causing from_pretrained to download the model again on first use. Fix: _repair_hf_cache() walks the full known directory tree at startup and unlinks any non-directory at paths that must be directories: - cache_root/models--*/ - cache_root/models--*/blobs/ - cache_root/models--*/refs/ - cache_root/models--*/snapshots/ - cache_root/models--*/snapshots/{40-char-hash}/ Real files (safetensors, configs, symlinks) are left untouched. Also log the state of model_dir and refs/main before download so the next failure is immediately diagnosable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>0859512 -
Fix FileExistsError on cache path: unlink placeholder file before makedirs
exist_ok=True only suppresses FileExistsError when the target is already a directory. The HF storage system leaves a placeholder file at the cache path on every restart, so makedirs fails. Unlink any non-directory obstacle with lexists+isdir check before calling makedirs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>54ba688 -
Change cache path to /data/hf_cache to avoid storage git conflict
Root cause: the persistent storage git repo has a file named 'hub' committed inside 'huggingface/', so /data/huggingface/hub is always a file when the storage is mounted — no matter how many times we delete it, git restores it on every restart. Fix: use /data/hf_cache — a flat single-level path directly under /data with no conflicting entry in the storage repo. First cold start downloads the model (~30s on HF CDN); every subsequent restart finds the directory intact and skips the download entirely. Also simplify the startup block: _ensure_dir and diagnostics removed now that the path conflict is resolved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>21046df -
Fix ENOTDIR by validating every cache path level; add diagnostics
Root cause: if /data/huggingface exists as a file (not a dir), then os.makedirs('/data/huggingface/hub') raises OSError (silently caught), the hub/ dir is never created, and snapshot_download fails with ENOTDIR deep inside its own makedirs call. We were only checking the leaf model path, missing corruption in parent components. Fix: - _ensure_dir() helper: removes file/symlink obstacles then makedirs - Apply _ensure_dir to both /data/huggingface AND /data/huggingface/hub before setting HF_HUB_CACHE env vars - _describe() helper prints the exact state of each path level at startup so future issues are immediately diagnosable from logs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>4830e70 -
Fix corrupt cache detection (lexists) and suppress asyncio GC noise
Two robustness fixes in the HF Spaces startup block: 1. Use os.path.lexists() instead of os.path.exists() to detect corrupt cache entries. exists() follows symlinks and returns False for broken symlinks; lexists() checks the path itself — catches regular files, working symlinks, AND broken symlinks. Also log exactly what was found (dir / file / symlink / absent) to make future issues diagnosable. Use os.unlink() which handles both files and symlinks (os.remove() only handles files). 2. Install sys.unraisablehook to silently drop the Python 3.10 GC bug (BaseEventLoop.__del__ → "Invalid file descriptor: -1"). This is the correct Python 3.8+ API for intercepting exceptions raised in __del__ and other un-raisable contexts — cleaner than monkey-patching __del__. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>1bcd3f8 -
Fix corrupt cache entry and asyncio fd warning on startup
Two fixes in image_generator.py HF Spaces startup block: 1. Corrupt cache: if /data/huggingface/hub/models--black-forest-labs--FLUX.1-schnell exists as a FILE instead of a directory (happens when persistent storage gets partially initialised), remove it so huggingface_hub can create the proper directory structure on the next snapshot_download call. 2. asyncio 'Invalid file descriptor: -1': Python 3.10 BaseEventLoop.__del__ crashes when the GC collects an unclosed event loop. Fix: create an explicit event loop in the download thread, set it as the thread's loop, and close it in a finally block before the thread exits — prevents the GC from seeing an open loop at all. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>2ed1759 -
Redesign game loop: level-based flow with reward at end of each level
New flow per cycle: - Pick animals + places (picker shows "Level N" for level 2+) - Answer 5 questions correctly - Reward screen shows AI image + "Next Level →" button - Back to picker with fresh random emoji pre-selections for variety Key changes: - REWARD_EVERY=3 mid-level rewards removed; replaced with ANSWERS_PER_LEVEL=5 per-level reward - Collection gets add-locked at level START, unlock at level END - pregenerate_image fires once at level start (not after each reward) - New next_level() function: increments level, resets to picker - New next_level_btn in reward panel - New picker_level_md shows "Level N — Difficulty" on return to picker - Status bar shows correct count (X/5) during level - Math difficulty caps at 4 (Mix), level display number uncapped - State simplified: removed reward_count, correct_since_reward, level_correct, pregenerate_next Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>a15351b -
Revert share=True — not supported on HF Spaces
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>75bda08 -
Enable share=True for public Gradio link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>d334b80 -
Fix FileExistsError on /data/huggingface/hub mkdir
exist_ok=True only suppresses errors when the path is already a directory; it still raises if the path is a file or broken symlink. Wrap in try/except (FileExistsError, OSError) to handle all cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>27a8ab3