72c41ae8345326a73bc689ff3620574567e4981c
Builds the "indexed library" foundation and first intelligent features on top of the organizer (sql.js index, non-destructive in-place indexing). Phase 0 — Library index: - sql.js (WASM SQLite) index DB; contentHash-keyed assets, resumable indexing (skip by path+mtime), batch persistence (chosen over native better-sqlite3 which fails to build on Node 24 / Python 3.12) - Library folders (in place, non-destructive) + background indexer w/ progress - Thumbnails generated in the AI worker (canvas->webp), cached in userData; served via photoai-media://thumb by hash; thumbnail grid w/ pagination Phase 1 — AI quality assessment & culling: - Focus (Laplacian variance), exposure (histogram), eyes-open (face-api EAR) computed in one analyze pass alongside the thumbnail - Culling filters (candidate/rejected) + quality badges - Adjustable thresholds (live SQL re-classification from stored raw scores, no re-analysis) + manual star rating (0-5) and color labels (usermeta) Phase 2 — CLIP natural-language / similarity search: - @huggingface/transformers (WASM/WebGPU, no native build) - CLIP image/text embeddings (lazy-loaded); Korean queries auto-translated via opus-mt-ko-en into the English CLIP - Embeddings stored as SQLite BLOBs; "build search index" batch w/ progress; brute-force cosine search; new Search tab - Note: models download from HF Hub on first use; fully-offline ORT-wasm packaging and KO search-accuracy tuning are follow-ups Tabs added (Organize / Library / Search). All typecheck/tests(12)/build green; boot smoke verified across phases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AI Photo Organizer
얼굴 인식 + 촬영일(EXIF) 기준으로 사진을 로컬에서 자동 정리하는 Electron 데스크톱 앱. 클라우드 업로드 없이 내 PC 안에서만 동작한다.
기획·설계 문서: docs/PRD.md · docs/DECISIONS.md · docs/ARCHITECTURE.md
동작 방식
- 인물 프로필(최대 3명)과 참조 얼굴 사진을 등록한다.
- 정리할 폴더(소스)와 결과 폴더(출력)를 고른다.
- [정리 시작] → 각 사진을 스캔해
- 얼굴이 매칭되면
출력/<인물>/YYYY/MM/로 이동(2·3순위 인물에게는 복사) - 매칭 인물이 없으면
출력/Unsorted/YYYY/MM/로 이동 - 영상 파일(
.mp4 .mov .avi .mkv .webm .m4v)은 얼굴인식 없이출력/Movie/YYYY/MM/로 이동 - EXIF 촬영일이 없으면 파일 수정일로 대체
- 얼굴이 매칭되면
데이터 안전: 이동은 복사 → 무결성 검증 → 원본 삭제 순서로 수행하고, 파일명 충돌 시 _1, _2 로 자동 리네임한다(덮어쓰기 없음).
기술 스택
Electron 33 · electron-vite · React 18 + TypeScript · Zustand · Tailwind · @vladmandic/face-api (WebGL) · exifr · electron-builder
3개 프로세스로 분리된 구조:
- Main (Node): 스캔 / EXIF / 파일 이동·복사 / 오케스트레이션
- UI Renderer (React): 화면 — 무거운 연산 없음
- Inference Renderer (숨김 창): face-api 얼굴 인식 전담
개발
npm install
npm run models:download # 최초 1회 — 모델 가중치 받기
npm run dev # 개발 실행 (HMR)
검증 / 빌드
npm run typecheck # 타입체크 (node + web)
npm test # 순수 로직 단위 테스트 (Vitest)
npm run dist:all # Windows(nsis) + macOS(dmg) 인스톨러 빌드
macOS 타깃은 macOS 호스트에서 빌드해야 코드사이닝/공증이 가능하다(미서명 dmg는 어디서나 생성 가능).
트러블슈팅
TypeError: Cannot read properties of undefined (reading 'whenReady')로 부팅 즉시 크래시하면, 환경에ELECTRON_RUN_AS_NODE=1이 설정된 것이다. 이 변수가 있으면 Electron 바이너리가 일반 Node로 동작해electron.app이undefined가 된다. 실행 전 변수를 해제하라:- PowerShell:
Remove-Item Env:\ELECTRON_RUN_AS_NODE - bash:
unset ELECTRON_RUN_AS_NODE
- PowerShell:
폴더 구조
src/
main/ Main 프로세스 (scanner, exif, fileOps, orchestrator, ...)
preload/ contextBridge (UI용 index, 추론창용 inference)
renderer/ React UI
inference/ 숨김 추론 창 (faceEngine, imageLoader)
shared/ 공유 타입/상수
models/ face-api 가중치 (download 스크립트로 채움)
tests/ Vitest 단위 테스트
docs/ 기획·설계 문서
Description
Languages
TypeScript
97%
JavaScript
2.2%
CSS
0.6%
HTML
0.2%