Spaces:
Running on Zero
Running on Zero
| """Prepare per-user data bundles for the HF Space. | |
| For each user in USERS: | |
| hf_demo/data/u{N}/ | |
| βββ vector_store/ | |
| β βββ manifest.json | |
| β βββ records.json (with paths rewritten to thumbs/u{N}/<pid>.jpg) | |
| β βββ vectors.npy | |
| βββ events.json | |
| βββ images.json | |
| hf_demo/thumbs/u{N}/<photoid>.jpg (resized to MAX_SIZE on long edge, JPEG q85) | |
| """ | |
| from __future__ import annotations | |
| import json, shutil, os, re | |
| from pathlib import Path | |
| from PIL import Image | |
| REPO = Path('/sensei-fs-3/tenants/Sensei-AdobeResearchTeam/thaon/code') | |
| KII_DIR = REPO / 'converted_data/database/kii/yfcc_data' | |
| HF = Path(__file__).resolve().parent | |
| USERS = [3, 8] # start with these; easy to expand later | |
| MAX_SIZE = 384 # long-edge px; Qwen2.5-VL is happy at 384β512 | |
| JPEG_Q = 85 | |
| def rewrite_path(orig: str, uid: int) -> str: | |
| """Convert an absolute disk path into the Space-relative path.""" | |
| m = re.search(r'/(\d+\.jpg)$', orig) | |
| if not m: | |
| return orig # leave non-matching entries (e.g. "image2.jpg") alone | |
| return f'thumbs/u{uid}/{m.group(1)}' | |
| def resize_one(src: Path, dst: Path): | |
| if dst.exists(): | |
| return | |
| dst.parent.mkdir(parents=True, exist_ok=True) | |
| try: | |
| with Image.open(src) as im: | |
| im = im.convert('RGB') | |
| im.thumbnail((MAX_SIZE, MAX_SIZE), Image.LANCZOS) | |
| im.save(dst, 'JPEG', quality=JPEG_Q, optimize=True) | |
| except Exception as e: | |
| print(f' ! failed to resize {src}: {e}') | |
| def prep_user(uid: int): | |
| src_dir = KII_DIR / str(uid) | |
| out_dir = HF / 'data' / f'u{uid}' | |
| thumb_dir = HF / 'thumbs' / f'u{uid}' | |
| print(f'\n[u{uid}] {src_dir} -> {out_dir}') | |
| if not src_dir.exists(): | |
| print(f' ! source dir missing'); return | |
| # Copy events.json + images.json verbatim (they're small + UI uses them). | |
| out_dir.mkdir(parents=True, exist_ok=True) | |
| for fname in ('events.json', 'images.json'): | |
| sp, dp = src_dir / fname, out_dir / fname | |
| if sp.exists(): | |
| shutil.copy(sp, dp) | |
| # Vector store | |
| vs_src = src_dir / 'vector_store' | |
| vs_dst = out_dir / 'vector_store' | |
| vs_dst.mkdir(parents=True, exist_ok=True) | |
| shutil.copy(vs_src / 'manifest.json', vs_dst / 'manifest.json') | |
| shutil.copy(vs_src / 'vectors.npy', vs_dst / 'vectors.npy') | |
| # Rewrite records.json paths to be Space-relative | |
| records = json.loads((vs_src / 'records.json').read_text()) | |
| needed_pids = set() | |
| for r in records: | |
| p = r.get('payload', {}) | |
| # images list (event records) | |
| if 'images' in p: | |
| new_imgs = [] | |
| for orig in p['images']: | |
| new = rewrite_path(orig, uid) | |
| new_imgs.append(new) | |
| m = re.search(r'(\d+)\.jpg$', orig) | |
| if m: | |
| needed_pids.add(m.group(1)) | |
| p['images'] = new_imgs | |
| # single path (image record) | |
| if 'path' in p: | |
| orig = p['path'] | |
| p['path'] = rewrite_path(orig, uid) | |
| m = re.search(r'(\d+)\.jpg$', orig) | |
| if m: | |
| needed_pids.add(m.group(1)) | |
| (vs_dst / 'records.json').write_text(json.dumps(records)) | |
| # Resize the needed photos into thumbs/u{N}/ | |
| yfcc_imgs = REPO / 'thaodata/yfcc_v3' / str(uid) / 'images' | |
| n_done = 0 | |
| n_missing = 0 | |
| for pid in sorted(needed_pids): | |
| src = yfcc_imgs / f'{pid}.jpg' | |
| if not src.exists(): | |
| n_missing += 1 | |
| continue | |
| resize_one(src, thumb_dir / f'{pid}.jpg') | |
| n_done += 1 | |
| print(f' records: {len(records)} thumbs: {n_done} done, {n_missing} missing') | |
| # Report sizes | |
| total_mb = sum(p.stat().st_size for p in thumb_dir.rglob('*.jpg')) / 1024 / 1024 | |
| vs_mb = sum(p.stat().st_size for p in vs_dst.iterdir()) / 1024 / 1024 | |
| print(f' thumb dir: {total_mb:.1f} MB vector store: {vs_mb:.1f} MB') | |
| def main(): | |
| for uid in USERS: | |
| prep_user(uid) | |
| print('\nDONE.') | |
| if __name__ == '__main__': | |
| main() | |